From: Damyan Ivanov Date: Thu, 16 Jul 2020 08:38:43 +0000 (+0000) Subject: more asynchronous account list (re-)loading X-Git-Tag: v0.15.0~89 X-Git-Url: https://git.ktnx.net/?a=commitdiff_plain;h=d08ab8235d0fd152c772b2dd5ffa1ca5747f67b1;p=mobile-ledger.git more asynchronous account list (re-)loading it was loaded from DB in a background thread already, but recycler view now updates are also managed in a background thread --- diff --git a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java index db8f8de7..86d4cc45 100644 --- a/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java +++ b/app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java @@ -206,7 +206,7 @@ public class RetrieveTransactionsTask // state of the database db.setTransactionSuccessful(); db.endTransaction(); - Data.accounts.setList(accountList); + profile.setAccounts(accountList); db.beginTransaction(); continue; } @@ -527,16 +527,13 @@ public class RetrieveTransactionsTask profile.deleteNotPresentAccounts(db); throwIfCancelled(); db.setTransactionSuccessful(); - listFilledOK = true; } finally { db.endTransaction(); } } - // should not be set in the DB transaction, because of a possible deadlock - // with the main and DbOpQueueRunner threads - if (listFilledOK) - Data.accounts.setList(accountList); + + profile.setAccounts(accountList); return true; } diff --git a/app/src/main/java/net/ktnx/mobileledger/async/UpdateAccountsTask.java b/app/src/main/java/net/ktnx/mobileledger/async/UpdateAccountsTask.java deleted file mode 100644 index 8beab181..00000000 --- a/app/src/main/java/net/ktnx/mobileledger/async/UpdateAccountsTask.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright © 2019 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 . - */ - -package net.ktnx.mobileledger.async; - -import android.database.Cursor; -import android.database.sqlite.SQLiteDatabase; -import android.os.AsyncTask; - -import net.ktnx.mobileledger.App; -import net.ktnx.mobileledger.model.Data; -import net.ktnx.mobileledger.model.LedgerAccount; -import net.ktnx.mobileledger.model.MobileLedgerProfile; - -import java.util.ArrayList; - -import static net.ktnx.mobileledger.utils.Logger.debug; - -public class UpdateAccountsTask extends AsyncTask> { - protected ArrayList doInBackground(Void... params) { - Data.backgroundTaskStarted(); - try { - MobileLedgerProfile profile = Data.profile.getValue(); - if (profile == null) throw new AssertionError(); - String profileUUID = profile.getUuid(); - ArrayList newList = new ArrayList<>(); - - String sql = "SELECT a.name from accounts a WHERE a.profile = ?"; - sql += " ORDER BY a.name"; - - SQLiteDatabase db = App.getDatabase(); - try (Cursor cursor = db.rawQuery(sql, new String[]{profileUUID})) { - while (cursor.moveToNext()) { - final String accName = cursor.getString(0); -// debug("accounts", -// String.format("Read account '%s' from DB [%s]", accName, profileUUID)); - LedgerAccount acc = profile.loadAccount(db, accName); - if (acc.isVisible(newList)) newList.add(acc); - } - } - - return newList; - } - finally { - debug("UAT", "decrementing background task count"); - Data.backgroundTaskFinished(); - } - } -} diff --git a/app/src/main/java/net/ktnx/mobileledger/model/Data.java b/app/src/main/java/net/ktnx/mobileledger/model/Data.java index 5764434f..a6d3fd98 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/Data.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/Data.java @@ -50,8 +50,6 @@ public final class Data { new MutableLiveData<>(null); public static final MutableLiveData latestTransactionDate = new MutableLiveData<>(null); - public static final ObservableList accounts = - new ObservableList<>(new ArrayList<>()); public static final MutableLiveData backgroundTasksRunning = new MutableLiveData<>(false); public static final MutableLiveData lastUpdateDate = new MutableLiveData<>(); diff --git a/app/src/main/java/net/ktnx/mobileledger/model/LedgerAccount.java b/app/src/main/java/net/ktnx/mobileledger/model/LedgerAccount.java index 3bc01d1f..11c1a16b 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/LedgerAccount.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/LedgerAccount.java @@ -66,13 +66,7 @@ public class LedgerAccount { name.equals(((LedgerAccount) obj).getName()); } // an account is visible if: - // - it is starred (not hidden by a star) - // - and it has an expanded parent or is a top account - public boolean isVisible() { - if (level == 0) return true; - - return isVisible(Data.accounts); - } + // - it has an expanded parent or is a top account public boolean isVisible(List list) { for (LedgerAccount acc : list) { if (acc.isParentOf(this)) { diff --git a/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java b/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java index 21acf677..fc940e9a 100644 --- a/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java +++ b/app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java @@ -24,11 +24,14 @@ import android.util.SparseArray; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; import net.ktnx.mobileledger.App; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.async.DbOpQueue; import net.ktnx.mobileledger.async.SendTransactionTask; +import net.ktnx.mobileledger.utils.Logger; import net.ktnx.mobileledger.utils.MLDB; import net.ktnx.mobileledger.utils.Misc; @@ -61,6 +64,9 @@ public final class MobileLedgerProfile { private SendTransactionTask.API apiVersion = SendTransactionTask.API.auto; private Calendar firstTransactionDate; private Calendar lastTransactionDate; + private MutableLiveData> accounts = + new MutableLiveData<>(new ArrayList<>()); + private AccountListLoader loader = null; public MobileLedgerProfile() { this.uuid = String.valueOf(UUID.randomUUID()); } @@ -141,6 +147,26 @@ public final class MobileLedgerProfile { db.endTransaction(); } } + public LiveData> getAccounts() { + return accounts; + } + synchronized public void scheduleAccountListReload() { + Logger.debug("async-acc", "scheduleAccountListReload() enter"); + if ((loader != null) && loader.isAlive()) { + Logger.debug("async-acc", "returning early - loader already active"); + return; + } + + Logger.debug("async-acc", "Starting AccountListLoader"); + loader = new AccountListLoader(this); + loader.start(); + } + synchronized public void abortAccountListReload() { + if (loader == null) + return; + loader.interrupt(); + loader = null; + } public boolean getShowCommentsByDefault() { return showCommentsByDefault; } @@ -402,7 +428,7 @@ public final class MobileLedgerProfile { } @Nullable public LedgerAccount tryLoadAccount(SQLiteDatabase db, String accName) { - try (Cursor cursor = db.rawQuery("SELECT a.expanded, (select 1 from accounts a2 " + + try (Cursor cursor = db.rawQuery("SELECT a.expanded, a.amounts_expanded, (select 1 from accounts a2 " + "where a2.profile = a.profile and a2.name like a" + ".name||':%' limit 1) " + "FROM accounts a WHERE a.profile = ? and a.name=?", @@ -411,7 +437,8 @@ public final class MobileLedgerProfile { if (cursor.moveToFirst()) { LedgerAccount acc = new LedgerAccount(this, accName); acc.setExpanded(cursor.getInt(0) == 1); - acc.setHasSubAccounts(cursor.getInt(1) == 1); + acc.setAmountsExpanded(cursor.getInt(1) == 1); + acc.setHasSubAccounts(cursor.getInt(2) == 1); try (Cursor c2 = db.rawQuery( "SELECT value, currency FROM account_values WHERE profile = ? " + @@ -573,6 +600,9 @@ public final class MobileLedgerProfile { public Calendar getLastTransactionDate() { return lastTransactionDate; } + public void setAccounts(ArrayList list) { + accounts.postValue(list); + } public enum FutureDates { None(0), OneWeek(7), TwoWeeks(14), OneMonth(30), TwoMonths(60), ThreeMonths(90), SixMonths(180), OneYear(365), All(-1); @@ -617,4 +647,42 @@ public final class MobileLedgerProfile { } } } + + static class AccountListLoader extends Thread { + MobileLedgerProfile profile; + AccountListLoader(MobileLedgerProfile profile) { + this.profile = profile; + } + @Override + public void run() { + Logger.debug("async-acc", "AccountListLoader::run() entered"); + String profileUUID = profile.getUuid(); + ArrayList newList = new ArrayList<>(); + + String sql = "SELECT a.name from accounts a WHERE a.profile = ?"; + sql += " ORDER BY a.name"; + + SQLiteDatabase db = App.getDatabase(); + try (Cursor cursor = db.rawQuery(sql, new String[]{profileUUID})) { + while (cursor.moveToNext()) { + if (isInterrupted()) + return; + + final String accName = cursor.getString(0); +// debug("accounts", +// String.format("Read account '%s' from DB [%s]", accName, +// profileUUID)); + LedgerAccount acc = profile.loadAccount(db, accName); + if (acc.isVisible(newList)) + newList.add(acc); + } + } + + if (isInterrupted()) + return; + + Logger.debug("async-acc", "AccountListLoader::run() posting new list"); + profile.accounts.postValue(newList); + } + } } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java index 0540438d..ee46b9c7 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java @@ -19,6 +19,7 @@ package net.ktnx.mobileledger.ui.account_summary; import android.content.Context; import android.content.res.Resources; +import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; @@ -29,48 +30,45 @@ import android.widget.TextView; import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.constraintlayout.widget.ConstraintLayout; +import androidx.recyclerview.widget.AsyncListDiffer; +import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; import net.ktnx.mobileledger.R; -import net.ktnx.mobileledger.model.Data; +import net.ktnx.mobileledger.async.DbOpQueue; import net.ktnx.mobileledger.model.LedgerAccount; +import net.ktnx.mobileledger.model.MobileLedgerProfile; import net.ktnx.mobileledger.ui.activity.MainActivity; -import net.ktnx.mobileledger.utils.LockHolder; + +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; + +import static net.ktnx.mobileledger.utils.Logger.debug; public class AccountSummaryAdapter extends RecyclerView.Adapter { public static final int AMOUNT_LIMIT = 3; - - AccountSummaryAdapter() { } + private MobileLedgerProfile profile; + private AsyncListDiffer listDiffer; + AccountSummaryAdapter() { + listDiffer = new AsyncListDiffer<>(this, new DiffUtil.ItemCallback() { + @Override + public boolean areItemsTheSame(@NotNull LedgerAccount oldItem, + @NotNull LedgerAccount newItem) { + return TextUtils.equals(oldItem.getName(), newItem.getName()); + } + @Override + public boolean areContentsTheSame(@NotNull LedgerAccount oldItem, + @NotNull LedgerAccount newItem) { + return (oldItem.isExpanded() == newItem.isExpanded()) && + (oldItem.amountsExpanded() == newItem.amountsExpanded()); + } + }); + } public void onBindViewHolder(@NonNull LedgerRowHolder holder, int position) { - try (LockHolder lh = Data.accounts.lockForReading()) { - LedgerAccount acc = Data.accounts.get(position); - Context ctx = holder.row.getContext(); - Resources rm = ctx.getResources(); - - holder.row.setTag(acc); - holder.row.setVisibility(View.VISIBLE); - holder.tvAccountName.setText(acc.getShortName()); - ConstraintLayout.LayoutParams lp = - (ConstraintLayout.LayoutParams) holder.tvAccountName.getLayoutParams(); - lp.setMarginStart( - acc.getLevel() * rm.getDimensionPixelSize(R.dimen.thumb_row_height) / 3); - holder.expanderContainer.setVisibility( - acc.hasSubAccounts() ? View.VISIBLE : View.GONE); - holder.expanderContainer.setRotation(acc.isExpanded() ? 0 : 180); - int amounts = acc.getAmountCount(); - if ((amounts > AMOUNT_LIMIT) && !acc.amountsExpanded()) { - holder.tvAccountAmounts.setText(acc.getAmountsString(AMOUNT_LIMIT)); - holder.accountExpanderContainer.setVisibility(View.VISIBLE); - } - else { - holder.tvAccountAmounts.setText(acc.getAmountsString()); - holder.accountExpanderContainer.setVisibility(View.GONE); - } - - holder.row.setTag(R.id.POS, position); - } + holder.bindToAccount(listDiffer.getCurrentList().get(position)); } @NonNull @@ -83,9 +81,13 @@ public class AccountSummaryAdapter @Override public int getItemCount() { - return Data.accounts.size(); + return listDiffer.getCurrentList().size(); + } + public void setAccounts(MobileLedgerProfile profile, ArrayList newList) { + this.profile = profile; + listDiffer.submitList(newList); } - static class LedgerRowHolder extends RecyclerView.ViewHolder { + class LedgerRowHolder extends RecyclerView.ViewHolder { TextView tvAccountName, tvAccountAmounts; ConstraintLayout row; View expanderContainer; @@ -93,12 +95,12 @@ public class AccountSummaryAdapter View accountExpanderContainer; public LedgerRowHolder(@NonNull View itemView) { super(itemView); - this.row = itemView.findViewById(R.id.account_summary_row); - this.tvAccountName = itemView.findViewById(R.id.account_row_acc_name); - this.tvAccountAmounts = itemView.findViewById(R.id.account_row_acc_amounts); - this.expanderContainer = itemView.findViewById(R.id.account_expander_container); - this.expander = itemView.findViewById(R.id.account_expander); - this.accountExpanderContainer = + row = itemView.findViewById(R.id.account_summary_row); + tvAccountName = itemView.findViewById(R.id.account_row_acc_name); + tvAccountAmounts = itemView.findViewById(R.id.account_row_acc_amounts); + expanderContainer = itemView.findViewById(R.id.account_expander_container); + expander = itemView.findViewById(R.id.account_expander); + accountExpanderContainer = itemView.findViewById(R.id.account_row_amounts_expander_container); itemView.setOnLongClickListener(this::onItemLongClick); @@ -107,6 +109,63 @@ public class AccountSummaryAdapter expanderContainer.setOnLongClickListener(this::onItemLongClick); expander.setOnLongClickListener(this::onItemLongClick); row.setOnLongClickListener(this::onItemLongClick); + + tvAccountName.setOnClickListener(v -> toggleAccountExpanded()); + expanderContainer.setOnClickListener(v -> toggleAccountExpanded()); + expander.setOnClickListener(v -> toggleAccountExpanded()); + tvAccountAmounts.setOnClickListener(v -> toggleAmountsExpanded()); + } + private @NonNull + LedgerAccount getAccount() { + final ArrayList accountList = profile.getAccounts() + .getValue(); + if (accountList == null) + throw new IllegalStateException("No account list"); + + return accountList.get(getAdapterPosition()); + } + private void toggleAccountExpanded() { + LedgerAccount acc = getAccount(); + if (!acc.hasSubAccounts()) + return; + debug("accounts", "Account expander clicked"); + + acc.toggleExpanded(); + expanderContainer.animate() + .rotation(acc.isExpanded() ? 0 : 180); + + MobileLedgerProfile profile = acc.getProfile(); + if (profile == null) + return; + + DbOpQueue.add("update accounts set expanded=? where name=? and profile=?", + new Object[]{acc.isExpanded(), acc.getName(), profile.getUuid() + }, profile::scheduleAccountListReload); + + } + private void toggleAmountsExpanded() { + LedgerAccount acc = getAccount(); + if (acc.getAmountCount() <= AMOUNT_LIMIT) + return; + + acc.toggleAmountsExpanded(); + if (acc.amountsExpanded()) { + tvAccountAmounts.setText(acc.getAmountsString()); + accountExpanderContainer.setVisibility(View.GONE); + } + else { + tvAccountAmounts.setText(acc.getAmountsString(AMOUNT_LIMIT)); + accountExpanderContainer.setVisibility(View.VISIBLE); + } + + MobileLedgerProfile profile = acc.getProfile(); + if (profile == null) + return; + + DbOpQueue.add("update accounts set amounts_expanded=? where name=? and profile=?", + new Object[]{acc.amountsExpanded(), acc.getName(), profile.getUuid() + }); + } private boolean onItemLongClick(View v) { MainActivity activity = (MainActivity) v.getContext(); @@ -136,13 +195,13 @@ public class AccountSummaryAdapter String.format("Don't know how to handle long click on id %d", id)); return false; } - LedgerAccount acc = (LedgerAccount) row.getTag(); + LedgerAccount acc = getAccount(); builder.setTitle(acc.getName()); builder.setItems(R.array.acc_ctx_menu, (dialog, which) -> { switch (which) { case 0: // show transactions - activity.showAccountTransactions(acc); + activity.showAccountTransactions(acc.getName()); break; } dialog.dismiss(); @@ -150,5 +209,36 @@ public class AccountSummaryAdapter builder.show(); return true; } + public void bindToAccount(LedgerAccount acc) { + Context ctx = row.getContext(); + Resources rm = ctx.getResources(); + + row.setTag(acc); + + tvAccountName.setText(acc.getShortName()); + + ConstraintLayout.LayoutParams lp = + (ConstraintLayout.LayoutParams) tvAccountName.getLayoutParams(); + lp.setMarginStart( + acc.getLevel() * rm.getDimensionPixelSize(R.dimen.thumb_row_height) / 3); + + if (acc.hasSubAccounts()) { + expanderContainer.setVisibility(View.VISIBLE); + expanderContainer.setRotation(acc.isExpanded() ? 0 : 180); + } + else { + expanderContainer.setVisibility(View.GONE); + } + + int amounts = acc.getAmountCount(); + if ((amounts > AMOUNT_LIMIT) && !acc.amountsExpanded()) { + tvAccountAmounts.setText(acc.getAmountsString(AMOUNT_LIMIT)); + accountExpanderContainer.setVisibility(View.VISIBLE); + } + else { + tvAccountAmounts.setText(acc.getAmountsString()); + accountExpanderContainer.setVisibility(View.GONE); + } + } } } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java index 79253bfb..9f2344fb 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java @@ -31,12 +31,17 @@ import androidx.recyclerview.widget.RecyclerView; import net.ktnx.mobileledger.R; import net.ktnx.mobileledger.model.Data; +import net.ktnx.mobileledger.model.LedgerAccount; +import net.ktnx.mobileledger.model.MobileLedgerProfile; import net.ktnx.mobileledger.ui.MobileLedgerListFragment; import net.ktnx.mobileledger.ui.activity.MainActivity; import net.ktnx.mobileledger.utils.Colors; +import net.ktnx.mobileledger.utils.Logger; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; + import static net.ktnx.mobileledger.utils.Logger.debug; public class AccountSummaryFragment extends MobileLedgerListFragment { @@ -90,7 +95,15 @@ public class AccountSummaryFragment extends MobileLedgerListFragment { Data.scheduleTransactionListRetrieval(mainActivity); }); - Data.accounts.addObserver( - (o, arg) -> mainActivity.runOnUiThread(() -> modelAdapter.notifyDataSetChanged())); + Data.profile.observe(getViewLifecycleOwner(), profile -> profile.getAccounts() + .observe( + getViewLifecycleOwner(), + (accounts) -> onAccountsChanged( + profile, + accounts))); + } + private void onAccountsChanged(MobileLedgerProfile profile, ArrayList accounts) { + Logger.debug("async-acc", "fragment: got new account list"); + modelAdapter.setAccounts(profile, accounts); } } diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryViewModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryViewModel.java deleted file mode 100644 index d7f4c616..00000000 --- a/app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryViewModel.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright © 2019 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 . - */ - -package net.ktnx.mobileledger.ui.account_summary; - -import android.os.AsyncTask; - -import androidx.lifecycle.ViewModel; - -import net.ktnx.mobileledger.async.UpdateAccountsTask; -import net.ktnx.mobileledger.model.Data; -import net.ktnx.mobileledger.model.LedgerAccount; - -import java.util.ArrayList; - -import static net.ktnx.mobileledger.utils.Logger.debug; - -public class AccountSummaryViewModel extends ViewModel { - static public void scheduleAccountListReload() { - if (Data.profile.getValue() == null) return; - - UAT task = new UAT(); - task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); - - } - - private static class UAT extends UpdateAccountsTask { - @Override - protected void onPostExecute(ArrayList list) { - super.onPostExecute(list); - if (list != null) { - debug("acc", "setting updated account list"); - Data.accounts.setList(list); - } - } - } - -} - diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java index 8d9adfbe..3a210ef0 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java @@ -31,7 +31,6 @@ import android.os.Bundle; import android.util.Log; import android.view.View; import android.view.ViewGroup; -import android.view.ViewPropertyAnimator; import android.view.animation.AnimationUtils; import android.widget.LinearLayout; import android.widget.ProgressBar; @@ -53,22 +52,18 @@ import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.snackbar.Snackbar; import net.ktnx.mobileledger.R; -import net.ktnx.mobileledger.async.DbOpQueue; import net.ktnx.mobileledger.async.RefreshDescriptionsTask; import net.ktnx.mobileledger.async.RetrieveTransactionsTask; import net.ktnx.mobileledger.model.Data; import net.ktnx.mobileledger.model.LedgerAccount; import net.ktnx.mobileledger.model.MobileLedgerProfile; -import net.ktnx.mobileledger.ui.account_summary.AccountSummaryAdapter; import net.ktnx.mobileledger.ui.account_summary.AccountSummaryFragment; -import net.ktnx.mobileledger.ui.account_summary.AccountSummaryViewModel; import net.ktnx.mobileledger.ui.profiles.ProfileDetailFragment; import net.ktnx.mobileledger.ui.profiles.ProfilesRecyclerViewAdapter; import net.ktnx.mobileledger.ui.transaction_list.TransactionListFragment; import net.ktnx.mobileledger.ui.transaction_list.TransactionListViewModel; import net.ktnx.mobileledger.utils.Colors; import net.ktnx.mobileledger.utils.GetOptCallback; -import net.ktnx.mobileledger.utils.LockHolder; import net.ktnx.mobileledger.utils.Logger; import net.ktnx.mobileledger.utils.MLDB; @@ -399,6 +394,10 @@ public class MainActivity extends ProfileThemedActivity { else setTitle(R.string.app_name); + if (this.profile != null) + this.profile.getAccounts() + .removeObservers(this); + this.profile = profile; int newProfileTheme = haveProfile ? profile.getThemeHue() : -1; @@ -422,10 +421,9 @@ public class MainActivity extends ProfileThemedActivity { debug("transactions", "requesting list reload"); TransactionListViewModel.scheduleTransactionListReload(); - Data.accounts.clear(); - AccountSummaryViewModel.scheduleAccountListReload(); - if (haveProfile) { + profile.scheduleAccountListReload(); + if (profile.isPostingPermitted()) { mToolbar.setSubtitle(null); fab.show(); @@ -529,16 +527,13 @@ public class MainActivity extends ProfileThemedActivity { showTransactionsFragment((String) null); } - private void showTransactionsFragment(String accName) { + public void showTransactionsFragment(String accName) { Data.accountFilter.setValue(accName); mViewPager.setCurrentItem(1, true); } - private void showTransactionsFragment(LedgerAccount account) { - showTransactionsFragment((account == null) ? null : account.getName()); - } - public void showAccountTransactions(LedgerAccount account) { + public void showAccountTransactions(String accountName) { mBackMeansToAccountList = true; - showTransactionsFragment(account); + showTransactionsFragment(accountName); } @Override public void onBackPressed() { @@ -658,87 +653,8 @@ public class MainActivity extends ProfileThemedActivity { case R.id.account_row_acc_name: case R.id.account_expander: case R.id.account_expander_container: - debug("accounts", "Account expander clicked"); - if (!acc.hasSubAccounts()) - return; - - boolean wasExpanded = acc.isExpanded(); - - View arrow = row.findViewById(R.id.account_expander_container); - - arrow.clearAnimation(); - ViewPropertyAnimator animator = arrow.animate(); - - acc.toggleExpanded(); - DbOpQueue.add("update accounts set expanded=? where name=? and profile=?", - new Object[]{acc.isExpanded(), acc.getName(), profile.getUuid() - }); - - if (wasExpanded) { - debug("accounts", String.format("Collapsing account '%s'", acc.getName())); - arrow.setRotation(0); - animator.rotationBy(180); - - // removing all child accounts from the view - int start = -1, count = 0; - try (LockHolder ignored = Data.accounts.lockForWriting()) { - for (int i = 0; i < Data.accounts.size(); i++) { - if (acc.isParentOf(Data.accounts.get(i))) { -// debug("accounts", String.format("Found a child '%s' at position -// %d", -// Data.accounts.get(i).getName(), i)); - if (start == -1) { - start = i; - } - count++; - } - else { - if (start != -1) { -// debug("accounts", -// String.format("Found a non-child '%s' at position %d", -// Data.accounts.get(i).getName(), i)); - break; - } - } - } - - if (start != -1) { - for (int j = 0; j < count; j++) { -// debug("accounts", String.format("Removing item %d: %s", start + j, -// Data.accounts.get(start).getName())); - Data.accounts.removeQuietly(start); - } - - mAccountSummaryFragment.modelAdapter.notifyItemRangeRemoved(start, - count); - } - } - } - else { - debug("accounts", String.format("Expanding account '%s'", acc.getName())); - arrow.setRotation(180); - animator.rotationBy(-180); - List children = profile.loadVisibleChildAccountsOf(acc); - try (LockHolder ignored = Data.accounts.lockForWriting()) { - int parentPos = Data.accounts.indexOf(acc); - if (parentPos != -1) { - // may have disappeared in a concurrent refresh operation - Data.accounts.addAllQuietly(parentPos + 1, children); - mAccountSummaryFragment.modelAdapter.notifyItemRangeInserted( - parentPos + 1, children.size()); - } - } - } break; case R.id.account_row_acc_amounts: - if (acc.getAmountCount() > AccountSummaryAdapter.AMOUNT_LIMIT) { - acc.toggleAmountsExpanded(); - DbOpQueue.add( - "update accounts set amounts_expanded=? where name=? and profile=?", - new Object[]{acc.amountsExpanded(), acc.getName(), profile.getUuid() - }); - Data.accounts.triggerItemChangedNotification(acc); - } break; } } diff --git a/app/src/main/res/values/ids.xml b/app/src/main/res/values/ids.xml index a314e7ac..09840bec 100644 --- a/app/src/main/res/values/ids.xml +++ b/app/src/main/res/values/ids.xml @@ -18,6 +18,5 @@ - \ No newline at end of file