package net.ktnx.mobileledger.ui.templates;
+import android.view.View;
+
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.RecyclerView;
import net.ktnx.mobileledger.R;
import net.ktnx.mobileledger.databinding.TemplateListTemplateItemBinding;
+import net.ktnx.mobileledger.databinding.TemplatesFallbackDividerBinding;
import net.ktnx.mobileledger.db.TemplateHeader;
-class TemplateViewHolder extends RecyclerView.ViewHolder {
- final TemplateListTemplateItemBinding b;
- public TemplateViewHolder(@NonNull TemplateListTemplateItemBinding binding) {
- super(binding.getRoot());
- b = binding;
+abstract class BaseTemplateViewHolder extends RecyclerView.ViewHolder {
+ public BaseTemplateViewHolder(@NonNull View itemView) {
+ super(itemView);
+ }
+ abstract void bindToItem(TemplatesRecyclerViewAdapter.BaseTemplateItem item);
+ static class TemplateDividerViewHolder extends BaseTemplateViewHolder {
+ public TemplateDividerViewHolder(@NonNull TemplatesFallbackDividerBinding binding) {
+ super(binding.getRoot());
+ }
+ @Override
+ void bindToItem(TemplatesRecyclerViewAdapter.BaseTemplateItem item) {
+ // nothing
+ }
}
- public void bindToItem(TemplateHeader item) {
- b.templateName.setText(item.getName());
- b.templateName.setOnClickListener(
- v -> ((TemplatesActivity) v.getContext()).onEditTemplate(item.getId()));
- b.templateName.setOnLongClickListener((v) -> {
- TemplatesActivity activity = (TemplatesActivity) v.getContext();
- AlertDialog.Builder builder = new AlertDialog.Builder(activity);
- final String templateName = item.getName();
- builder.setTitle(templateName);
- builder.setItems(R.array.templates_ctx_menu, (dialog, which) -> {
- if (which == 0) { // edit
- activity.onEditTemplate(item.getId());
- }
- else if (which == 1) { // duplicate
- activity.onDuplicateTemplate(item.getId());
- }
- else if (which == 2) { // delete
- activity.onDeleteTemplate(item.getId());
- }
- else {
- throw new RuntimeException(String.format("Unknown menu item id (%d)", which));
- }
- dialog.dismiss();
+
+ static class TemplateViewHolder extends BaseTemplateViewHolder {
+ final TemplateListTemplateItemBinding b;
+ public TemplateViewHolder(@NonNull TemplateListTemplateItemBinding binding) {
+ super(binding.getRoot());
+ b = binding;
+ }
+ @Override
+ public void bindToItem(TemplatesRecyclerViewAdapter.BaseTemplateItem baseItem) {
+ TemplateHeader item = ((TemplatesRecyclerViewAdapter.TemplateItem) baseItem).template;
+ b.templateName.setText(item.getName());
+ b.templateName.setOnClickListener(
+ v -> ((TemplatesActivity) v.getContext()).onEditTemplate(item.getId()));
+ b.templateName.setOnLongClickListener((v) -> {
+ TemplatesActivity activity = (TemplatesActivity) v.getContext();
+ AlertDialog.Builder builder = new AlertDialog.Builder(activity);
+ final String templateName = item.getName();
+ builder.setTitle(templateName);
+ builder.setItems(R.array.templates_ctx_menu, (dialog, which) -> {
+ if (which == 0) { // edit
+ activity.onEditTemplate(item.getId());
+ }
+ else if (which == 1) { // duplicate
+ activity.onDuplicateTemplate(item.getId());
+ }
+ else if (which == 2) { // delete
+ activity.onDeleteTemplate(item.getId());
+ }
+ else {
+ throw new RuntimeException(
+ String.format("Unknown menu item id (%d)", which));
+ }
+ dialog.dismiss();
+ });
+ builder.show();
+ return true;
});
- builder.show();
- return true;
- });
+ }
}
-}
+}
\ No newline at end of file
import androidx.recyclerview.widget.RecyclerView;
import net.ktnx.mobileledger.databinding.TemplateListTemplateItemBinding;
+import net.ktnx.mobileledger.databinding.TemplatesFallbackDividerBinding;
import net.ktnx.mobileledger.db.TemplateHeader;
import org.jetbrains.annotations.NotNull;
+import java.util.ArrayList;
import java.util.List;
-public class TemplatesRecyclerViewAdapter extends RecyclerView.Adapter<TemplateViewHolder> {
- private final AsyncListDiffer<TemplateHeader> listDiffer;
+public class TemplatesRecyclerViewAdapter extends RecyclerView.Adapter<BaseTemplateViewHolder> {
+ private static final int ITEM_TYPE_TEMPLATE = 1;
+ private static final int ITEM_TYPE_DIVIDER = 2;
+ private final AsyncListDiffer<BaseTemplateItem> listDiffer;
+
public TemplatesRecyclerViewAdapter() {
- listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<TemplateHeader>() {
+ listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<BaseTemplateItem>() {
@Override
- public boolean areItemsTheSame(@NotNull TemplateHeader oldItem,
- @NotNull TemplateHeader newItem) {
- return oldItem.getId()
- .equals(newItem.getId());
+ public boolean areItemsTheSame(
+ @NotNull TemplatesRecyclerViewAdapter.BaseTemplateItem oldItem,
+ @NotNull TemplatesRecyclerViewAdapter.BaseTemplateItem newItem) {
+ return oldItem.getId() == newItem.getId();
}
@Override
- public boolean areContentsTheSame(@NotNull TemplateHeader oldItem,
- @NotNull TemplateHeader newItem) {
+ public boolean areContentsTheSame(
+ @NotNull TemplatesRecyclerViewAdapter.BaseTemplateItem oldItem,
+ @NotNull TemplatesRecyclerViewAdapter.BaseTemplateItem newItem) {
return oldItem.equals(newItem);
}
});
}
@NonNull
@Override
- public TemplateViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- TemplateListTemplateItemBinding b =
- TemplateListTemplateItemBinding.inflate(LayoutInflater.from(parent.getContext()),
- parent, false);
-
- return new TemplateViewHolder(b);
+ public BaseTemplateViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+ switch (viewType) {
+ case ITEM_TYPE_TEMPLATE:
+ TemplateListTemplateItemBinding b =
+ TemplateListTemplateItemBinding.inflate(inflater, parent, false);
+ return new BaseTemplateViewHolder.TemplateViewHolder(b);
+ case ITEM_TYPE_DIVIDER:
+ return new BaseTemplateViewHolder.TemplateDividerViewHolder(
+ TemplatesFallbackDividerBinding.inflate(inflater, parent, false));
+ default:
+ throw new RuntimeException("Can't handle " + viewType);
+ }
}
@Override
- public void onBindViewHolder(@NonNull TemplateViewHolder holder, int position) {
+ public void onBindViewHolder(@NonNull BaseTemplateViewHolder holder, int position) {
holder.bindToItem(listDiffer.getCurrentList()
.get(position));
}
@Override
+ public int getItemViewType(int position) {
+ BaseTemplateItem item = getItem(position);
+ if (item instanceof TemplateItem)
+ return ITEM_TYPE_TEMPLATE;
+ if (item instanceof TemplateDivider)
+ return ITEM_TYPE_DIVIDER;
+
+ throw new RuntimeException("Can't handle " + item);
+ }
+ @Override
public int getItemCount() {
return listDiffer.getCurrentList()
.size();
}
public void setTemplates(List<TemplateHeader> newList) {
- listDiffer.submitList(newList);
+ List<BaseTemplateItem> itemList = new ArrayList<>();
+
+ boolean reachedFallbackItems = false;
+
+ for (TemplateHeader item : newList) {
+ if (!reachedFallbackItems && item.isFallback()) {
+ itemList.add(new TemplateDivider());
+ reachedFallbackItems = true;
+ }
+ itemList.add(new TemplateItem(item));
+ }
+
+ listDiffer.submitList(itemList);
+ }
+ public BaseTemplateItem getItem(int position) {
+ return listDiffer.getCurrentList()
+ .get(position);
+ }
+
+ static abstract class BaseTemplateItem {
+ abstract long getId();
+
+ abstract boolean equals(BaseTemplateItem other);
+ }
+
+ static class TemplateItem extends BaseTemplateItem {
+ final TemplateHeader template;
+ TemplateItem(TemplateHeader template) {this.template = template;}
+ @Override
+ long getId() {
+ return template.getId();
+ }
+ @Override
+ boolean equals(BaseTemplateItem other) {
+ return template.equals(((TemplateItem) other).template);
+ }
+ }
+
+ static class TemplateDivider extends BaseTemplateItem {
+ @Override
+ long getId() {
+ return -1;
+ }
+ @Override
+ boolean equals(BaseTemplateItem other) {
+ return true;
+ }
}
}
android:id="@+id/template_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/text_margin"
+ android:layout_marginHorizontal="@dimen/text_margin"
android:gravity="center_vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright © 2021 Damyan Ivanov.
+ ~ This file is part of MoLe.
+ ~ MoLe is free software: you can distribute it and/or modify it
+ ~ under the term of the GNU General Public License as published by
+ ~ the Free Software Foundation, either version 3 of the License, or
+ ~ (at your opinion), any later version.
+ ~
+ ~ MoLe is distributed in the hope that it will be useful,
+ ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ ~ GNU General Public License terms for details.
+ ~
+ ~ You should have received a copy of the GNU General Public License
+ ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
+ -->
+
+<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ <TextView
+ android:id="@+id/top_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text=" "
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toTopOf="parent"
+ />
+ <TextView
+ android:id="@+id/label"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/text_margin"
+ android:gravity="end"
+ android:text="@string/fallback_templates_divider"
+ android:textStyle="italic"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/divider"
+ />
+ <View
+ android:id="@+id/divider"
+ android:layout_width="0dp"
+ android:layout_height="1dp"
+ android:layout_marginHorizontal="@dimen/text_margin"
+ android:background="?colorPrimary"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/top_text"
+ />
+</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<string name="template_is_fallback_label">Резервен макет</string>
<string name="template_is_fallback_yes">Макетът ще се предлага за избор само ако няма друг макет, който да пасва и да не е маркиран като резервен</string>
<string name="template_is_fallback_no">Макетът не е резервен</string>
+ <string name="fallback_templates_divider">Резервни макети</string>
</resources>
<string name="template_is_fallback_label">Fallback template</string>
<string name="template_is_fallback_yes">Template will be offered for selection only when no templates match that aren\'t marked as fallback templates</string>
<string name="template_is_fallback_no">Template is a primary, high priority one, not a catch-all</string>
+ <string name="fallback_templates_divider">Fallback templates</string>
</resources>