Home | History | Annotate | Download | only in calculator2
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *   http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.calculator2;
     18 
     19 import androidx.recyclerview.widget.RecyclerView;
     20 import android.view.LayoutInflater;
     21 import android.view.View;
     22 import android.view.ViewGroup;
     23 import android.widget.TextView;
     24 
     25 import java.util.ArrayList;
     26 import java.util.Calendar;
     27 import java.util.List;
     28 
     29 /**
     30  * Adapter for RecyclerView of HistoryItems.
     31  */
     32 public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHolder> {
     33 
     34     private static final String TAG = "HistoryAdapter";
     35 
     36     private static final int EMPTY_VIEW_TYPE = 0;
     37     public static final int HISTORY_VIEW_TYPE = 1;
     38 
     39     private Evaluator mEvaluator;
     40 
     41     private final Calendar mCalendar = Calendar.getInstance();
     42 
     43     private List<HistoryItem> mDataSet;
     44 
     45     private boolean mIsResultLayout;
     46     private boolean mIsOneLine;
     47     private boolean mIsDisplayEmpty;
     48 
     49     public HistoryAdapter(ArrayList<HistoryItem> dataSet) {
     50         mDataSet = dataSet;
     51         setHasStableIds(true);
     52     }
     53 
     54     @Override
     55     public HistoryAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
     56         final View v;
     57         if (viewType == HISTORY_VIEW_TYPE) {
     58             v = LayoutInflater.from(parent.getContext())
     59                     .inflate(R.layout.history_item, parent, false);
     60         } else {
     61             v = LayoutInflater.from(parent.getContext())
     62                     .inflate(R.layout.empty_history_view, parent, false);
     63         }
     64         return new ViewHolder(v, viewType);
     65     }
     66 
     67     @Override
     68     public void onBindViewHolder(final HistoryAdapter.ViewHolder holder, int position) {
     69         final HistoryItem item = getItem(position);
     70 
     71         if (item.isEmptyView()) {
     72             return;
     73         }
     74 
     75         holder.mFormula.setText(item.getFormula());
     76         // Note: HistoryItems that are not the current expression will always have interesting ops.
     77         holder.mResult.setEvaluator(mEvaluator, item.getEvaluatorIndex());
     78         if (item.getEvaluatorIndex() == Evaluator.HISTORY_MAIN_INDEX) {
     79             holder.mDate.setText(R.string.title_current_expression);
     80             holder.mResult.setVisibility(mIsOneLine ? View.GONE : View.VISIBLE);
     81         } else {
     82             // If the previous item occurred on the same date, the current item does not need
     83             // a date header.
     84             if (shouldShowHeader(position, item)) {
     85                 holder.mDate.setText(item.getDateString());
     86                 // Special case -- very first item should not have a divider above it.
     87                 holder.mDivider.setVisibility(position == getItemCount() - 1
     88                         ? View.GONE : View.VISIBLE);
     89             } else {
     90                 holder.mDate.setVisibility(View.GONE);
     91                 holder.mDivider.setVisibility(View.INVISIBLE);
     92             }
     93         }
     94     }
     95 
     96     @Override
     97     public void onViewRecycled(ViewHolder holder) {
     98         if (holder.getItemViewType() == EMPTY_VIEW_TYPE) {
     99             return;
    100         }
    101         mEvaluator.cancel(holder.getItemId(), true);
    102 
    103         holder.mDate.setVisibility(View.VISIBLE);
    104         holder.mDivider.setVisibility(View.VISIBLE);
    105         holder.mDate.setText(null);
    106         holder.mFormula.setText(null);
    107         holder.mResult.setText(null);
    108 
    109         super.onViewRecycled(holder);
    110     }
    111 
    112     @Override
    113     public long getItemId(int position) {
    114         return getItem(position).getEvaluatorIndex();
    115     }
    116 
    117     @Override
    118     public int getItemViewType(int position) {
    119         return getItem(position).isEmptyView() ? EMPTY_VIEW_TYPE : HISTORY_VIEW_TYPE;
    120     }
    121 
    122     @Override
    123     public int getItemCount() {
    124         return mDataSet.size();
    125     }
    126 
    127     public void setDataSet(ArrayList<HistoryItem> dataSet) {
    128         mDataSet = dataSet;
    129     }
    130 
    131     public void setIsResultLayout(boolean isResult) {
    132         mIsResultLayout = isResult;
    133     }
    134 
    135     public void setIsOneLine(boolean isOneLine) {
    136         mIsOneLine = isOneLine;
    137     }
    138 
    139     public void setIsDisplayEmpty(boolean isDisplayEmpty) {
    140         mIsDisplayEmpty = isDisplayEmpty;
    141     }
    142 
    143     public void setEvaluator(Evaluator evaluator) {
    144         mEvaluator = evaluator;
    145     }
    146 
    147     private int getEvaluatorIndex(int position) {
    148         if (mIsDisplayEmpty || mIsResultLayout) {
    149             return (int) (mEvaluator.getMaxIndex() - position);
    150         } else {
    151             // Account for the additional "Current Expression" with the +1.
    152             return (int) (mEvaluator.getMaxIndex() - position + 1);
    153         }
    154     }
    155 
    156     private boolean shouldShowHeader(int position, HistoryItem item) {
    157         if (position == getItemCount() - 1) {
    158             // First/oldest element should always show the header.
    159             return true;
    160         }
    161         final HistoryItem prevItem = getItem(position + 1);
    162         // We need to use Calendars to determine this because of Daylight Savings.
    163         mCalendar.setTimeInMillis(item.getTimeInMillis());
    164         final int year = mCalendar.get(Calendar.YEAR);
    165         final int day = mCalendar.get(Calendar.DAY_OF_YEAR);
    166         mCalendar.setTimeInMillis(prevItem.getTimeInMillis());
    167         final int prevYear = mCalendar.get(Calendar.YEAR);
    168         final int prevDay = mCalendar.get(Calendar.DAY_OF_YEAR);
    169         return year != prevYear || day != prevDay;
    170     }
    171 
    172     /**
    173      * Gets the HistoryItem from mDataSet, lazy-filling the dataSet if necessary.
    174      */
    175     private HistoryItem getItem(int position) {
    176         HistoryItem item = mDataSet.get(position);
    177         // Lazy-fill the data set.
    178         if (item == null) {
    179             final int evaluatorIndex = getEvaluatorIndex(position);
    180             item = new HistoryItem(evaluatorIndex,
    181                     mEvaluator.getTimeStamp(evaluatorIndex),
    182                     mEvaluator.getExprAsSpannable(evaluatorIndex));
    183             mDataSet.set(position, item);
    184         }
    185         return item;
    186     }
    187 
    188     public static class ViewHolder extends RecyclerView.ViewHolder {
    189 
    190         private TextView mDate;
    191         private AlignedTextView mFormula;
    192         private CalculatorResult mResult;
    193         private View mDivider;
    194 
    195         public ViewHolder(View v, int viewType) {
    196             super(v);
    197             if (viewType == EMPTY_VIEW_TYPE) {
    198                 return;
    199             }
    200             mDate = (TextView) v.findViewById(R.id.history_date);
    201             mFormula = (AlignedTextView) v.findViewById(R.id.history_formula);
    202             mResult = (CalculatorResult) v.findViewById(R.id.history_result);
    203             mDivider = v.findViewById(R.id.history_divider);
    204         }
    205 
    206         public AlignedTextView getFormula() {
    207             return mFormula;
    208         }
    209 
    210         public CalculatorResult getResult() {
    211             return mResult;
    212         }
    213 
    214         public TextView getDate() {
    215             return mDate;
    216         }
    217 
    218         public View getDivider() {
    219             return mDivider;
    220         }
    221     }
    222 }