]> git.ktnx.net Git - mobile-ledger.git/blob - app/src/main/java/net/ktnx/mobileledger/ui/new_transaction/NewTransactionItemsAdapter.java
NT: keep cursor position while setting account name text
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / ui / new_transaction / NewTransactionItemsAdapter.java
1 /*
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.
8  *
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.
13  *
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/>.
16  */
17
18 package net.ktnx.mobileledger.ui.new_transaction;
19
20 import android.view.LayoutInflater;
21 import android.view.ViewGroup;
22
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;
28
29 import net.ktnx.mobileledger.databinding.NewTransactionRowBinding;
30 import net.ktnx.mobileledger.model.MobileLedgerProfile;
31 import net.ktnx.mobileledger.utils.Logger;
32
33 import java.util.List;
34 import java.util.Locale;
35 import java.util.Objects;
36
37 class NewTransactionItemsAdapter extends RecyclerView.Adapter<NewTransactionItemHolder> {
38     final NewTransactionModel model;
39     private final ItemTouchHelper touchHelper;
40     private final AsyncListDiffer<NewTransactionModel.Item> differ =
41             new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<NewTransactionModel.Item>() {
42                 @Override
43                 public boolean areItemsTheSame(@NonNull NewTransactionModel.Item oldItem,
44                                                @NonNull NewTransactionModel.Item newItem) {
45 //                    Logger.debug("new-trans",
46 //                            String.format("comparing ids of {%s} and {%s}", oldItem.toString(),
47 //                                    newItem.toString()));
48                     return oldItem.getId() == newItem.getId();
49                 }
50                 @Override
51                 public boolean areContentsTheSame(@NonNull NewTransactionModel.Item oldItem,
52                                                   @NonNull NewTransactionModel.Item newItem) {
53
54 //                    Logger.debug("new-trans",
55 //                            String.format("comparing contents of {%s} and {%s}", oldItem
56 //                            .toString(),
57 //                                    newItem.toString()));
58                     return oldItem.equalContents(newItem);
59                 }
60             });
61     private MobileLedgerProfile mProfile;
62     private int checkHoldCounter = 0;
63     NewTransactionItemsAdapter(NewTransactionModel viewModel, MobileLedgerProfile profile) {
64         super();
65         setHasStableIds(true);
66         model = viewModel;
67         mProfile = profile;
68
69
70         NewTransactionItemsAdapter adapter = this;
71
72         touchHelper = new ItemTouchHelper(new ItemTouchHelper.Callback() {
73             @Override
74             public boolean isLongPressDragEnabled() {
75                 return true;
76             }
77             @Override
78             public boolean canDropOver(@NonNull RecyclerView recyclerView,
79                                        @NonNull RecyclerView.ViewHolder current,
80                                        @NonNull RecyclerView.ViewHolder target) {
81                 final int adapterPosition = target.getAdapterPosition();
82
83                 // first item is immovable
84                 if (adapterPosition == 0)
85                     return false;
86
87                 return super.canDropOver(recyclerView, current, target);
88             }
89             @Override
90             public int getMovementFlags(@NonNull RecyclerView recyclerView,
91                                         @NonNull RecyclerView.ViewHolder viewHolder) {
92                 int flags = makeFlag(ItemTouchHelper.ACTION_STATE_IDLE, ItemTouchHelper.END);
93                 // the top (date and description) and the bottom (padding) items are always there
94                 final int adapterPosition = viewHolder.getAdapterPosition();
95                 if (adapterPosition > 0) {
96                     flags |= makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,
97                             ItemTouchHelper.UP | ItemTouchHelper.DOWN) |
98                              makeFlag(ItemTouchHelper.ACTION_STATE_SWIPE,
99                                      ItemTouchHelper.START | ItemTouchHelper.END);
100                 }
101
102                 return flags;
103             }
104             @Override
105             public boolean onMove(@NonNull RecyclerView recyclerView,
106                                   @NonNull RecyclerView.ViewHolder viewHolder,
107                                   @NonNull RecyclerView.ViewHolder target) {
108
109                 model.moveItem(viewHolder.getAdapterPosition(), target.getAdapterPosition());
110                 return true;
111             }
112             @Override
113             public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
114                 int pos = viewHolder.getAdapterPosition();
115                 viewModel.removeItem(pos);
116             }
117         });
118     }
119     @Override
120     public long getItemId(int position) {
121         return differ.getCurrentList()
122                      .get(position)
123                      .getId();
124     }
125     public void setProfile(MobileLedgerProfile profile) {
126         mProfile = profile;
127     }
128     @NonNull
129     @Override
130     public NewTransactionItemHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
131         NewTransactionRowBinding b =
132                 NewTransactionRowBinding.inflate(LayoutInflater.from(parent.getContext()), parent,
133                         false);
134
135         final NewTransactionItemHolder newHolder = new NewTransactionItemHolder(b, this);
136         Logger.debug("new-trans",
137                 "Creating new ViewHolder " + Integer.toHexString(newHolder.hashCode()));
138         return newHolder;
139     }
140     @Override
141     public void onBindViewHolder(@NonNull NewTransactionItemHolder holder, int position) {
142         Logger.debug("bind",
143                 String.format(Locale.US, "Binding item at position %d, holder %s", position,
144                         Integer.toHexString(holder.hashCode())));
145         NewTransactionModel.Item item = Objects.requireNonNull(differ.getCurrentList()
146                                                                      .get(position));
147         holder.bind(item);
148         Logger.debug("bind", String.format(Locale.US, "Bound %s item at position %d", item.getType()
149                                                                                           .toString(),
150                 position));
151     }
152     @Override
153     public int getItemCount() {
154         return differ.getCurrentList()
155                      .size();
156     }
157     @Override
158     public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
159         super.onAttachedToRecyclerView(recyclerView);
160         touchHelper.attachToRecyclerView(recyclerView);
161     }
162     @Override
163     public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {
164         touchHelper.attachToRecyclerView(null);
165         super.onDetachedFromRecyclerView(recyclerView);
166     }
167     void noteFocusIsOnAccount(int position) {
168         model.noteFocusChanged(position, FocusedElement.Account);
169     }
170     void noteFocusIsOnAmount(int position) {
171         model.noteFocusChanged(position, FocusedElement.Amount);
172     }
173     void noteFocusIsOnComment(int position) {
174         model.noteFocusChanged(position, FocusedElement.Comment);
175     }
176     void noteFocusIsOnTransactionComment(int position) {
177         model.noteFocusChanged(position, FocusedElement.TransactionComment);
178     }
179     public void noteFocusIsOnDescription(int pos) {
180         model.noteFocusChanged(pos, FocusedElement.Description);
181     }
182     private void holdSubmittableChecks() {
183         checkHoldCounter++;
184     }
185     private void releaseSubmittableChecks() {
186         if (checkHoldCounter == 0)
187             throw new RuntimeException("Asymmetrical call to releaseSubmittableChecks");
188         checkHoldCounter--;
189     }
190     void setItemCurrency(int position, String newCurrency) {
191         model.setItemCurrency(position, newCurrency);
192     }
193
194     public void setItems(List<NewTransactionModel.Item> newList) {
195         Logger.debug("new-trans", "adapter: submitting new item list");
196         differ.submitList(newList);
197     }
198 }