/*
* Copyright 2013 serso aka se.solovyev
*
* 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.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Contact details
*
* Email: se.solovyev@gmail.com
* Site: http://se.solovyev.org
*/
package org.solovyev.android.calculator.history;
import android.app.Activity;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.text.ClipboardManager;
import android.text.format.DateUtils;
import android.view.*;
import android.widget.TextView;
import butterknife.Bind;
import butterknife.ButterKnife;
import com.squareup.otto.Bus;
import com.squareup.otto.Subscribe;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.*;
import org.solovyev.android.calculator.jscl.JsclOperation;
import org.solovyev.android.views.DividerItemDecoration;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.List;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
public abstract class BaseHistoryFragment extends BaseFragment {
private final boolean recentHistory;
@Inject
History history;
@Inject
Editor editor;
@Inject
Bus bus;
@Inject
Typeface typeface;
@Bind(R.id.history_recyclerview)
RecyclerView recyclerView;
private HistoryAdapter adapter;
protected BaseHistoryFragment(boolean recentHistory) {
super(R.layout.fragment_history);
this.recentHistory = recentHistory;
}
@Override
protected void inject(@Nonnull AppComponent component) {
super.inject(component);
component.inject(this);
}
@Nonnull
public static String getHistoryText(@Nonnull HistoryState state) {
return state.editor.getTextString() + getIdentitySign(state.display.getOperation()) + state.display.text;
}
@Nonnull
private static String getIdentitySign(@Nonnull JsclOperation operation) {
return operation == JsclOperation.simplify ? "≡" : "=";
}
public void useState(@Nonnull final HistoryState state) {
editor.setState(state.editor);
final FragmentActivity activity = getActivity();
if (!(activity instanceof CalculatorActivity)) {
activity.finish();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = super.onCreateView(inflater, container, savedInstanceState);
ButterKnife.bind(this, view);
final Context context = inflater.getContext();
adapter = new HistoryAdapter(context);
bus.register(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(context, null));
return view;
}
@SuppressWarnings("deprecation")
protected final void copyResult(@Nonnull HistoryState state) {
final Context context = getActivity();
final String displayText = state.display.text;
if (Strings.isEmpty(displayText)) {
return;
}
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(displayText);
}
@Override
public void onDestroyView() {
bus.unregister(adapter);
super.onDestroyView();
}
@SuppressWarnings("deprecation")
protected final void copyExpression(@Nonnull HistoryState state) {
final Context context = getActivity();
final String editorText = state.editor.getTextString();
if (Strings.isEmpty(editorText)) {
return;
}
final ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(editorText);
}
protected final boolean shouldHaveCopyResult(@Nonnull HistoryState state) {
return !state.display.valid || !Strings.isEmpty(state.display.text);
}
public class HistoryViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener, MenuItem.OnMenuItemClickListener {
private static final int DATETIME_FORMAT = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_ABBREV_TIME;
@Bind(R.id.history_item_value)
TextView valueView;
@Bind(R.id.history_item_comment)
TextView commentView;
@Bind(R.id.history_item_time)
TextView timeView;
@Nullable
private HistoryState state;
public HistoryViewHolder(View view) {
super(view);
BaseActivity.fixFonts(view, typeface);
ButterKnife.bind(this, view);
view.setOnCreateContextMenuListener(this);
view.setOnClickListener(this);
}
void bind(@Nonnull HistoryState state) {
this.state = state;
valueView.setText(BaseHistoryFragment.getHistoryText(state));
timeView.setText(DateUtils.formatDateTime(getContext(), state.getTime(), DATETIME_FORMAT));
final String comment = state.getComment();
if (!Strings.isEmpty(comment)) {
commentView.setText(comment);
commentView.setVisibility(VISIBLE);
} else {
commentView.setText(null);
commentView.setVisibility(GONE);
}
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Check.isNotNull(state);
if (recentHistory) {
addMenu(menu, R.string.c_use, this);
addMenu(menu, R.string.c_copy_expression, this);
if (shouldHaveCopyResult(state)) {
addMenu(menu, R.string.c_copy_result, this);
}
addMenu(menu, R.string.c_save, this);
} else {
addMenu(menu, R.string.c_use, this);
addMenu(menu, R.string.c_copy_expression, this);
if (shouldHaveCopyResult(state)) {
addMenu(menu, R.string.c_copy_result, this);
}
addMenu(menu, R.string.cpp_edit, this);
addMenu(menu, R.string.cpp_delete, this);
}
}
@Override
public void onClick(View v) {
Check.isNotNull(state);
useState(state);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
Check.isNotNull(state);
switch (item.getItemId()) {
case R.string.c_use:
useState(state);
return true;
case R.string.c_copy_expression:
copyExpression(state);
return true;
case R.string.c_copy_result:
copyResult(state);
return true;
case R.string.cpp_edit:
EditHistoryFragment.show(state, false, getFragmentManager());
return true;
case R.string.c_save:
EditHistoryFragment.show(state, true, getFragmentManager());
return true;
case R.string.cpp_delete:
history.removeSaved(state);
return true;
}
return false;
}
}
public class HistoryAdapter extends RecyclerView.Adapter<HistoryViewHolder> {
@NonNull
private final LayoutInflater inflater;
@NonNull
private final List<HistoryState> list;
public HistoryAdapter(@NonNull Context context) {
inflater = LayoutInflater.from(context);
list = loadHistory();
setHasStableIds(true);
}
@NonNull
private List<HistoryState> loadHistory() {
return recentHistory ? history.getRecent() : history.getSaved();
}
@Override
public HistoryViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new HistoryViewHolder(inflater.inflate(R.layout.fragment_history_item, parent, false));
}
@Override
public void onBindViewHolder(HistoryViewHolder holder, int position) {
holder.bind(list.get(position));
}
@Override
public long getItemId(int position) {
return list.get(position).hashCode();
}
@Override
public int getItemCount() {
return list.size();
}
@Subscribe
public void onHistoryCleared(@Nonnull History.ClearedEvent e) {
if (e.recent != recentHistory) {
return;
}
list.clear();
notifyDataSetChanged();
}
@Subscribe
public void onHistoryAdded(@Nonnull History.AddedEvent e) {
if (e.recent != recentHistory) {
return;
}
list.add(e.state);
notifyItemInserted(0);
}
@Subscribe
public void onHistoryUpdated(@Nonnull History.UpdatedEvent e) {
if (e.recent != recentHistory) {
return;
}
final int i = list.indexOf(e.state);
if (i >= 0) {
list.set(i, e.state);
notifyItemChanged(i);
}
}
@Subscribe
public void onHistoryRemoved(@Nonnull History.RemovedEvent e) {
if (e.recent != recentHistory) {
return;
}
final int i = list.indexOf(e.state);
if (i >= 0) {
list.remove(i);
notifyItemRemoved(i);
}
}
}
}