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.model.MobileLedgerProfile;
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 MobileLedgerProfile mProfile;
65 private int checkHoldCounter = 0;
66 NewTransactionItemsAdapter(NewTransactionModel viewModel, MobileLedgerProfile 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.getAdapterPosition();
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.getAdapterPosition();
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.getAdapterPosition(), target.getAdapterPosition());
116 public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
117 int pos = viewHolder.getAdapterPosition();
118 viewModel.removeItem(pos);
123 public int getItemViewType(int position) {
124 final ItemType type = differ.getCurrentList()
129 return ITEM_VIEW_TYPE_HEADER;
131 return ITEM_VIEW_TYPE_ACCOUNT;
133 throw new RuntimeException("Can't handle " + type);
137 public long getItemId(int position) {
138 return differ.getCurrentList()
142 public void setProfile(MobileLedgerProfile profile) {
147 public NewTransactionItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent,
150 case ITEM_VIEW_TYPE_HEADER:
151 NewTransactionHeaderRowBinding headerBinding =
152 NewTransactionHeaderRowBinding.inflate(
153 LayoutInflater.from(parent.getContext()), parent, false);
154 final NewTransactionHeaderItemHolder headerHolder =
155 new NewTransactionHeaderItemHolder(headerBinding, this);
156 Logger.debug("new-trans", "Creating new Header ViewHolder " +
157 Integer.toHexString(headerHolder.hashCode()));
159 case ITEM_VIEW_TYPE_ACCOUNT:
160 NewTransactionAccountRowBinding accBinding =
161 NewTransactionAccountRowBinding.inflate(
162 LayoutInflater.from(parent.getContext()), parent, false);
163 final NewTransactionAccountRowItemHolder accHolder =
164 new NewTransactionAccountRowItemHolder(accBinding, this);
165 Logger.debug("new-trans", "Creating new AccountRow ViewHolder " +
166 Integer.toHexString(accHolder.hashCode()));
169 throw new RuntimeException("Cant handle view type " + viewType);
173 public void onBindViewHolder(@NonNull NewTransactionItemViewHolder holder, int position) {
175 String.format(Locale.US, "Binding item at position %d, holder %s", position,
176 Integer.toHexString(holder.hashCode())));
177 NewTransactionModel.Item item = Objects.requireNonNull(differ.getCurrentList()
180 Logger.debug("bind", String.format(Locale.US, "Bound %s item at position %d", item.getType()
185 public int getItemCount() {
186 return differ.getCurrentList()
190 public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
191 super.onAttachedToRecyclerView(recyclerView);
192 touchHelper.attachToRecyclerView(recyclerView);
195 public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
196 touchHelper.attachToRecyclerView(null);
197 super.onDetachedFromRecyclerView(recyclerView);
199 void noteFocusIsOnAccount(int position) {
200 model.noteFocusChanged(position, FocusedElement.Account);
202 void noteFocusIsOnAmount(int position) {
203 model.noteFocusChanged(position, FocusedElement.Amount);
205 void noteFocusIsOnComment(int position) {
206 model.noteFocusChanged(position, FocusedElement.Comment);
208 void noteFocusIsOnTransactionComment(int position) {
209 model.noteFocusChanged(position, FocusedElement.TransactionComment);
211 public void noteFocusIsOnDescription(int pos) {
212 model.noteFocusChanged(pos, FocusedElement.Description);
214 private void holdSubmittableChecks() {
217 private void releaseSubmittableChecks() {
218 if (checkHoldCounter == 0)
219 throw new RuntimeException("Asymmetrical call to releaseSubmittableChecks");
222 void setItemCurrency(int position, String newCurrency) {
223 model.setItemCurrency(position, newCurrency);
226 public void setItems(List<NewTransactionModel.Item> newList) {
227 Logger.debug("new-trans", "adapter: submitting new item list");
228 differ.submitList(newList);
230 public NewTransactionModel.Item getItem(int position) {
231 return differ.getCurrentList()