blob: f65f1e9be110f875619ca9bd1b05ba574a30ffc3 [file] [log] [blame]
Annie Chinabd202f2016-10-14 14:23:45 -07001/*
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
17package com.android.calculator2;
18
19import android.animation.Animator;
20import android.animation.ObjectAnimator;
21import android.app.Fragment;
Annie Chin1ff328d2016-11-22 12:57:46 -080022import android.app.FragmentTransaction;
Annie Chin36147982016-12-01 15:07:34 -080023import android.graphics.Color;
Annie Chinabd202f2016-10-14 14:23:45 -070024import android.os.Bundle;
Annie Chin36147982016-12-01 15:07:34 -080025import android.support.v4.content.ContextCompat;
Annie Chind0f87d22016-10-24 09:04:12 -070026import android.support.v7.widget.RecyclerView;
Annie Chinabd202f2016-10-14 14:23:45 -070027import android.view.LayoutInflater;
28import android.view.MenuItem;
Annie Chind0f87d22016-10-24 09:04:12 -070029import android.view.MotionEvent;
Annie Chinabd202f2016-10-14 14:23:45 -070030import android.view.View;
31import android.view.ViewGroup;
32import android.widget.Toolbar;
33
Annie Chin06fd3cf2016-11-07 16:04:33 -080034import java.util.ArrayList;
35
Annie Chinabd202f2016-10-14 14:23:45 -070036public class HistoryFragment extends Fragment {
37
38 public static final String TAG = "HistoryFragment";
39
Annie Chind0f87d22016-10-24 09:04:12 -070040 private final DragLayout.DragCallback mDragCallback =
41 new DragLayout.DragCallback() {
42 @Override
Annie Chin9a211132016-11-30 12:52:06 -080043 public void onStartDraggingOpen() {
Annie Chind0f87d22016-10-24 09:04:12 -070044 // no-op
45 }
46
47 @Override
48 public void whileDragging(float yFraction) {
Annie Chin0e88baa2016-11-28 15:23:07 -080049 mDragController.animateViews(yFraction, mRecyclerView);
Annie Chind0f87d22016-10-24 09:04:12 -070050 }
51
52 @Override
Annie Chind0f87d22016-10-24 09:04:12 -070053 public boolean allowDrag(MotionEvent event) {
54 // Do not allow drag if the recycler view can move down more
55 return !mRecyclerView.canScrollVertically(1);
56 }
57
58 @Override
59 public boolean shouldInterceptTouchEvent(MotionEvent event) {
60 return true;
61 }
62
63 @Override
64 public int getDisplayHeight() {
65 return 0;
66 }
67
68 @Override
69 public void onLayout(int translation) {
70 // no-op
71 }
72 };
73
74 private final DragController mDragController = new DragController();
75
76 private RecyclerView mRecyclerView;
77 private HistoryAdapter mAdapter;
Annie Chinb2e96182016-11-28 13:14:54 -080078 private DragLayout mDragLayout;
Annie Chind0f87d22016-10-24 09:04:12 -070079
Annie Chin06fd3cf2016-11-07 16:04:33 -080080 private Evaluator mEvaluator;
81
82 private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
83
Annie Chind0f87d22016-10-24 09:04:12 -070084 @Override
85 public void onCreate(Bundle savedInstanceState) {
86 super.onCreate(savedInstanceState);
87
Annie Chin06fd3cf2016-11-07 16:04:33 -080088 mAdapter = new HistoryAdapter((Calculator) getActivity(), mDataSet,
Annie Chind0f87d22016-10-24 09:04:12 -070089 getContext().getResources().getString(R.string.title_current_expression));
90 }
91
Annie Chinabd202f2016-10-14 14:23:45 -070092 @Override
93 public View onCreateView(LayoutInflater inflater, ViewGroup container,
94 Bundle savedInstanceState) {
95 final View view = inflater.inflate(
96 R.layout.fragment_history, container, false /* attachToRoot */);
97
Annie Chind0f87d22016-10-24 09:04:12 -070098 mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
99
100 // The size of the RecyclerView is not affected by the adapter's contents.
Annie Chin36147982016-12-01 15:07:34 -0800101 mRecyclerView.setHasFixedSize(true);
Annie Chind0f87d22016-10-24 09:04:12 -0700102 mRecyclerView.setAdapter(mAdapter);
103
Annie Chinabd202f2016-10-14 14:23:45 -0700104 final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
105 toolbar.inflateMenu(R.menu.fragment_history);
106 toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
107 @Override
108 public boolean onMenuItemClick(MenuItem item) {
109 if (item.getItemId() == R.id.menu_clear_history) {
110 clearHistory();
111 return true;
112 }
113 return onOptionsItemSelected(item);
114 }
115 });
116 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
117 @Override
118 public void onClick(View v) {
Annie Chin09547532016-10-14 10:59:07 -0700119 getActivity().onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700120 }
121 });
Annie Chinbc001882016-11-09 19:41:21 -0800122
Annie Chinabd202f2016-10-14 14:23:45 -0700123 return view;
124 }
125
126 @Override
Annie Chind0f87d22016-10-24 09:04:12 -0700127 public void onActivityCreated(Bundle savedInstanceState) {
128 super.onActivityCreated(savedInstanceState);
129
Annie Chin70ac8ea2016-11-18 14:43:56 -0800130 final Calculator activity = (Calculator) getActivity();
Annie Chin94c1bd92016-11-23 13:39:56 -0800131 final boolean isResultLayout = activity.isResultLayout();
Annie Chin70ac8ea2016-11-18 14:43:56 -0800132
Annie Chinb2e96182016-11-28 13:14:54 -0800133 mDragLayout = (DragLayout) activity.findViewById(R.id.drag_layout);
134 mDragLayout.removeDragCallback(mDragCallback);
135 mDragLayout.addDragCallback(mDragCallback);
136
Annie Chin70ac8ea2016-11-18 14:43:56 -0800137 mEvaluator = Evaluator.getInstance(activity);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800138
139 if (mEvaluator != null) {
Annie Chin94c1bd92016-11-23 13:39:56 -0800140 initializeController(isResultLayout);
Annie Chinbc001882016-11-09 19:41:21 -0800141
Annie Chin06fd3cf2016-11-07 16:04:33 -0800142 final long maxIndex = mEvaluator.getMaxIndex();
143
144 final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
Annie Chinbc001882016-11-09 19:41:21 -0800145
Annie Chin94c1bd92016-11-23 13:39:56 -0800146 if (!EvaluatorStateUtils.isDisplayEmpty(mEvaluator) && !isResultLayout) {
Annie Chin70ac8ea2016-11-18 14:43:56 -0800147 // Add the current expression as the first element in the list (the layout is
148 // reversed and we want the current expression to be the last one in the
149 // recyclerview).
150 // If we are in the result state, the result will animate to the last history
151 // element in the list and there will be no "Current Expression."
Hans Boehm31ea2522016-11-23 17:47:02 -0800152 mEvaluator.copyMainToHistory();
153 newDataSet.add(new HistoryItem(Evaluator.HISTORY_MAIN_INDEX,
154 System.currentTimeMillis(), mEvaluator.getExprAsSpannable(0)));
Annie Chinbc001882016-11-09 19:41:21 -0800155 }
Annie Chin91796232016-11-16 17:27:36 -0800156 for (long i = 0; i < maxIndex; ++i) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800157 newDataSet.add(null);
158 }
Annie Chin36147982016-12-01 15:07:34 -0800159 final boolean isEmpty = newDataSet.isEmpty();
160 mRecyclerView.setBackgroundColor(isEmpty
161 ? ContextCompat.getColor(activity, R.color.empty_history_color)
162 : Color.TRANSPARENT);
163 if (isEmpty) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800164 newDataSet.add(new HistoryItem());
165 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800166 mDataSet = newDataSet;
167 mAdapter.setDataSet(mDataSet);
Annie Chin94c1bd92016-11-23 13:39:56 -0800168 mAdapter.setIsResultLayout(isResultLayout);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800169 }
Annie Chinbc001882016-11-09 19:41:21 -0800170
171 mAdapter.notifyDataSetChanged();
Annie Chinefa259a2016-11-23 14:15:15 -0800172 }
Annie Chinbc001882016-11-09 19:41:21 -0800173
Annie Chinefa259a2016-11-23 14:15:15 -0800174 @Override
175 public void onStart() {
176 super.onStart();
177
178 // The orientation may have changed.
Annie Chin94c1bd92016-11-23 13:39:56 -0800179 mDragController.initializeAnimation(mRecyclerView,
Annie Chinb2e96182016-11-28 13:14:54 -0800180 ((Calculator) getActivity()).isResultLayout(), mDragLayout.isOpen());
Annie Chind0f87d22016-10-24 09:04:12 -0700181 }
182
183 @Override
Annie Chinabd202f2016-10-14 14:23:45 -0700184 public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
185 final View view = getView();
186 final int height = getResources().getDisplayMetrics().heightPixels;
Annie Chin91796232016-11-16 17:27:36 -0800187 if (enter) {
Annie Chin1ff328d2016-11-22 12:57:46 -0800188 if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
189 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height, 0f);
190 } else {
191 return null;
192 }
Annie Chin91796232016-11-16 17:27:36 -0800193 } else {
194 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height);
Annie Chinabd202f2016-10-14 14:23:45 -0700195 }
Annie Chinabd202f2016-10-14 14:23:45 -0700196 }
197
Annie Chind0f87d22016-10-24 09:04:12 -0700198 @Override
199 public void onDestroyView() {
200 final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
201 if (dragLayout != null) {
202 dragLayout.removeDragCallback(mDragCallback);
203 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800204
Annie Chin9a211132016-11-30 12:52:06 -0800205 // Note that the view is destroyed when the fragment backstack is popped, so
206 // these are essentially called when the DragLayout is closed.
Hans Boehm31ea2522016-11-23 17:47:02 -0800207 mEvaluator.cancelNonMain();
Annie Chin9a211132016-11-30 12:52:06 -0800208
209 super.onDestroyView();
Annie Chind0f87d22016-10-24 09:04:12 -0700210 }
211
Annie Chin94c1bd92016-11-23 13:39:56 -0800212 private void initializeController(boolean isResult) {
Annie Chind0f87d22016-10-24 09:04:12 -0700213 mDragController.setDisplayFormula(
214 (CalculatorFormula) getActivity().findViewById(R.id.formula));
215
216 mDragController.setDisplayResult(
217 (CalculatorResult) getActivity().findViewById(R.id.result));
218
219 mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
Annie Chinbc001882016-11-09 19:41:21 -0800220
221 mDragController.setEvaluator(mEvaluator);
Annie Chin94c1bd92016-11-23 13:39:56 -0800222
223 mDragController.initializeController(isResult);
Annie Chind0f87d22016-10-24 09:04:12 -0700224 }
225
Annie Chinabd202f2016-10-14 14:23:45 -0700226 private void clearHistory() {
Hans Boehm9db3ee22016-11-18 10:09:47 -0800227 // TODO: Try to preserve the current, saved, and memory expressions. How should we
228 // handle expressions to which they refer?
229 // FIXME: This should clearly happen on a background thread.
230 mEvaluator.clearEverything();
231 // TODO: It's not clear what we should really do here. This is an initial hack.
232 // May want to make onClearAnimationEnd() private if/when we fix this.
233 Calculator calculator = (Calculator) getActivity();
234 calculator.onClearAnimationEnd();
235 calculator.onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700236 }
237}