Merge "Implement grouped headers." into ub-calculator-euler
diff --git a/res/layout/empty_history_view.xml b/res/layout/empty_history_view.xml
index cd5b759..7814b52 100644
--- a/res/layout/empty_history_view.xml
+++ b/res/layout/empty_history_view.xml
@@ -18,8 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/empty_history_view"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@color/empty_history_color">
+ android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
diff --git a/res/layout/fragment_history.xml b/res/layout/fragment_history.xml
index c8c0bc8..0d8ed9b 100644
--- a/res/layout/fragment_history.xml
+++ b/res/layout/fragment_history.xml
@@ -40,6 +40,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
+ android:clipToPadding="false"
+ android:paddingBottom="@dimen/history_divider_padding"
app:layoutManager="LinearLayoutManager"
app:reverseLayout="true" />
</LinearLayout>
diff --git a/res/layout/history_item.xml b/res/layout/history_item.xml
index 3baaf73..eaa95ad 100644
--- a/res/layout/history_item.xml
+++ b/res/layout/history_item.xml
@@ -19,16 +19,27 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingTop="@dimen/history_divider_padding"
android:clipChildren="false"
+ android:clipToPadding="false"
android:orientation="vertical">
+ <View
+ android:id="@+id/history_divider"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/history_divider_padding"
+ android:layout_marginBottom="@dimen/history_divider_padding"
+ android:background="?android:attr/listDivider"
+ android:importantForAccessibility="no" />
+
<TextView
android:id="@+id/history_date"
android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:layout_height="wrap_content"
android:fontFamily="sans-serif-medium"
- android:paddingStart="@dimen/history_item_text_padding_start"
- android:paddingEnd="@dimen/history_item_text_padding_end"
+ android:paddingStart="@dimen/result_padding_start"
+ android:paddingEnd="@dimen/result_padding_end"
android:text="@string/title_current_expression"
android:textColor="?android:attr/colorAccent"
android:textSize="14dp" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9de65d5..225cde3 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -20,9 +20,9 @@
<!-- The margin between the pad pages when displayed using a view pager. -->
<dimen name="pad_page_margin">24dip</dimen>
+ <dimen name="history_divider_padding">14dip</dimen>
+
<dimen name="history_item_text_padding_top">8dip</dimen>
<dimen name="history_item_text_padding_bottom">16dip</dimen>
- <dimen name="history_item_text_padding_start">16dip</dimen>
- <dimen name="history_item_text_padding_end">24dip</dimen>
</resources>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 773c5a8..9e45a75 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -49,8 +49,9 @@
<item name="android:layout_gravity">bottom|end</item>
<item name="android:paddingTop">@dimen/history_item_text_padding_top</item>
<item name="android:paddingBottom">@dimen/history_item_text_padding_bottom</item>
- <item name="android:paddingStart">@dimen/history_item_text_padding_start</item>
- <item name="android:paddingEnd">@dimen/history_item_text_padding_end</item>
+ <!-- Note: result_padding_start == formula_padding_start. -->
+ <item name="android:paddingStart">@dimen/result_padding_start</item>
+ <item name="android:paddingEnd">@dimen/result_padding_end</item>
<item name="android:textSize">@dimen/result_textsize</item>
</style>
diff --git a/src/com/android/calculator2/DragController.java b/src/com/android/calculator2/DragController.java
index 1c31767..ed983c5 100644
--- a/src/com/android/calculator2/DragController.java
+++ b/src/com/android/calculator2/DragController.java
@@ -51,6 +51,9 @@
private int mResultStartColor;
private int mResultEndColor;
+ // The padding at the bottom of the RecyclerView itself.
+ private int mBottomPaddingHeight;
+
private boolean mAnimationInitialized;
private AnimationController mAnimationController;
@@ -97,8 +100,11 @@
final AlignedTextView formula = vh.getFormula();
final CalculatorResult result = vh.getResult();
final TextView date = vh.getDate();
+ final View divider = vh.getDivider();
if (!mAnimationInitialized) {
+ mBottomPaddingHeight = recyclerView.getPaddingBottom();
+
mAnimationController.initializeScales(formula, result);
mAnimationController.initializeColorAnimators(formula, result);
@@ -140,6 +146,7 @@
mResultEndColor));
date.setTranslationY(mAnimationController.getDateTranslationY(yFraction));
+ divider.setTranslationY(mAnimationController.getDateTranslationY(yFraction));
}
} else if (EvaluatorStateUtils.isDisplayEmpty(mEvaluator)) {
// There is no current expression but we still need to collect information
@@ -243,7 +250,8 @@
// difference in result height.
mFormulaTranslationY =
mDisplayFormula.getPaddingBottom() - formula.getPaddingBottom()
- + mDisplayResult.getHeight() - result.getHeight();
+ + mDisplayResult.getHeight() - result.getHeight()
+ - mBottomPaddingHeight;
}
@@ -254,7 +262,8 @@
public void initializeResultTranslationY(CalculatorResult result) {
// Baseline of result moves by the difference in result bottom padding.
- mResultTranslationY = mDisplayResult.getPaddingBottom() - result.getPaddingBottom();
+ mResultTranslationY = mDisplayResult.getPaddingBottom() - result.getPaddingBottom()
+ - mBottomPaddingHeight;
}
public void initializeResultTranslationX(CalculatorResult result) {
@@ -322,7 +331,8 @@
// Baseline of formula moves by the difference in formula bottom padding and the
// difference in the result height.
mFormulaTranslationY = mDisplayFormula.getPaddingBottom() - formula.getPaddingBottom()
- + mDisplayResult.getHeight() - result.getHeight();
+ + mDisplayResult.getHeight() - result.getHeight()
+ - mBottomPaddingHeight;
}
@Override
@@ -334,8 +344,9 @@
@Override
public void initializeResultTranslationY(CalculatorResult result) {
// Baseline of result moves by the difference in result bottom padding.
- mResultTranslationY = mDisplayResult.getBottom() - result.getBottom() +
- mDisplayResult.getPaddingBottom() - result.getPaddingBottom();
+ mResultTranslationY = mDisplayResult.getBottom() - result.getBottom()
+ + mDisplayResult.getPaddingBottom() - result.getPaddingBottom()
+ - mBottomPaddingHeight;
}
@Override
@@ -447,7 +458,7 @@
@Override
public float getHistoryElementTranslationY(float yFraction) {
- return -mDisplayHeight * (1 - yFraction);
+ return -mDisplayHeight * (1 - yFraction) - mBottomPaddingHeight;
}
@Override
diff --git a/src/com/android/calculator2/HistoryAdapter.java b/src/com/android/calculator2/HistoryAdapter.java
index 429d0d7..68ad7bf 100644
--- a/src/com/android/calculator2/HistoryAdapter.java
+++ b/src/com/android/calculator2/HistoryAdapter.java
@@ -23,6 +23,7 @@
import android.widget.TextView;
import java.util.ArrayList;
+import java.util.Calendar;
import java.util.List;
/**
@@ -30,6 +31,8 @@
*/
public class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHolder> {
+ private static final String TAG = "HistoryAdapter";
+
private static final int EMPTY_VIEW_TYPE = 0;
private static final int HISTORY_VIEW_TYPE = 1;
@@ -37,6 +40,8 @@
/* Text/accessibility descriptor for the current expression item. */
private final String mCurrentExpressionDescription;
+ private final Calendar mCalendar = Calendar.getInstance();
+
private List<HistoryItem> mDataSet;
private boolean mIsResultLayout;
@@ -64,7 +69,7 @@
@Override
public void onBindViewHolder(final HistoryAdapter.ViewHolder holder, int position) {
- final HistoryItem item = mDataSet.get(position);
+ final HistoryItem item = getItem(position);
if (item.isEmptyView()) {
return;
@@ -77,7 +82,17 @@
holder.mDate.setText(mCurrentExpressionDescription);
holder.mDate.setContentDescription(mCurrentExpressionDescription);
} else {
- holder.mDate.setText(item.getDateString());
+ // If the previous item occurred on the same date, the current item does not need
+ // a date header.
+ if (shouldShowHeader(position, item)) {
+ holder.mDate.setText(item.getDateString());
+ // Special case -- very first item should not have a divider above it.
+ holder.mDivider.setVisibility(position == getItemCount() - 1
+ ? View.GONE : View.VISIBLE);
+ } else {
+ holder.mDate.setVisibility(View.GONE);
+ holder.mDivider.setVisibility(View.INVISIBLE);
+ }
}
}
@@ -88,6 +103,8 @@
}
mEvaluator.cancel(holder.getItemId(), true);
+ holder.mDate.setVisibility(View.VISIBLE);
+ holder.mDivider.setVisibility(View.VISIBLE);
holder.mDate.setContentDescription(null);
holder.mDate.setText(null);
holder.mFormula.setText(null);
@@ -98,21 +115,12 @@
@Override
public long getItemId(int position) {
- return mDataSet.get(position).getEvaluatorIndex();
+ return getItem(position).getEvaluatorIndex();
}
@Override
public int getItemViewType(int position) {
- HistoryItem item = mDataSet.get(position);
-
- // Continue to lazy-fill the data set
- if (item == null) {
- final int evaluatorIndex = getEvaluatorIndex(position);
- item = new HistoryItem(evaluatorIndex, mEvaluator.getTimeStamp(evaluatorIndex),
- mEvaluator.getExprAsSpannable(evaluatorIndex));
- mDataSet.set(position, item);
- }
- return item.isEmptyView() ? EMPTY_VIEW_TYPE : HISTORY_VIEW_TYPE;
+ return getItem(position).isEmptyView() ? EMPTY_VIEW_TYPE : HISTORY_VIEW_TYPE;
}
@Override
@@ -124,17 +132,49 @@
mDataSet = dataSet;
}
+ public void setIsResultLayout(boolean isResult) {
+ mIsResultLayout = isResult;
+ }
+
private int getEvaluatorIndex(int position) {
if (EvaluatorStateUtils.isDisplayEmpty(mEvaluator) || mIsResultLayout) {
- return (int) mEvaluator.getMaxIndex() - position;
+ return (int) (mEvaluator.getMaxIndex() - position);
} else {
// Account for the additional "Current Expression" with the +1.
- return (int) mEvaluator.getMaxIndex() - position + 1;
+ return (int) (mEvaluator.getMaxIndex() - position + 1);
}
}
- public void setIsResultLayout(boolean isResult) {
- mIsResultLayout = isResult;
+ private boolean shouldShowHeader(int position, HistoryItem item) {
+ if (position == getItemCount() - 1) {
+ // First/oldest element should always show the header.
+ return true;
+ }
+ final HistoryItem prevItem = getItem(position + 1);
+ // We need to use Calendars to determine this because of Daylight Savings.
+ mCalendar.setTimeInMillis(item.getTimeInMillis());
+ final int year = mCalendar.get(Calendar.YEAR);
+ final int day = mCalendar.get(Calendar.DAY_OF_YEAR);
+ mCalendar.setTimeInMillis(prevItem.getTimeInMillis());
+ final int prevYear = mCalendar.get(Calendar.YEAR);
+ final int prevDay = mCalendar.get(Calendar.DAY_OF_YEAR);
+ return year != prevYear || day != prevDay;
+ }
+
+ /**
+ * Gets the HistoryItem from mDataSet, lazy-filling the dataSet if necessary.
+ */
+ private HistoryItem getItem(int position) {
+ HistoryItem item = mDataSet.get(position);
+ // Lazy-fill the data set.
+ if (item == null) {
+ final int evaluatorIndex = getEvaluatorIndex(position);
+ item = new HistoryItem(evaluatorIndex,
+ mEvaluator.getTimeStamp(evaluatorIndex),
+ mEvaluator.getExprAsSpannable(evaluatorIndex));
+ mDataSet.set(position, item);
+ }
+ return item;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
@@ -142,6 +182,7 @@
private TextView mDate;
private AlignedTextView mFormula;
private CalculatorResult mResult;
+ private View mDivider;
public ViewHolder(View v, int viewType) {
super(v);
@@ -151,6 +192,7 @@
mDate = (TextView) v.findViewById(R.id.history_date);
mFormula = (AlignedTextView) v.findViewById(R.id.history_formula);
mResult = (CalculatorResult) v.findViewById(R.id.history_result);
+ mDivider = v.findViewById(R.id.history_divider);
}
public AlignedTextView getFormula() {
@@ -164,5 +206,9 @@
public TextView getDate() {
return mDate;
}
+
+ public View getDivider() {
+ return mDivider;
+ }
}
-}
+}
\ No newline at end of file
diff --git a/src/com/android/calculator2/HistoryFragment.java b/src/com/android/calculator2/HistoryFragment.java
index 22adcd3..f65f1e9 100644
--- a/src/com/android/calculator2/HistoryFragment.java
+++ b/src/com/android/calculator2/HistoryFragment.java
@@ -20,7 +20,9 @@
import android.animation.ObjectAnimator;
import android.app.Fragment;
import android.app.FragmentTransaction;
+import android.graphics.Color;
import android.os.Bundle;
+import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
@@ -96,6 +98,7 @@
mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
// The size of the RecyclerView is not affected by the adapter's contents.
+ mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(mAdapter);
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
@@ -153,7 +156,11 @@
for (long i = 0; i < maxIndex; ++i) {
newDataSet.add(null);
}
- if (newDataSet.isEmpty()) {
+ final boolean isEmpty = newDataSet.isEmpty();
+ mRecyclerView.setBackgroundColor(isEmpty
+ ? ContextCompat.getColor(activity, R.color.empty_history_color)
+ : Color.TRANSPARENT);
+ if (isEmpty) {
newDataSet.add(new HistoryItem());
}
mDataSet = newDataSet;
diff --git a/src/com/android/calculator2/HistoryItem.java b/src/com/android/calculator2/HistoryItem.java
index 5694cc7..f20d1a7 100644
--- a/src/com/android/calculator2/HistoryItem.java
+++ b/src/com/android/calculator2/HistoryItem.java
@@ -57,6 +57,10 @@
DateUtils.DAY_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE);
}
+ public long getTimeInMillis() {
+ return mTimeInMillis;
+ }
+
public Spannable getFormula() {
return mFormula;
}