/* * 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; } } } } }