blob: b16ccdbe565064d3e403816145dda21169ee6e91 [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;
Annie Chinb2e96182016-11-28 13:14:54 -080082 private DragLayout mDragLayout;
Annie Chind0f87d22016-10-24 09:04:12 -070083
Annie Chin06fd3cf2016-11-07 16:04:33 -080084 private Evaluator mEvaluator;
85
86 private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
87
Annie Chind0f87d22016-10-24 09:04:12 -070088 @Override
89 public void onCreate(Bundle savedInstanceState) {
90 super.onCreate(savedInstanceState);
91
Annie Chin06fd3cf2016-11-07 16:04:33 -080092 mAdapter = new HistoryAdapter((Calculator) getActivity(), mDataSet,
Annie Chind0f87d22016-10-24 09:04:12 -070093 getContext().getResources().getString(R.string.title_current_expression));
94 }
95
Annie Chinabd202f2016-10-14 14:23:45 -070096 @Override
97 public View onCreateView(LayoutInflater inflater, ViewGroup container,
98 Bundle savedInstanceState) {
99 final View view = inflater.inflate(
100 R.layout.fragment_history, container, false /* attachToRoot */);
101
Annie Chind0f87d22016-10-24 09:04:12 -0700102 mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
103
104 // The size of the RecyclerView is not affected by the adapter's contents.
Annie Chind0f87d22016-10-24 09:04:12 -0700105 mRecyclerView.setAdapter(mAdapter);
106
Annie Chinabd202f2016-10-14 14:23:45 -0700107 final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
108 toolbar.inflateMenu(R.menu.fragment_history);
109 toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
110 @Override
111 public boolean onMenuItemClick(MenuItem item) {
112 if (item.getItemId() == R.id.menu_clear_history) {
113 clearHistory();
114 return true;
115 }
116 return onOptionsItemSelected(item);
117 }
118 });
119 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
120 @Override
121 public void onClick(View v) {
Annie Chin09547532016-10-14 10:59:07 -0700122 getActivity().onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700123 }
124 });
Annie Chinbc001882016-11-09 19:41:21 -0800125
Annie Chinabd202f2016-10-14 14:23:45 -0700126 return view;
127 }
128
129 @Override
Annie Chind0f87d22016-10-24 09:04:12 -0700130 public void onActivityCreated(Bundle savedInstanceState) {
131 super.onActivityCreated(savedInstanceState);
132
Annie Chin70ac8ea2016-11-18 14:43:56 -0800133 final Calculator activity = (Calculator) getActivity();
Annie Chin94c1bd92016-11-23 13:39:56 -0800134 final boolean isResultLayout = activity.isResultLayout();
Annie Chin70ac8ea2016-11-18 14:43:56 -0800135
Annie Chinb2e96182016-11-28 13:14:54 -0800136 mDragLayout = (DragLayout) activity.findViewById(R.id.drag_layout);
137 mDragLayout.removeDragCallback(mDragCallback);
138 mDragLayout.addDragCallback(mDragCallback);
139
Annie Chin70ac8ea2016-11-18 14:43:56 -0800140 mEvaluator = Evaluator.getInstance(activity);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800141
142 if (mEvaluator != null) {
Annie Chin94c1bd92016-11-23 13:39:56 -0800143 initializeController(isResultLayout);
Annie Chinbc001882016-11-09 19:41:21 -0800144
Annie Chin06fd3cf2016-11-07 16:04:33 -0800145 final long maxIndex = mEvaluator.getMaxIndex();
146
147 final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
Annie Chinbc001882016-11-09 19:41:21 -0800148
Annie Chin94c1bd92016-11-23 13:39:56 -0800149 if (!EvaluatorStateUtils.isDisplayEmpty(mEvaluator) && !isResultLayout) {
Annie Chin70ac8ea2016-11-18 14:43:56 -0800150 // Add the current expression as the first element in the list (the layout is
151 // reversed and we want the current expression to be the last one in the
152 // recyclerview).
153 // If we are in the result state, the result will animate to the last history
154 // element in the list and there will be no "Current Expression."
Annie Chin91796232016-11-16 17:27:36 -0800155 newDataSet.add(new HistoryItem(Evaluator.MAIN_INDEX, System.currentTimeMillis(),
Annie Chinbc001882016-11-09 19:41:21 -0800156 mEvaluator.getExprAsSpannable(0)));
157 }
Annie Chin91796232016-11-16 17:27:36 -0800158 for (long i = 0; i < maxIndex; ++i) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800159 newDataSet.add(null);
160 }
161 if (maxIndex == 0) {
162 newDataSet.add(new HistoryItem());
163 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800164 mDataSet = newDataSet;
165 mAdapter.setDataSet(mDataSet);
Annie Chin94c1bd92016-11-23 13:39:56 -0800166 mAdapter.setIsResultLayout(isResultLayout);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800167 }
Annie Chinbc001882016-11-09 19:41:21 -0800168
169 mAdapter.notifyDataSetChanged();
Annie Chinefa259a2016-11-23 14:15:15 -0800170 }
Annie Chinbc001882016-11-09 19:41:21 -0800171
Annie Chinefa259a2016-11-23 14:15:15 -0800172 @Override
173 public void onStart() {
174 super.onStart();
175
176 // The orientation may have changed.
Annie Chin94c1bd92016-11-23 13:39:56 -0800177 mDragController.initializeAnimation(mRecyclerView,
Annie Chinb2e96182016-11-28 13:14:54 -0800178 ((Calculator) getActivity()).isResultLayout(), mDragLayout.isOpen());
Annie Chind0f87d22016-10-24 09:04:12 -0700179 }
180
181 @Override
Annie Chinabd202f2016-10-14 14:23:45 -0700182 public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
183 final View view = getView();
184 final int height = getResources().getDisplayMetrics().heightPixels;
Annie Chin91796232016-11-16 17:27:36 -0800185 if (enter) {
Annie Chin1ff328d2016-11-22 12:57:46 -0800186 if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
187 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height, 0f);
188 } else {
189 return null;
190 }
Annie Chin91796232016-11-16 17:27:36 -0800191 } else {
192 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height);
Annie Chinabd202f2016-10-14 14:23:45 -0700193 }
Annie Chinabd202f2016-10-14 14:23:45 -0700194 }
195
Annie Chind0f87d22016-10-24 09:04:12 -0700196 @Override
197 public void onDestroyView() {
198 final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
199 if (dragLayout != null) {
200 dragLayout.removeDragCallback(mDragCallback);
201 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800202
203 mEvaluator.cancelAll(true);
Annie Chind0f87d22016-10-24 09:04:12 -0700204 super.onDestroy();
Hans Boehmbd01e4b2016-11-23 10:12:58 -0800205 // FIXME: There are probably better ways to do this. But we can end up cancelling
206 // an in-progress evaluation for the main expression that we have to restart.
207 ((Calculator)(getActivity())).evaluateInstantIfNecessary();
Annie Chind0f87d22016-10-24 09:04:12 -0700208 }
209
Annie Chin94c1bd92016-11-23 13:39:56 -0800210 private void initializeController(boolean isResult) {
Annie Chind0f87d22016-10-24 09:04:12 -0700211 mDragController.setDisplayFormula(
212 (CalculatorFormula) getActivity().findViewById(R.id.formula));
213
214 mDragController.setDisplayResult(
215 (CalculatorResult) getActivity().findViewById(R.id.result));
216
217 mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
Annie Chinbc001882016-11-09 19:41:21 -0800218
219 mDragController.setEvaluator(mEvaluator);
Annie Chin94c1bd92016-11-23 13:39:56 -0800220
221 mDragController.initializeController(isResult);
Annie Chind0f87d22016-10-24 09:04:12 -0700222 }
223
Annie Chinabd202f2016-10-14 14:23:45 -0700224 private void clearHistory() {
Hans Boehm9db3ee22016-11-18 10:09:47 -0800225 // TODO: Try to preserve the current, saved, and memory expressions. How should we
226 // handle expressions to which they refer?
227 // FIXME: This should clearly happen on a background thread.
228 mEvaluator.clearEverything();
229 // TODO: It's not clear what we should really do here. This is an initial hack.
230 // May want to make onClearAnimationEnd() private if/when we fix this.
231 Calculator calculator = (Calculator) getActivity();
232 calculator.onClearAnimationEnd();
233 calculator.onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700234 }
235}