2 * Copyright © 2021 Damyan Ivanov.
3 * This file is part of MoLe.
4 * MoLe is free software: you can distribute it and/or modify it
5 * under the term of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your opinion), any later version.
9 * MoLe is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License terms for details.
14 * You should have received a copy of the GNU General Public License
15 * along with MoLe. If not, see <https://www.gnu.org/licenses/>.
18 package net.ktnx.mobileledger.ui.new_transaction;
20 import android.view.LayoutInflater;
21 import android.view.ViewGroup;
23 import androidx.annotation.NonNull;
24 import androidx.recyclerview.widget.AsyncListDiffer;
25 import androidx.recyclerview.widget.DiffUtil;
26 import androidx.recyclerview.widget.ItemTouchHelper;
27 import androidx.recyclerview.widget.RecyclerView;
29 import net.ktnx.mobileledger.databinding.NewTransactionAccountRowBinding;
30 import net.ktnx.mobileledger.databinding.NewTransactionHeaderRowBinding;
31 import net.ktnx.mobileledger.db.Profile;
32 import net.ktnx.mobileledger.utils.Logger;
34 import java.util.List;
35 import java.util.Locale;
36 import java.util.Objects;
38 class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItemViewHolder> {
39 private static final int ITEM_VIEW_TYPE_HEADER = 1;
40 private static final int ITEM_VIEW_TYPE_ACCOUNT = 2;
41 final NewTransactionModel model;
42 private final ItemTouchHelper touchHelper;
43 private final AsyncListDiffer<NewTransactionModel.Item> differ =
44 new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<NewTransactionModel.Item>() {
46 public boolean areItemsTheSame(@NonNull NewTransactionModel.Item oldItem,
47 @NonNull NewTransactionModel.Item newItem) {
48 // Logger.debug("new-trans",
49 // String.format("comparing ids of {%s} and {%s}", oldItem.toString(),
50 // newItem.toString()));
51 return oldItem.getId() == newItem.getId();
54 public boolean areContentsTheSame(@NonNull NewTransactionModel.Item oldItem,
55 @NonNull NewTransactionModel.Item newItem) {
57 // Logger.debug("new-trans",
58 // String.format("comparing contents of {%s} and {%s}", oldItem
60 // newItem.toString()));
61 return oldItem.equalContents(newItem);
64 private Profile mProfile;
65 private int checkHoldCounter = 0;
66 NewTransactionItemsAdapter(NewTransactionModel viewModel, Profile profile) {
68 setHasStableIds(true);
73 NewTransactionItemsAdapter adapter = this;
75 touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
77 public boolean isLongPressDragEnabled() {
81 public boolean canDropOver(@NonNull RecyclerView recyclerView,
82 @NonNull RecyclerView.ViewHolder current,
83 @NonNull RecyclerView.ViewHolder target) {
84 final int adapterPosition = target.getBindingAdapterPosition();
86 // first item is immovable
87 if (adapterPosition == 0)
90 return super.canDropOver(recyclerView, current, target);
93 public int getMovementFlags(@NonNull RecyclerView recyclerView,
94 @NonNull RecyclerView.ViewHolder viewHolder) {
95 int flags = makeFlag(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.END);
96 // the top (date and description) and the bottom (padding) items are always there
97 final int adapterPosition = viewHolder.getBindingAdapterPosition();
98 if (adapterPosition > 0) {
99 flags |= makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,
100 ItemTouchHelper.UP | ItemTouchHelper.DOWN) |
101 makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE,
102 ItemTouchHelper.START | ItemTouchHelper.END);
108 public boolean onMove(@NonNull RecyclerView recyclerView,
109 @NonNull RecyclerView.ViewHolder viewHolder,
110 @NonNull RecyclerView.ViewHolder target) {
112 model.moveItem(viewHolder.getBindingAdapterPosition(),
113 target.getBindingAdapterPosition());
117 public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
118 int pos = viewHolder.getBindingAdapterPosition();
119 viewModel.removeItem(pos);
124 public int getItemViewType(int position) {
125 final ItemType type = differ.getCurrentList()
130 return ITEM_VIEW_TYPE_HEADER;
132 return ITEM_VIEW_TYPE_ACCOUNT;
134 throw new RuntimeException("Can't handle " + type);
138 public long getItemId(int position) {
139 return differ.getCurrentList()
143 public void setProfile(Profile profile) {
148 public NewTransactionItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
151 case ITEM_VIEW_TYPE_HEADER:
152 NewTransactionHeaderRowBinding headerBinding =
153 NewTransactionHeaderRowBinding.inflate(
154 LayoutInflater.from(parent.getContext()), parent, false);
155 final NewTransactionHeaderItemHolder headerHolder =
156 new NewTransactionHeaderItemHolder(headerBinding, this);
157 Logger.debug("new-trans", "Creating new Header ViewHolder " +
158 Integer.toHexString(headerHolder.hashCode()));
160 case ITEM_VIEW_TYPE_ACCOUNT:
161 NewTransactionAccountRowBinding accBinding =
162 NewTransactionAccountRowBinding.inflate(
163 LayoutInflater.from(parent.getContext()), parent, false);
164 final NewTransactionAccountRowItemHolder accHolder =
165 new NewTransactionAccountRowItemHolder(accBinding, this);
166 Logger.debug("new-trans", "Creating new AccountRow ViewHolder " +
167 Integer.toHexString(accHolder.hashCode()));
170 throw new RuntimeException("Cant handle view type " + viewType);
174 public void onBindViewHolder(@NonNull NewTransactionItemViewHolder holder, int position) {
176 String.format(Locale.US, "Binding item at position %d, holder %s", position,
177 Integer.toHexString(holder.hashCode())));
178 NewTransactionModel.Item item = Objects.requireNonNull(differ.getCurrentList()
181 Logger.debug("bind", String.format(Locale.US, "Bound %s item at position %d", item.getType()
186 public int getItemCount() {
187 return differ.getCurrentList()
191 public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
192 super.onAttachedToRecyclerView(recyclerView);
193 touchHelper.attachToRecyclerView(recyclerView);
196 public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
197 touchHelper.attachToRecyclerView(null);
198 super.onDetachedFromRecyclerView(recyclerView);
200 void noteFocusIsOnAccount(int position) {
201 model.noteFocusChanged(position, FocusedElement.Account);
203 void noteFocusIsOnAmount(int position) {
204 model.noteFocusChanged(position, FocusedElement.Amount);
206 void noteFocusIsOnComment(int position) {
207 model.noteFocusChanged(position, FocusedElement.Comment);
209 void noteFocusIsOnTransactionComment(int position) {
210 model.noteFocusChanged(position, FocusedElement.TransactionComment);
212 public void noteFocusIsOnDescription(int pos) {
213 model.noteFocusChanged(pos, FocusedElement.Description);
215 private void holdSubmittableChecks() {
218 private void releaseSubmittableChecks() {
219 if (checkHoldCounter == 0)
220 throw new RuntimeException("Asymmetrical call to releaseSubmittableChecks");
223 void setItemCurrency(int position, String newCurrency) {
224 model.setItemCurrency(position, newCurrency);
227 public void setItems(List<NewTransactionModel.Item> newList) {
228 Logger.debug("new-trans", "adapter: submitting new item list");
229 differ.submitList(newList);
231 public NewTransactionModel.Item getItem(int position) {
232 return differ.getCurrentList()