blob: eb2a325cc07058309e34cdcb2da87082f3fb6ab5 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.calculator2;
import android.animation.Animator;
import android.app.Fragment;
import android.os.Bundle;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toolbar;
import java.util.ArrayList;
import static androidx.recyclerview.widget.RecyclerView.SCROLL_STATE_DRAGGING;
public class HistoryFragment extends Fragment implements DragLayout.DragCallback {
public static final String TAG = "HistoryFragment";
public static final String CLEAR_DIALOG_TAG = "clear";
private final DragController mDragController = new DragController();
private RecyclerView mRecyclerView;
private HistoryAdapter mAdapter;
private DragLayout mDragLayout;
private Evaluator mEvaluator;
private ArrayList<HistoryItem> mDataSet = new ArrayList<>();
private boolean mIsDisplayEmpty;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAdapter = new HistoryAdapter(mDataSet);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View view = inflater.inflate(
R.layout.fragment_history, container, false /* attachToRoot */);
mDragLayout = (DragLayout) container.getRootView().findViewById(R.id.drag_layout);
mDragLayout.addDragCallback(this);
mRecyclerView = (RecyclerView) view.findViewById(R.id.history_recycler_view);
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (newState == SCROLL_STATE_DRAGGING) {
stopActionModeOrContextMenu();
}
super.onScrollStateChanged(recyclerView, newState);
}
});
// The size of the RecyclerView is not affected by the adapter's contents.
mRecyclerView.setHasFixedSize(true);
mRecyclerView.setAdapter(mAdapter);
final Toolbar toolbar = (Toolbar) view.findViewById(R.id.history_toolbar);
toolbar.inflateMenu(R.menu.fragment_history);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
if (item.getItemId() == R.id.menu_clear_history) {
final Calculator calculator = (Calculator) getActivity();
AlertDialogFragment.showMessageDialog(calculator, "" /* title */,
getString(R.string.dialog_clear),
getString(R.string.menu_clear_history),
CLEAR_DIALOG_TAG);
return true;
}
return onOptionsItemSelected(item);
}
});
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getActivity().onBackPressed();
}
});
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final Calculator activity = (Calculator) getActivity();
mEvaluator = Evaluator.getInstance(activity);
mAdapter.setEvaluator(mEvaluator);
final boolean isResultLayout = activity.isResultLayout();
final boolean isOneLine = activity.isOneLine();
// Snapshot display state here. For the rest of the lifecycle of this current
// HistoryFragment, this is what we will consider the display state.
// In rare cases, the display state can change after our adapter is initialized.
final CalculatorExpr mainExpr = mEvaluator.getExpr(Evaluator.MAIN_INDEX);
mIsDisplayEmpty = mainExpr == null || mainExpr.isEmpty();
initializeController(isResultLayout, isOneLine, mIsDisplayEmpty);
final long maxIndex = mEvaluator.getMaxIndex();
final ArrayList<HistoryItem> newDataSet = new ArrayList<>();
if (!mIsDisplayEmpty && !isResultLayout) {
// Add the current expression as the first element in the list (the layout is
// reversed and we want the current expression to be the last one in the
// RecyclerView).
// If we are in the result state, the result will animate to the last history
// element in the list and there will be no "Current Expression."
mEvaluator.copyMainToHistory();
newDataSet.add(new HistoryItem(Evaluator.HISTORY_MAIN_INDEX,
System.currentTimeMillis(), mEvaluator.getExprAsSpannable(0)));
}
for (long i = 0; i < maxIndex; ++i) {
newDataSet.add(null);
}
final boolean isEmpty = newDataSet.isEmpty();
mRecyclerView.setBackgroundColor(ContextCompat.getColor(activity,
isEmpty ? R.color.empty_history_color : R.color.display_background_color));
if (isEmpty) {
newDataSet.add(new HistoryItem());
}
mDataSet = newDataSet;
mAdapter.setDataSet(mDataSet);
mAdapter.setIsResultLayout(isResultLayout);
mAdapter.setIsOneLine(activity.isOneLine());
mAdapter.setIsDisplayEmpty(mIsDisplayEmpty);
mAdapter.notifyDataSetChanged();
}
@Override
public void onStart() {
super.onStart();
final Calculator activity = (Calculator) getActivity();
mDragController.initializeAnimation(activity.isResultLayout(), activity.isOneLine(),
mIsDisplayEmpty);
}
@Override
public Animator onCreateAnimator(int transit, boolean enter, int nextAnim) {
return mDragLayout.createAnimator(enter);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mDragLayout != null) {
mDragLayout.removeDragCallback(this);
}
if (mEvaluator != null) {
// Note that the view is destroyed when the fragment backstack is popped, so
// these are essentially called when the DragLayout is closed.
mEvaluator.cancelNonMain();
}
}
private void initializeController(boolean isResult, boolean isOneLine, boolean isDisplayEmpty) {
mDragController.setDisplayFormula(
(CalculatorFormula) getActivity().findViewById(R.id.formula));
mDragController.setDisplayResult(
(CalculatorResult) getActivity().findViewById(R.id.result));
mDragController.setToolbar(getActivity().findViewById(R.id.toolbar));
mDragController.setEvaluator(mEvaluator);
mDragController.initializeController(isResult, isOneLine, isDisplayEmpty);
}
public boolean stopActionModeOrContextMenu() {
if (mRecyclerView == null) {
return false;
}
for (int i = 0; i < mRecyclerView.getChildCount(); i++) {
final View view = mRecyclerView.getChildAt(i);
final HistoryAdapter.ViewHolder viewHolder =
(HistoryAdapter.ViewHolder) mRecyclerView.getChildViewHolder(view);
if (viewHolder != null && viewHolder.getResult() != null
&& viewHolder.getResult().stopActionModeOrContextMenu()) {
return true;
}
}
return false;
}
/* Begin override DragCallback methods. */
@Override
public void onStartDraggingOpen() {
// no-op
}
@Override
public void onInstanceStateRestored(boolean isOpen) {
if (isOpen) {
mRecyclerView.setVisibility(View.VISIBLE);
}
}
@Override
public void whileDragging(float yFraction) {
if (isVisible() || isRemoving()) {
mDragController.animateViews(yFraction, mRecyclerView);
}
}
@Override
public boolean shouldCaptureView(View view, int x, int y) {
return !mRecyclerView.canScrollVertically(1 /* scrolling down */);
}
@Override
public int getDisplayHeight() {
return 0;
}
/* End override DragCallback methods. */
}