blob: 454c47af7cfdba5df2f27a602beb84108a1eb78c [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;
29import android.view.View;
30import android.view.ViewGroup;
31import android.widget.Toolbar;
32
Annie Chin06fd3cf2016-11-07 16:04:33 -080033import java.util.ArrayList;
34
Christine Franks7485df52016-12-01 13:18:45 -080035import static android.support.v7.widget.RecyclerView.SCROLL_STATE_DRAGGING;
36
Annie Chin52eed7a2017-01-04 15:06:05 -080037public class HistoryFragment extends Fragment implements DragLayout.DragCallback {
Annie Chinabd202f2016-10-14 14:23:45 -070038
39 public static final String TAG = "HistoryFragment";
Annie Chin532b77e2016-12-06 13:30:35 -080040 public static final String CLEAR_DIALOG_TAG = "clear";
Annie Chinabd202f2016-10-14 14:23:45 -070041
Annie Chind0f87d22016-10-24 09:04:12 -070042 private final DragController mDragController = new DragController();
43
44 private RecyclerView mRecyclerView;
45 private HistoryAdapter mAdapter;
Annie Chinb2e96182016-11-28 13:14:54 -080046 private DragLayout mDragLayout;
Annie Chind0f87d22016-10-24 09:04:12 -070047
Annie Chin06fd3cf2016-11-07 16:04:33 -080048 private Evaluator mEvaluator;
49
50 private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
51
Annie Chind0f87d22016-10-24 09:04:12 -070052 @Override
53 public void onCreate(Bundle savedInstanceState) {
54 super.onCreate(savedInstanceState);
55
Annie Chin7d039632016-12-08 15:23:39 -080056 mAdapter = new HistoryAdapter(mDataSet);
Annie Chind0f87d22016-10-24 09:04:12 -070057 }
58
Annie Chinabd202f2016-10-14 14:23:45 -070059 @Override
60 public View onCreateView(LayoutInflater inflater, ViewGroup container,
61 Bundle savedInstanceState) {
62 final View view = inflater.inflate(
63 R.layout.fragment_history, container, false /* attachToRoot */);
64
Annie Chind0f87d22016-10-24 09:04:12 -070065 mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
Christine Franks7485df52016-12-01 13:18:45 -080066 mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
67 @Override
68 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
69 if (newState == SCROLL_STATE_DRAGGING) {
70 stopActionModeOrContextMenu();
71 }
72 super.onScrollStateChanged(recyclerView, newState);
73 }
74 });
Annie Chind0f87d22016-10-24 09:04:12 -070075
76 // The size of the RecyclerView is not affected by the adapter's contents.
Annie Chin36147982016-12-01 15:07:34 -080077 mRecyclerView.setHasFixedSize(true);
Annie Chind0f87d22016-10-24 09:04:12 -070078 mRecyclerView.setAdapter(mAdapter);
79
Annie Chinabd202f2016-10-14 14:23:45 -070080 final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
81 toolbar.inflateMenu(R.menu.fragment_history);
82 toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
83 @Override
84 public boolean onMenuItemClick(MenuItem item) {
85 if (item.getItemId() == R.id.menu_clear_history) {
Annie Chin532b77e2016-12-06 13:30:35 -080086 final Calculator calculator = (Calculator) getActivity();
87 AlertDialogFragment.showMessageDialog(calculator, "" /* title */,
88 getString(R.string.dialog_clear),
89 getString(R.string.menu_clear_history),
90 CLEAR_DIALOG_TAG);
Annie Chinabd202f2016-10-14 14:23:45 -070091 return true;
92 }
93 return onOptionsItemSelected(item);
94 }
95 });
96 toolbar.setNavigationOnClickListener(new View.OnClickListener() {
97 @Override
98 public void onClick(View v) {
Annie Chin09547532016-10-14 10:59:07 -070099 getActivity().onBackPressed();
Annie Chinabd202f2016-10-14 14:23:45 -0700100 }
101 });
Annie Chinabd202f2016-10-14 14:23:45 -0700102 return view;
103 }
104
105 @Override
Annie Chind0f87d22016-10-24 09:04:12 -0700106 public void onActivityCreated(Bundle savedInstanceState) {
107 super.onActivityCreated(savedInstanceState);
108
Annie Chin70ac8ea2016-11-18 14:43:56 -0800109 final Calculator activity = (Calculator) getActivity();
Christine Frankscbc51fa2017-01-04 21:00:36 -0800110 mEvaluator = Evaluator.getInstance(activity);
111 mAdapter.setEvaluator(mEvaluator);
Annie Chin7d039632016-12-08 15:23:39 -0800112
Annie Chin94c1bd92016-11-23 13:39:56 -0800113 final boolean isResultLayout = activity.isResultLayout();
Annie Chin70ac8ea2016-11-18 14:43:56 -0800114
Annie Chinb2e96182016-11-28 13:14:54 -0800115 mDragLayout = (DragLayout) activity.findViewById(R.id.drag_layout);
Annie Chin52eed7a2017-01-04 15:06:05 -0800116 mDragLayout.removeDragCallback(this);
117 mDragLayout.addDragCallback(this);
Annie Chinb2e96182016-11-28 13:14:54 -0800118
Annie Chin06fd3cf2016-11-07 16:04:33 -0800119 if (mEvaluator != null) {
Annie Chin94c1bd92016-11-23 13:39:56 -0800120 initializeController(isResultLayout);
Annie Chinbc001882016-11-09 19:41:21 -0800121
Annie Chin06fd3cf2016-11-07 16:04:33 -0800122 final long maxIndex = mEvaluator.getMaxIndex();
123
124 final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
Annie Chinbc001882016-11-09 19:41:21 -0800125
Annie Chin94c1bd92016-11-23 13:39:56 -0800126 if (!EvaluatorStateUtils.isDisplayEmpty(mEvaluator) && !isResultLayout) {
Annie Chin70ac8ea2016-11-18 14:43:56 -0800127 // Add the current expression as the first element in the list (the layout is
128 // reversed and we want the current expression to be the last one in the
Annie Chind3443222016-12-07 17:19:07 -0800129 // RecyclerView).
Annie Chin70ac8ea2016-11-18 14:43:56 -0800130 // If we are in the result state, the result will animate to the last history
131 // element in the list and there will be no "Current Expression."
Hans Boehm31ea2522016-11-23 17:47:02 -0800132 mEvaluator.copyMainToHistory();
133 newDataSet.add(new HistoryItem(Evaluator.HISTORY_MAIN_INDEX,
134 System.currentTimeMillis(), mEvaluator.getExprAsSpannable(0)));
Annie Chinbc001882016-11-09 19:41:21 -0800135 }
Annie Chin91796232016-11-16 17:27:36 -0800136 for (long i = 0; i < maxIndex; ++i) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800137 newDataSet.add(null);
138 }
Annie Chin36147982016-12-01 15:07:34 -0800139 final boolean isEmpty = newDataSet.isEmpty();
140 mRecyclerView.setBackgroundColor(isEmpty
141 ? ContextCompat.getColor(activity, R.color.empty_history_color)
142 : Color.TRANSPARENT);
143 if (isEmpty) {
Annie Chin06fd3cf2016-11-07 16:04:33 -0800144 newDataSet.add(new HistoryItem());
145 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800146 mDataSet = newDataSet;
147 mAdapter.setDataSet(mDataSet);
Annie Chin94c1bd92016-11-23 13:39:56 -0800148 mAdapter.setIsResultLayout(isResultLayout);
Annie Chin06fd3cf2016-11-07 16:04:33 -0800149 }
Annie Chinbc001882016-11-09 19:41:21 -0800150
151 mAdapter.notifyDataSetChanged();
Annie Chinefa259a2016-11-23 14:15:15 -0800152 }
Annie Chinbc001882016-11-09 19:41:21 -0800153
Annie Chinefa259a2016-11-23 14:15:15 -0800154 @Override
155 public void onStart() {
156 super.onStart();
157
158 // The orientation may have changed.
Annie Chin94c1bd92016-11-23 13:39:56 -0800159 mDragController.initializeAnimation(mRecyclerView,
Annie Chinb2e96182016-11-28 13:14:54 -0800160 ((Calculator) getActivity()).isResultLayout(), mDragLayout.isOpen());
Annie Chind0f87d22016-10-24 09:04:12 -0700161 }
162
163 @Override
Annie Chinabd202f2016-10-14 14:23:45 -0700164 public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
165 final View view = getView();
166 final int height = getResources().getDisplayMetrics().heightPixels;
Annie Chin91796232016-11-16 17:27:36 -0800167 if (enter) {
Annie Chin1ff328d2016-11-22 12:57:46 -0800168 if (transit == FragmentTransaction.TRANSIT_FRAGMENT_OPEN) {
169 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height, 0f);
170 } else {
171 return null;
172 }
Annie Chin91796232016-11-16 17:27:36 -0800173 } else {
174 return ObjectAnimator.ofFloat(view, View.TRANSLATION_Y, -height);
Annie Chinabd202f2016-10-14 14:23:45 -0700175 }
Annie Chinabd202f2016-10-14 14:23:45 -0700176 }
177
Annie Chind0f87d22016-10-24 09:04:12 -0700178 @Override
179 public void onDestroyView() {
180 final DragLayout dragLayout = (DragLayout) getActivity().findViewById(R.id.drag_layout);
181 if (dragLayout != null) {
Annie Chin52eed7a2017-01-04 15:06:05 -0800182 dragLayout.removeDragCallback(this);
Annie Chind0f87d22016-10-24 09:04:12 -0700183 }
Annie Chin06fd3cf2016-11-07 16:04:33 -0800184
Annie Chin9a211132016-11-30 12:52:06 -0800185 // Note that the view is destroyed when the fragment backstack is popped, so
186 // these are essentially called when the DragLayout is closed.
Hans Boehm31ea2522016-11-23 17:47:02 -0800187 mEvaluator.cancelNonMain();
Annie Chin9a211132016-11-30 12:52:06 -0800188
189 super.onDestroyView();
Annie Chind0f87d22016-10-24 09:04:12 -0700190 }
191
Annie Chin94c1bd92016-11-23 13:39:56 -0800192 private void initializeController(boolean isResult) {
Annie Chind0f87d22016-10-24 09:04:12 -0700193 mDragController.setDisplayFormula(
194 (CalculatorFormula) getActivity().findViewById(R.id.formula));
195
196 mDragController.setDisplayResult(
197 (CalculatorResult) getActivity().findViewById(R.id.result));
198
199 mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
Annie Chinbc001882016-11-09 19:41:21 -0800200
201 mDragController.setEvaluator(mEvaluator);
Annie Chin94c1bd92016-11-23 13:39:56 -0800202
203 mDragController.initializeController(isResult);
Annie Chind0f87d22016-10-24 09:04:12 -0700204 }
205
Christine Franks7485df52016-12-01 13:18:45 -0800206 public boolean stopActionModeOrContextMenu() {
Annie Chin1fcfc312016-12-06 09:36:36 -0800207 if (mRecyclerView == null) {
208 return false;
209 }
Christine Franks7485df52016-12-01 13:18:45 -0800210 for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
211 final View view = mRecyclerView.getChildAt(i);
212 final HistoryAdapter.ViewHolder viewHolder =
213 (HistoryAdapter.ViewHolder) mRecyclerView.getChildViewHolder(view);
Annie Chin532b77e2016-12-06 13:30:35 -0800214 if (viewHolder != null && viewHolder.getResult() != null
215 && viewHolder.getResult().stopActionModeOrContextMenu()) {
Christine Franks7485df52016-12-01 13:18:45 -0800216 return true;
217 }
218 }
219 return false;
220 }
Annie Chin52eed7a2017-01-04 15:06:05 -0800221
222 /* Begin override DragCallback methods. */
223
224 @Override
225 public void onStartDraggingOpen() {
226 // no-op
227 }
228
229 @Override
230 public void whileDragging(float yFraction) {
231 mDragController.animateViews(yFraction, mRecyclerView);
232 }
233
234 @Override
235 public boolean shouldCaptureView(View view, int x, int y) {
236 return view.getId() == R.id.history_frame
237 && mDragLayout.isViewUnder(view, x, y)
238 && !mRecyclerView.canScrollVertically(1 /* scrolling down */);
239 }
240
241 @Override
242 public int getDisplayHeight() {
243 return 0;
244 }
245
246 @Override
247 public void onLayout(int translation) {
248 // no-op
249 }
250
251 /* End override DragCallback methods. */
Annie Chinabd202f2016-10-14 14:23:45 -0700252}