blob: 5e93d5046f3aa0dcbda4501582a9655b0475fa80 [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
Christine Franks7485df52016-12-01 13:18:45 -080036import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
37
Annie Chinabd202f2016-10-14 14:23:45 -070038public class HistoryFragment extends Fragment {
39
40 public static final String TAG = "HistoryFragment";
41
Annie Chind0f87d22016-10-24 09:04:12 -070042 private final DragLayout.DragCallback mDragCallback =
43 new DragLayout.DragCallback() {
44 @Override
Annie Chin9a211132016-11-30 12:52:06 -080045 public void onStartDraggingOpen() {
Annie Chind0f87d22016-10-24 09:04:12 -070046 // no-op
47 }
48
49 @Override
50 public void whileDragging(float yFraction) {
Annie Chin0e88baa2016-11-28 15:23:07 -080051 mDragController.animateViews(yFraction, mRecyclerView);
Annie Chind0f87d22016-10-24 09:04:12 -070052 }
53
54 @Override
Annie Chind0f87d22016-10-24 09:04:12 -070055 public boolean shouldInterceptTouchEvent(MotionEvent event) {
Annie Chinc5b6e4f2016-12-05 13:34:14 -080056 return !mRecyclerView.canScrollVertically(1);
Annie Chind0f87d22016-10-24 09:04:12 -070057 }
58
59 @Override
60 public int getDisplayHeight() {
61 return 0;
62 }
63
64 @Override
65 public void onLayout(int translation) {
66 // no-op
67 }
68 };
69
70 private final DragController mDragController = new DragController();
71
72 private RecyclerView mRecyclerView;
73 private HistoryAdapter mAdapter;
Annie Chinb2e96182016-11-28 13:14:54 -080074 private DragLayout mDragLayout;
Annie Chind0f87d22016-10-24 09:04:12 -070075
Annie Chin06fd3cf2016-11-07 16:04:33 -080076 private Evaluator mEvaluator;
77
78 private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
79
Annie Chind0f87d22016-10-24 09:04:12 -070080 @Override
81 public void onCreate(Bundle savedInstanceState) {
82 super.onCreate(savedInstanceState);
83
Annie Chin06fd3cf2016-11-07 16:04:33 -080084 mAdapter = new HistoryAdapter((Calculator) getActivity(), mDataSet,
Annie Chind0f87d22016-10-24 09:04:12 -070085 getContext().getResources().getString(R.string.title_current_expression));
86 }
87
Annie Chinabd202f2016-10-14 14:23:45 -070088 @Override
89 public View onCreateView(LayoutInflater inflater, ViewGroup container,
90 Bundle savedInstanceState) {
91 final View view = inflater.inflate(
92 R.layout.fragment_history, container, false /* attachToRoot */);
93
Annie Chind0f87d22016-10-24 09:04:12 -070094 mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
Christine Franks7485df52016-12-01 13:18:45 -080095 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
96 @Override
97 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
98 if (newState == SCROLL_STATE_DRAGGING) {
99 stopActionModeOrContextMenu();
100 }
101 super.onScrollStateChanged(recyclerView, newState);
102 }
103 });
Annie Chind0f87d22016-10-24 09:04:12 -0700104
105 // The size of the RecyclerView is not affected by the adapter's contents.
Annie Chin36147982016-12-01 15:07:34 -0800106 mRecyclerView.setHasFixedSize(true);
Annie Chind0f87d22016-10-24 09:04:12 -0700107 mRecyclerView.setAdapter(mAdapter);
108
Annie Chinabd202f2016-10-14 14:23:45 -0700109 final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
110 toolbar.inflateMenu(R.menu.fragment_history);
111 toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
112 @Override
113 public boolean onMenuItemClick(MenuItem item) {
114 if (item.getItemId() == R.id.menu_clear_history) {
115 clearHistory();
116 return true;
117 }
118 return onOptionsItemSelected(item);
119 }
120 });
121 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
122 @Override
123 public void onClick(View v) {
Annie Chin09547532016-10-14 10:59:07 -0700124 getActivity().onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700125 }
126 });
Annie Chinbc001882016-11-09 19:41:21 -0800127
Annie Chinabd202f2016-10-14 14:23:45 -0700128 return view;
129 }
130
131 @Override
Annie Chind0f87d22016-10-24 09:04:12 -0700132 public void onActivityCreated(Bundle savedInstanceState) {
133 super.onActivityCreated(savedInstanceState);
134
Annie Chin70ac8ea2016-11-18 14:43:56 -0800135 final Calculator activity = (Calculator) getActivity();
Annie Chin94c1bd92016-11-23 13:39:56 -0800136 final boolean isResultLayout = activity.isResultLayout();
Annie Chin70ac8ea2016-11-18 14:43:56 -0800137
Annie Chinb2e96182016-11-28 13:14:54 -0800138 mDragLayout = (DragLayout) activity.findViewById(R.id.drag_layout);
139 mDragLayout.removeDragCallback(mDragCallback);
140 mDragLayout.addDragCallback(mDragCallback);
141
Annie Chin70ac8ea2016-11-18 14:43:56 -0800142 mEvaluator = Evaluator.getInstance(activity);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800143
144 if (mEvaluator != null) {
Annie Chin94c1bd92016-11-23 13:39:56 -0800145 initializeController(isResultLayout);
Annie Chinbc001882016-11-09 19:41:21 -0800146
Annie Chin06fd3cf2016-11-07 16:04:33 -0800147 final long maxIndex = mEvaluator.getMaxIndex();
148
149 final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
Annie Chinbc001882016-11-09 19:41:21 -0800150
Annie Chin94c1bd92016-11-23 13:39:56 -0800151 if (!EvaluatorStateUtils.isDisplayEmpty(mEvaluator) && !isResultLayout) {
Annie Chin70ac8ea2016-11-18 14:43:56 -0800152 // Add the current expression as the first element in the list (the layout is
153 // reversed and we want the current expression to be the last one in the
154 // recyclerview).
155 // If we are in the result state, the result will animate to the last history
156 // element in the list and there will be no "Current Expression."
Hans Boehm31ea2522016-11-23 17:47:02 -0800157 mEvaluator.copyMainToHistory();
158 newDataSet.add(new HistoryItem(Evaluator.HISTORY_MAIN_INDEX,
159 System.currentTimeMillis(), mEvaluator.getExprAsSpannable(0)));
Annie Chinbc001882016-11-09 19:41:21 -0800160 }
Annie Chin91796232016-11-16 17:27:36 -0800161 for (long i = 0; i < maxIndex; ++i) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800162 newDataSet.add(null);
163 }
Annie Chin36147982016-12-01 15:07:34 -0800164 final boolean isEmpty = newDataSet.isEmpty();
165 mRecyclerView.setBackgroundColor(isEmpty
166 ? ContextCompat.getColor(activity, R.color.empty_history_color)
167 : Color.TRANSPARENT);
168 if (isEmpty) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800169 newDataSet.add(new HistoryItem());
170 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800171 mDataSet = newDataSet;
172 mAdapter.setDataSet(mDataSet);
Annie Chin94c1bd92016-11-23 13:39:56 -0800173 mAdapter.setIsResultLayout(isResultLayout);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800174 }
Annie Chinbc001882016-11-09 19:41:21 -0800175
176 mAdapter.notifyDataSetChanged();
Annie Chinefa259a2016-11-23 14:15:15 -0800177 }
Annie Chinbc001882016-11-09 19:41:21 -0800178
Annie Chinefa259a2016-11-23 14:15:15 -0800179 @Override
180 public void onStart() {
181 super.onStart();
182
183 // The orientation may have changed.
Annie Chin94c1bd92016-11-23 13:39:56 -0800184 mDragController.initializeAnimation(mRecyclerView,
Annie Chinb2e96182016-11-28 13:14:54 -0800185 ((Calculator) getActivity()).isResultLayout(), mDragLayout.isOpen());
Annie Chind0f87d22016-10-24 09:04:12 -0700186 }
187
188 @Override
Annie Chinabd202f2016-10-14 14:23:45 -0700189 public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
190 final View view = getView();
191 final int height = getResources().getDisplayMetrics().heightPixels;
Annie Chin91796232016-11-16 17:27:36 -0800192 if (enter) {
Annie Chin1ff328d2016-11-22 12:57:46 -0800193 if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
194 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height, 0f);
195 } else {
196 return null;
197 }
Annie Chin91796232016-11-16 17:27:36 -0800198 } else {
199 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height);
Annie Chinabd202f2016-10-14 14:23:45 -0700200 }
Annie Chinabd202f2016-10-14 14:23:45 -0700201 }
202
Annie Chind0f87d22016-10-24 09:04:12 -0700203 @Override
204 public void onDestroyView() {
205 final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
206 if (dragLayout != null) {
207 dragLayout.removeDragCallback(mDragCallback);
208 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800209
Annie Chin9a211132016-11-30 12:52:06 -0800210 // Note that the view is destroyed when the fragment backstack is popped, so
211 // these are essentially called when the DragLayout is closed.
Hans Boehm31ea2522016-11-23 17:47:02 -0800212 mEvaluator.cancelNonMain();
Annie Chin9a211132016-11-30 12:52:06 -0800213
214 super.onDestroyView();
Annie Chind0f87d22016-10-24 09:04:12 -0700215 }
216
Annie Chin94c1bd92016-11-23 13:39:56 -0800217 private void initializeController(boolean isResult) {
Annie Chind0f87d22016-10-24 09:04:12 -0700218 mDragController.setDisplayFormula(
219 (CalculatorFormula) getActivity().findViewById(R.id.formula));
220
221 mDragController.setDisplayResult(
222 (CalculatorResult) getActivity().findViewById(R.id.result));
223
224 mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
Annie Chinbc001882016-11-09 19:41:21 -0800225
226 mDragController.setEvaluator(mEvaluator);
Annie Chin94c1bd92016-11-23 13:39:56 -0800227
228 mDragController.initializeController(isResult);
Annie Chind0f87d22016-10-24 09:04:12 -0700229 }
230
Annie Chinabd202f2016-10-14 14:23:45 -0700231 private void clearHistory() {
Hans Boehm9db3ee22016-11-18 10:09:47 -0800232 // TODO: Try to preserve the current, saved, and memory expressions. How should we
233 // handle expressions to which they refer?
234 // FIXME: This should clearly happen on a background thread.
235 mEvaluator.clearEverything();
236 // TODO: It's not clear what we should really do here. This is an initial hack.
237 // May want to make onClearAnimationEnd() private if/when we fix this.
238 Calculator calculator = (Calculator) getActivity();
239 calculator.onClearAnimationEnd();
240 calculator.onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700241 }
Christine Franks7485df52016-12-01 13:18:45 -0800242
243 public boolean stopActionModeOrContextMenu() {
Annie Chin1fcfc312016-12-06 09:36:36 -0800244 if (mRecyclerView == null) {
245 return false;
246 }
Christine Franks7485df52016-12-01 13:18:45 -0800247 for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
248 final View view = mRecyclerView.getChildAt(i);
249 final HistoryAdapter.ViewHolder viewHolder =
250 (HistoryAdapter.ViewHolder) mRecyclerView.getChildViewHolder(view);
251 if (viewHolder != null && viewHolder.getResult().stopActionModeOrContextMenu()) {
252 return true;
253 }
254 }
255 return false;
256 }
Annie Chinabd202f2016-10-14 14:23:45 -0700257}