/* * Author: Balch * Created: 9/4/14 12:26 AM * * This file is part of MockTrade. * * MockTrade is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MockTrade is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MockTrade. If not, see <http://www.gnu.org/licenses/>. * * Copyright (C) 2014 */ package com.balch.mocktrade; import android.content.Context; import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.LayoutRes; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.text.format.DateUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.BaseAdapter; import android.widget.LinearLayout; import android.widget.Spinner; import android.widget.TextView; import com.balch.android.app.framework.BaseView; import com.balch.android.app.framework.domain.ColumnDescriptor; import com.balch.android.app.framework.domain.EditState; import com.balch.android.app.framework.domain.ViewHint; import com.balch.mocktrade.account.Account; import com.balch.mocktrade.order.StockSymbolLayout; import com.balch.mocktrade.portfolio.PortfolioAdapter; import com.balch.mocktrade.portfolio.SummaryTotalsView; import com.balch.mocktrade.shared.PerformanceItem; import com.balch.mocktrade.shared.view.DailyGraphView; import java.text.DateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; public class MainPortfolioView extends LinearLayout implements BaseView { public interface MainPortfolioViewListener { void onGraphSelectionChanged(long accountId, int daysToReturn); } private final static int [] GRAPH_TIME_VALUES = {-1, 7, 30, 90, 180, 365}; private final static int GRAPH_TIME_HOURLY_INDEX = 0; private final static DateFormat DATE_FORMAT_SHORT = DateFormat.getDateInstance(DateFormat.SHORT); private RecyclerView portfolioRecycler; private SummaryTotalsView portfolioSummary; private TextView lastQuoteTime; private TextView lastSyncTime; private DailyGraphView dailyGraphView; private TextView emptyGraphView; private Spinner accountGraphSpinner; private ArrayAdapter<String> graphAccountAdapter; private GraphTimeAdapter graphTimeAdapter; // variables that need to be persisted private List<Long> accountIds = new ArrayList<>(); private int accountSelectedPosition = 0; private int graphTimeSelectedPosition = 0; private final MainPortfolioViewListener listener; public MainPortfolioView(Context context, MainPortfolioViewListener listener) { super(context); this.listener = listener; initializeLayout(); } private void initializeLayout() { setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); setOrientation(VERTICAL); inflate(getContext(), R.layout.portfolio_view_main, this); portfolioRecycler = (RecyclerView) findViewById(R.id.portfolio_list); portfolioRecycler.setLayoutManager(new LinearLayoutManager(getContext())); portfolioSummary = (SummaryTotalsView) findViewById(R.id.portfolio_view_summary_view); lastQuoteTime = (TextView) findViewById(R.id.portfolio_view_last_quote); lastSyncTime = (TextView) findViewById(R.id.portfolio_view_last_sync); dailyGraphView = (DailyGraphView) findViewById(R.id.portfolio_view_daily_graph); emptyGraphView = (TextView) findViewById(R.id.portfolio_view_daily_graph_empty); graphAccountAdapter = new ArrayAdapter<>(getContext(), R.layout.portfolio_view_graph_spinner_text); graphAccountAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); accountGraphSpinner = (Spinner) findViewById(R.id.portfolio_view_account_graph_spinner); if (accountGraphSpinner != null) { accountGraphSpinner.setAdapter(graphAccountAdapter); accountGraphSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (accountSelectedPosition != position) { accountSelectedPosition = position; if (listener != null) { listener.onGraphSelectionChanged(getSelectedAccountId(), getGraphDays()); } } } @Override public void onNothingSelected(AdapterView<?> parent) { accountSelectedPosition = 0; } }); } Resources resources = getResources(); Spinner timeGraphSpinner = (Spinner) findViewById(R.id.portfolio_view_time_graph_spinner); if (timeGraphSpinner != null) { graphTimeAdapter = new GraphTimeAdapter(getContext(), R.layout.portfolio_view_graph_spinner_text, android.R.layout.simple_spinner_dropdown_item); graphTimeAdapter.add(resources.getString(R.string.portfolio_view_time_title_today)); graphTimeAdapter.add(resources.getString(R.string.portfolio_view_time_title_last_week)); graphTimeAdapter.add(resources.getString(R.string.portfolio_view_time_title_last_month)); graphTimeAdapter.add(resources.getString(R.string.portfolio_view_time_title_last_90_days)); graphTimeAdapter.add(resources.getString(R.string.portfolio_view_time_title_last_180_days)); graphTimeAdapter.add(resources.getString(R.string.portfolio_view_time_title_last_year)); timeGraphSpinner.setAdapter(graphTimeAdapter); timeGraphSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { if (graphTimeSelectedPosition != position) { graphTimeSelectedPosition = position; if (listener != null) { listener.onGraphSelectionChanged(getSelectedAccountId(), getGraphDays()); } } } @Override public void onNothingSelected(AdapterView<?> parent) { graphTimeSelectedPosition = 0; } }); } StockSymbolLayout stockSymbolLayout = (StockSymbolLayout) findViewById(R.id.portfolio_nav_stock_picker); if (stockSymbolLayout != null) { ColumnDescriptor columnDescriptor = new ColumnDescriptor(null, null, R.string.order_symbol_label, EditState.CHANGEABLE, new ViewHint[]{new ViewHint(ViewHint.Hint.MAX_CHARS, "32"), new ViewHint(ViewHint.Hint.NOT_EMPTY, "true")}, 1, null); stockSymbolLayout.bind(columnDescriptor); } } public long getSelectedAccountId() { long accountId = -1; if (accountSelectedPosition < accountIds.size()) { accountId = accountIds.get(accountSelectedPosition); } return accountId; } public int getGraphDays() { int days = -1; if (graphTimeSelectedPosition < GRAPH_TIME_VALUES.length) { days = GRAPH_TIME_VALUES[graphTimeSelectedPosition]; } return days; } public void resetSelectedAccountID() { accountSelectedPosition = 0; } public void setPortfolioAdapter(PortfolioAdapter portfolioAdapter) { portfolioRecycler.setAdapter(portfolioAdapter); } public void setTotals(boolean showTotals, PerformanceItem performanceItem) { portfolioSummary.setVisibility(showTotals ? VISIBLE : GONE); if (showTotals) { portfolioSummary.bind(performanceItem); } } public void setSyncTimes(Date lastSync, Date lastQuote) { Resources resources = getResources(); lastSyncTime.setText(resources.getString(R.string.portfolio_view_last_sync, getDateTimeString(lastSync))); lastQuoteTime.setText(resources.getString(R.string.portfolio_view_last_quote, getDateTimeString(lastQuote))); } private String getDateTimeString(Date date) { String result = ""; if ((date != null) && (date.getTime() > 0)) { result = DateUtils.isToday(date.getTime()) ? DateFormat.getTimeInstance(DateFormat.SHORT).format(date) : DateFormat.getDateInstance(DateFormat.SHORT).format(date); } return result; } public void animateGraph() { dailyGraphView.animateGraph(); } public void setDailyGraphDataAccounts(List<Account> accounts) { if ((accountGraphSpinner != null) && (accounts != null)) { graphAccountAdapter.setNotifyOnChange(false); graphAccountAdapter.clear(); graphAccountAdapter.add(getContext().getString(R.string.portfolio_view_graph_spinner_totals)); accountIds.clear(); accountIds.add(-1L); for (Account account : accounts) { graphAccountAdapter.add(account.getName()); accountIds.add(account.getId()); } graphAccountAdapter.setNotifyOnChange(true); graphAccountAdapter.notifyDataSetChanged(); if (accountSelectedPosition != AdapterView.INVALID_POSITION) { accountGraphSpinner.setSelection(accountSelectedPosition); } } } public void setAccountSpinner(long accountID) { accountSelectedPosition = accountIds.contains(accountID) ? accountIds.indexOf(accountID) : 0; accountGraphSpinner.setSelection(accountSelectedPosition); } public void setDailyGraphData(List<PerformanceItem> performanceItems) { if ((dailyGraphView != null) && (emptyGraphView != null)) { if ((performanceItems != null) && (performanceItems.size() >= 2)) { if (graphTimeSelectedPosition == GRAPH_TIME_HOURLY_INDEX) { Date timestamp = performanceItems.get(performanceItems.size() - 1).getTimestamp(); String label = (DateUtils.isToday(timestamp.getTime()) ? getResources().getString(R.string.portfolio_view_time_title_today) : DATE_FORMAT_SHORT.format(timestamp)); if (!graphTimeAdapter.getItem(GRAPH_TIME_HOURLY_INDEX).equals(label)) { graphTimeAdapter.set(GRAPH_TIME_HOURLY_INDEX, label); } } dailyGraphView.bind(performanceItems, (graphTimeSelectedPosition == GRAPH_TIME_HOURLY_INDEX)); emptyGraphView.setVisibility(GONE); dailyGraphView.setVisibility(VISIBLE); } else { dailyGraphView.setVisibility(GONE); emptyGraphView.setVisibility(VISIBLE); } } } @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); SavedState ss = new SavedState(superState); ss.mAccountSelectedPosition = this.accountSelectedPosition; ss.mAccountIds = this.accountIds; ss.mGraphTimeSelectedPosition = this.graphTimeSelectedPosition; return ss; } @Override public void onRestoreInstanceState(Parcelable state) { if(!(state instanceof SavedState)) { super.onRestoreInstanceState(state); return; } SavedState ss = (SavedState)state; super.onRestoreInstanceState(ss.getSuperState()); this.accountSelectedPosition = ss.mAccountSelectedPosition; this.accountIds = ss.mAccountIds; this.graphTimeSelectedPosition = ss.mGraphTimeSelectedPosition; } static class SavedState extends BaseSavedState { int mAccountSelectedPosition; int mGraphTimeSelectedPosition; List<Long> mAccountIds; SavedState(Parcelable superState) { super(superState); } private SavedState(Parcel in) { super(in); mAccountSelectedPosition = in.readInt(); mAccountIds = new ArrayList<>(); in.readList(mAccountIds, getClass().getClassLoader()); mGraphTimeSelectedPosition = in.readInt(); } @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(mAccountSelectedPosition); out.writeList(mAccountIds); out.writeInt(mGraphTimeSelectedPosition); } public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() { public SavedState createFromParcel(Parcel in) { return new SavedState(in); } public SavedState[] newArray(int size) { return new SavedState[size]; } }; } private static class GraphTimeAdapter extends BaseAdapter { private final LayoutInflater mInflater; private final int mResource; private final int mDropDownResource; private final List<String> mDataItems = new ArrayList<>(); private GraphTimeAdapter(Context context, @LayoutRes int resource, @LayoutRes int dropdownResource) { this.mInflater = LayoutInflater.from(context); this.mResource = resource; this.mDropDownResource = dropdownResource; } @Override public int getCount() { return mDataItems.size(); } @Override public String getItem(int position) { return mDataItems.get(position); } @Override public long getItemId(int position) { return position; } public void add(String item) { mDataItems.add(item); } public void set(int position, String text) { mDataItems.set(position, text); notifyDataSetChanged(); } @Override public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mResource); } @Override public View getDropDownView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mDropDownResource); } private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) { View view; TextView text; if (convertView == null) { view = mInflater.inflate(resource, parent, false); } else { view = convertView; } text = (TextView) view; text.setText(getItem(position)); return view; } } }