/*
* 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.entities;
import android.app.Activity;
import android.content.Context;
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.TextUtils;
import android.view.*;
import android.widget.TextView;
import butterknife.Bind;
import butterknife.ButterKnife;
import org.solovyev.android.Check;
import org.solovyev.android.calculator.*;
import org.solovyev.android.views.DividerItemDecoration;
import org.solovyev.common.math.MathEntity;
import org.solovyev.common.text.Strings;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
public abstract class BaseEntitiesFragment<E extends MathEntity> extends BaseFragment {
public static final String ARG_CATEGORY = "category";
private static final Comparator<MathEntity> COMPARATOR = new Comparator<MathEntity>() {
@Override
public int compare(MathEntity l, MathEntity r) {
return l.getName().compareTo(r.getName());
}
};
@Bind(R.id.entities_recyclerview)
public RecyclerView recyclerView;
@Inject
Keyboard keyboard;
private EntitiesAdapter adapter;
@Nullable
private String category;
public BaseEntitiesFragment() {
super(R.layout.fragment_entities);
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle bundle = getArguments();
if (bundle != null) {
category = bundle.getString(ARG_CATEGORY);
}
}
@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 EntitiesAdapter(context, TextUtils.isEmpty(category) ? getEntities() : getEntities(category));
recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
recyclerView.setAdapter(adapter);
recyclerView.addItemDecoration(new DividerItemDecoration(context, null));
return view;
}
protected final void onClick(@Nonnull E entity) {
keyboard.buttonPressed(entity.getName());
final FragmentActivity activity = getActivity();
if (!(activity instanceof CalculatorActivity)) {
activity.finish();
}
}
@Nonnull
private List<E> getEntities(@NonNull String category) {
Check.isNotEmpty(category);
final List<E> entities = getEntities();
final Iterator<E> iterator = entities.iterator();
while (iterator.hasNext()) {
final E entity = iterator.next();
if (!isInCategory(entity, category)) {
iterator.remove();
}
}
return entities;
}
protected final boolean isInCategory(@NonNull E entity) {
return TextUtils.isEmpty(category) || isInCategory(entity, category);
}
private boolean isInCategory(@NonNull E entity, @NonNull String category) {
final Category entityCategory = getCategory(entity);
if (entityCategory == null) {
return false;
}
return TextUtils.equals(entityCategory.name(), category);
}
@Nonnull
protected abstract List<E> getEntities();
@Nullable
protected abstract Category getCategory(@Nonnull E e);
protected EntitiesAdapter getAdapter() {
return adapter;
}
@SuppressWarnings("deprecation")
protected final void copyText(@Nullable String text) {
if (!Strings.isEmpty(text)) {
return;
}
final ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(Activity.CLIPBOARD_SERVICE);
clipboard.setText(text);
}
protected void onEntityAdded(@NonNull E entity) {
final EntitiesAdapter adapter = getAdapter();
if (adapter == null) {
return;
}
if (!isInCategory(entity)) {
return;
}
adapter.add(entity);
}
protected void onEntityChanged(@NonNull E entity) {
final EntitiesAdapter adapter = getAdapter();
if (adapter == null) {
return;
}
if (!isInCategory(entity)) {
return;
}
adapter.update(entity);
}
protected void onEntityRemoved(@NonNull E entity) {
final EntitiesAdapter adapter = getAdapter();
if (adapter == null) {
return;
}
if (!isInCategory(entity)) {
return;
}
adapter.remove(entity);
}
@Nullable
protected abstract String getDescription(@NonNull E entity);
@NonNull
protected abstract String getName(@Nonnull E entity);
protected abstract void onCreateContextMenu(@Nonnull ContextMenu menu, @Nonnull E entity, @Nonnull MenuItem.OnMenuItemClickListener listener);
protected abstract boolean onMenuItemClicked(@Nonnull MenuItem item, @Nonnull E entity);
public class EntityViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnCreateContextMenuListener, MenuItem.OnMenuItemClickListener {
@Bind(R.id.entity_text)
TextView textView;
@Bind(R.id.entity_description)
TextView descriptionView;
@Nullable
private E entity;
public EntityViewHolder(@Nonnull View view) {
super(view);
BaseActivity.fixFonts(itemView, typeface);
ButterKnife.bind(this, view);
view.setOnClickListener(this);
view.setOnCreateContextMenuListener(this);
}
public void bind(@Nonnull E entity) {
this.entity = entity;
textView.setText(getName(entity));
final String description = getDescription(entity);
if (!Strings.isEmpty(description)) {
descriptionView.setVisibility(View.VISIBLE);
descriptionView.setText(description);
} else {
descriptionView.setVisibility(View.GONE);
}
}
@Override
public void onClick(View v) {
Check.isNotNull(entity);
BaseEntitiesFragment.this.onClick(entity);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Check.isNotNull(entity);
BaseEntitiesFragment.this.onCreateContextMenu(menu, entity, this);
}
@Override
public boolean onMenuItemClick(MenuItem item) {
Check.isNotNull(entity);
return BaseEntitiesFragment.this.onMenuItemClicked(item, entity);
}
}
private class EntitiesAdapter extends RecyclerView.Adapter<EntityViewHolder> {
@Nonnull
private final LayoutInflater inflater;
@Nonnull
private final List<E> list;
private EntitiesAdapter(@Nonnull Context context,
@Nonnull List<E> list) {
this.list = list;
Collections.sort(this.list, COMPARATOR);
this.inflater = LayoutInflater.from(context);
}
@Override
public EntityViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new EntityViewHolder(inflater.inflate(R.layout.fragment_entities_item, parent, false));
}
@Override
public void onBindViewHolder(EntityViewHolder holder, int position) {
holder.bind(list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
@Nonnull
public E getItem(int position) {
return list.get(position);
}
public void set(int position, @Nonnull E entity) {
list.set(position, entity);
}
public void add(@Nonnull E entity) {
final int itemCount = getItemCount();
for (int i = 0; i < itemCount; i++) {
final E adapterEntity = getItem(i);
if (COMPARATOR.compare(adapterEntity, entity) > 0) {
list.add(i, entity);
notifyItemInserted(i);
return;
}
}
list.add(itemCount, entity);
notifyItemInserted(itemCount);
}
public void remove(@Nonnull E entity) {
final int i = list.indexOf(entity);
if (i >= 0) {
list.remove(i);
notifyItemRemoved(i);
}
}
public void update(@NonNull E entity) {
if (!entity.isIdDefined()) {
return;
}
for (int i = 0; i < adapter.getItemCount(); i++) {
final E adapterEntity = adapter.getItem(i);
if (adapterEntity.isIdDefined() && entity.getId().equals(adapterEntity.getId())) {
adapter.set(i, entity);
notifyItemChanged(i);
break;
}
}
}
}
}