blob: 6eed1c25153e33c9d7088bc14e0e98f23e0bdf8e [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 Chinabd202f2016-10-14 14:23:45 -070023import android.os.Bundle;
Annie Chind0f87d22016-10-24 09:04:12 -070024import android.support.v7.widget.RecyclerView;
Annie Chinabd202f2016-10-14 14:23:45 -070025import android.view.LayoutInflater;
26import android.view.MenuItem;
Annie Chind0f87d22016-10-24 09:04:12 -070027import android.view.MotionEvent;
Annie Chinabd202f2016-10-14 14:23:45 -070028import android.view.View;
29import android.view.ViewGroup;
30import android.widget.Toolbar;
31
Annie Chin06fd3cf2016-11-07 16:04:33 -080032import java.util.ArrayList;
33
Annie Chinabd202f2016-10-14 14:23:45 -070034public class HistoryFragment extends Fragment {
35
36 public static final String TAG = "HistoryFragment";
37
Annie Chind0f87d22016-10-24 09:04:12 -070038 private final DragLayout.DragCallback mDragCallback =
39 new DragLayout.DragCallback() {
40 @Override
41 public void onStartDragging() {
42 // no-op
43 }
44
45 @Override
46 public void whileDragging(float yFraction) {
47 mDragController.animateViews(yFraction, mRecyclerView, mAdapter.getItemCount());
48 }
49
50 @Override
51 public void onClosed() {
Annie Chin06fd3cf2016-11-07 16:04:33 -080052 // TODO: only cancel historical evaluations
53 mEvaluator.cancelAll(true);
Annie Chind0f87d22016-10-24 09:04:12 -070054 }
55
56 @Override
57 public boolean allowDrag(MotionEvent event) {
58 // Do not allow drag if the recycler view can move down more
59 return !mRecyclerView.canScrollVertically(1);
60 }
61
62 @Override
63 public boolean shouldInterceptTouchEvent(MotionEvent event) {
64 return true;
65 }
66
67 @Override
68 public int getDisplayHeight() {
69 return 0;
70 }
71
72 @Override
73 public void onLayout(int translation) {
74 // no-op
75 }
76 };
77
78 private final DragController mDragController = new DragController();
79
80 private RecyclerView mRecyclerView;
81 private HistoryAdapter mAdapter;
82
Annie Chin06fd3cf2016-11-07 16:04:33 -080083 private Evaluator mEvaluator;
84
85 private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
86
Annie Chind0f87d22016-10-24 09:04:12 -070087 @Override
88 public void onCreate(Bundle savedInstanceState) {
89 super.onCreate(savedInstanceState);
90
Annie Chin06fd3cf2016-11-07 16:04:33 -080091 mAdapter = new HistoryAdapter((Calculator) getActivity(), mDataSet,
Annie Chind0f87d22016-10-24 09:04:12 -070092 getContext().getResources().getString(R.string.title_current_expression));
93 }
94
Annie Chinabd202f2016-10-14 14:23:45 -070095 @Override
96 public View onCreateView(LayoutInflater inflater, ViewGroup container,
97 Bundle savedInstanceState) {
98 final View view = inflater.inflate(
99 R.layout.fragment_history, container, false /* attachToRoot */);
100
Annie Chind0f87d22016-10-24 09:04:12 -0700101 mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
102
103 // The size of the RecyclerView is not affected by the adapter's contents.
Annie Chind0f87d22016-10-24 09:04:12 -0700104 mRecyclerView.setAdapter(mAdapter);
105
Annie Chinabd202f2016-10-14 14:23:45 -0700106 final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
107 toolbar.inflateMenu(R.menu.fragment_history);
108 toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
109 @Override
110 public boolean onMenuItemClick(MenuItem item) {
111 if (item.getItemId() == R.id.menu_clear_history) {
112 clearHistory();
113 return true;
114 }
115 return onOptionsItemSelected(item);
116 }
117 });
118 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
119 @Override
120 public void onClick(View v) {
Annie Chin09547532016-10-14 10:59:07 -0700121 getActivity().onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700122 }
123 });
Annie Chinbc001882016-11-09 19:41:21 -0800124
Annie Chinabd202f2016-10-14 14:23:45 -0700125 return view;
126 }
127
128 @Override
Annie Chind0f87d22016-10-24 09:04:12 -0700129 public void onActivityCreated(Bundle savedInstanceState) {
130 super.onActivityCreated(savedInstanceState);
131
Annie Chind0f87d22016-10-24 09:04:12 -0700132 final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
133 dragLayout.removeDragCallback(mDragCallback);
134 dragLayout.addDragCallback(mDragCallback);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800135
Annie Chin70ac8ea2016-11-18 14:43:56 -0800136 final Calculator activity = (Calculator) getActivity();
Annie Chin94c1bd92016-11-23 13:39:56 -0800137 final boolean isResultLayout = activity.isResultLayout();
Annie Chin70ac8ea2016-11-18 14:43:56 -0800138
139 mEvaluator = Evaluator.getInstance(activity);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800140
141 if (mEvaluator != null) {
Annie Chin94c1bd92016-11-23 13:39:56 -0800142 initializeController(isResultLayout);
Annie Chinbc001882016-11-09 19:41:21 -0800143
Annie Chin06fd3cf2016-11-07 16:04:33 -0800144 final long maxIndex = mEvaluator.getMaxIndex();
145
146 final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
Annie Chinbc001882016-11-09 19:41:21 -0800147
Annie Chin94c1bd92016-11-23 13:39:56 -0800148 if (!EvaluatorStateUtils.isDisplayEmpty(mEvaluator) && !isResultLayout) {
Annie Chin70ac8ea2016-11-18 14:43:56 -0800149 // Add the current expression as the first element in the list (the layout is
150 // reversed and we want the current expression to be the last one in the
151 // recyclerview).
152 // If we are in the result state, the result will animate to the last history
153 // element in the list and there will be no "Current Expression."
Annie Chin91796232016-11-16 17:27:36 -0800154 newDataSet.add(new HistoryItem(Evaluator.MAIN_INDEX, System.currentTimeMillis(),
Annie Chinbc001882016-11-09 19:41:21 -0800155 mEvaluator.getExprAsSpannable(0)));
156 }
Annie Chin91796232016-11-16 17:27:36 -0800157 for (long i = 0; i < maxIndex; ++i) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800158 newDataSet.add(null);
159 }
160 if (maxIndex == 0) {
161 newDataSet.add(new HistoryItem());
162 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800163 mDataSet = newDataSet;
164 mAdapter.setDataSet(mDataSet);
Annie Chin94c1bd92016-11-23 13:39:56 -0800165 mAdapter.setIsResultLayout(isResultLayout);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800166 }
Annie Chinbc001882016-11-09 19:41:21 -0800167
168 mAdapter.notifyDataSetChanged();
Annie Chinefa259a2016-11-23 14:15:15 -0800169 }
Annie Chinbc001882016-11-09 19:41:21 -0800170
Annie Chinefa259a2016-11-23 14:15:15 -0800171 @Override
172 public void onStart() {
173 super.onStart();
174
175 // The orientation may have changed.
Annie Chin94c1bd92016-11-23 13:39:56 -0800176 mDragController.initializeAnimation(mRecyclerView,
177 ((Calculator) getActivity()).isResultLayout());
Annie Chind0f87d22016-10-24 09:04:12 -0700178 }
179
180 @Override
Annie Chinabd202f2016-10-14 14:23:45 -0700181 public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
182 final View view = getView();
183 final int height = getResources().getDisplayMetrics().heightPixels;
Annie Chin91796232016-11-16 17:27:36 -0800184 if (enter) {
Annie Chin1ff328d2016-11-22 12:57:46 -0800185 if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
186 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height, 0f);
187 } else {
188 return null;
189 }
Annie Chin91796232016-11-16 17:27:36 -0800190 } else {
191 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height);
Annie Chinabd202f2016-10-14 14:23:45 -0700192 }
Annie Chinabd202f2016-10-14 14:23:45 -0700193 }
194
Annie Chind0f87d22016-10-24 09:04:12 -0700195 @Override
196 public void onDestroyView() {
197 final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
198 if (dragLayout != null) {
199 dragLayout.removeDragCallback(mDragCallback);
200 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800201
202 mEvaluator.cancelAll(true);
Annie Chind0f87d22016-10-24 09:04:12 -0700203 super.onDestroy();
Hans Boehmbd01e4b2016-11-23 10:12:58 -0800204 // FIXME: There are probably better ways to do this. But we can end up cancelling
205 // an in-progress evaluation for the main expression that we have to restart.
206 ((Calculator)(getActivity())).evaluateInstantIfNecessary();
Annie Chind0f87d22016-10-24 09:04:12 -0700207 }
208
Annie Chin94c1bd92016-11-23 13:39:56 -0800209 private void initializeController(boolean isResult) {
Annie Chind0f87d22016-10-24 09:04:12 -0700210 mDragController.setDisplayFormula(
211 (CalculatorFormula) getActivity().findViewById(R.id.formula));
212
213 mDragController.setDisplayResult(
214 (CalculatorResult) getActivity().findViewById(R.id.result));
215
216 mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
Annie Chinbc001882016-11-09 19:41:21 -0800217
218 mDragController.setEvaluator(mEvaluator);
Annie Chin94c1bd92016-11-23 13:39:56 -0800219
220 mDragController.initializeController(isResult);
Annie Chind0f87d22016-10-24 09:04:12 -0700221 }
222
Annie Chinabd202f2016-10-14 14:23:45 -0700223 private void clearHistory() {
Hans Boehm9db3ee22016-11-18 10:09:47 -0800224 // TODO: Try to preserve the current, saved, and memory expressions. How should we
225 // handle expressions to which they refer?
226 // FIXME: This should clearly happen on a background thread.
227 mEvaluator.clearEverything();
228 // TODO: It's not clear what we should really do here. This is an initial hack.
229 // May want to make onClearAnimationEnd() private if/when we fix this.
230 Calculator calculator = (Calculator) getActivity();
231 calculator.onClearAnimationEnd();
232 calculator.onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700233 }
234}