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.transaction_list;
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.RecyclerView;
28 import net.ktnx.mobileledger.databinding.LastUpdateLayoutBinding;
29 import net.ktnx.mobileledger.databinding.TransactionDelimiterBinding;
30 import net.ktnx.mobileledger.databinding.TransactionListRowBinding;
31 import net.ktnx.mobileledger.model.LedgerTransaction;
32 import net.ktnx.mobileledger.model.TransactionListItem;
33 import net.ktnx.mobileledger.utils.Logger;
34 import net.ktnx.mobileledger.utils.Misc;
36 import java.util.List;
37 import java.util.Locale;
39 public class TransactionListAdapter extends RecyclerView.Adapter<TransactionRowHolderBase> {
40 private final AsyncListDiffer<TransactionListItem> listDiffer;
41 public TransactionListAdapter() {
44 setHasStableIds(true);
46 listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback<TransactionListItem>() {
48 public boolean areItemsTheSame(@NonNull TransactionListItem oldItem,
49 @NonNull TransactionListItem newItem) {
50 if (oldItem.getType() != newItem.getType())
52 switch (oldItem.getType()) {
54 return (oldItem.getDate()
55 .equals(newItem.getDate()));
57 return oldItem.getTransaction()
58 .getLedgerId() == newItem.getTransaction()
61 return true; // there can be only one header
63 throw new IllegalStateException(
64 String.format(Locale.US, "Unexpected transaction item type %s",
69 public boolean areContentsTheSame(@NonNull TransactionListItem oldItem,
70 @NonNull TransactionListItem newItem) {
71 switch (oldItem.getType()) {
73 return oldItem.isMonthShown() == newItem.isMonthShown();
75 return oldItem.getTransaction()
76 .equals(newItem.getTransaction()) &&
77 Misc.equalStrings(oldItem.getBoldAccountName(),
78 newItem.getBoldAccountName());
80 // headers don't differ in their contents. they observe the last update
81 // date and react to its changes
84 throw new IllegalStateException(
85 String.format(Locale.US, "Unexpected transaction item type %s",
93 public long getItemId(int position) {
94 TransactionListItem item = listDiffer.getCurrentList()
96 switch (item.getType()) {
100 return item.getTransaction()
103 return -item.getDate()
107 throw new IllegalStateException("Unexpected value: " + item.getType());
111 public int getItemViewType(int position) {
112 return listDiffer.getCurrentList()
117 public void onBindViewHolder(@NonNull TransactionRowHolderBase holder, int position) {
118 TransactionListItem item = listDiffer.getCurrentList()
121 // in a race when transaction value is reduced, but the model hasn't been notified yet
122 // the view will disappear when the notifications reaches the model, so by simply omitting
123 // the out-of-range get() call nothing bad happens - just a to-be-deleted view remains
128 final TransactionListItem.Type newType = item.getType();
132 LedgerTransaction tr = item.getTransaction();
133 holder.asTransaction()
134 .bind(tr, item.getBoldAccountName());
147 throw new IllegalStateException("Unexpected value: " + newType);
152 public TransactionRowHolderBase onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
153 // debug("perf", "onCreateViewHolder called");
154 final LayoutInflater inflater = LayoutInflater.from(parent.getContext());
156 switch (TransactionListItem.Type.valueOf(viewType)) {
158 return new TransactionRowHolder(
159 TransactionListRowBinding.inflate(inflater, parent, false));
161 return new TransactionListDelimiterRowHolder(
162 TransactionDelimiterBinding.inflate(inflater, parent, false));
164 return new TransactionListLastUpdateRowHolder(
165 LastUpdateLayoutBinding.inflate(inflater, parent, false));
167 throw new IllegalStateException("Unexpected value: " + viewType);
172 public int getItemCount() {
173 return listDiffer.getCurrentList()
176 public void setTransactions(List<TransactionListItem> newList) {
177 Logger.debug("transactions",
178 String.format(Locale.US, "Got new transaction list (%d items)", newList.size()));
179 listDiffer.submitList(newList);