]> git.ktnx.net Git - mobile-ledger.git/commitdiff
more Room adoption - accounts@100%, some profiles/transactions
authorDamyan Ivanov <dam+mobileledger@ktnx.net>
Sat, 10 Apr 2021 09:35:15 +0000 (12:35 +0300)
committerDamyan Ivanov <dam+mobileledger@ktnx.net>
Sat, 10 Apr 2021 09:43:06 +0000 (12:43 +0300)
app/src/main/java/net/ktnx/mobileledger/dao/AccountDAO.java
app/src/main/java/net/ktnx/mobileledger/dao/AccountValueDAO.java
app/src/main/java/net/ktnx/mobileledger/dao/DescriptionHistoryDAO.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/dao/ProfileDAO.java
app/src/main/java/net/ktnx/mobileledger/dao/TransactionDAO.java
app/src/main/java/net/ktnx/mobileledger/db/AccountValue.java
app/src/main/java/net/ktnx/mobileledger/db/DB.java
app/src/main/java/net/ktnx/mobileledger/db/TransactionWithAccounts.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java
app/src/main/java/net/ktnx/mobileledger/ui/MainModel.java

index 3b401b669ef9e303e2b91d1aa5348acf05cdd0bf..7bca44ced51ec35f0658b08fd0730a08b4eff105 100644 (file)
@@ -23,16 +23,20 @@ import androidx.room.ColumnInfo;
 import androidx.room.Dao;
 import androidx.room.Delete;
 import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
 import androidx.room.Query;
 import androidx.room.Transaction;
 import androidx.room.Update;
 
 import net.ktnx.mobileledger.db.Account;
+import net.ktnx.mobileledger.db.AccountValue;
 import net.ktnx.mobileledger.db.AccountWithAmounts;
+import net.ktnx.mobileledger.db.DB;
 
 import java.util.ArrayList;
 import java.util.List;
 
+
 @Dao
 public abstract class AccountDAO extends BaseDAO<Account> {
     static public List<String> unbox(List<AccountNameContainer> list) {
@@ -43,9 +47,34 @@ public abstract class AccountDAO extends BaseDAO<Account> {
 
         return result;
     }
-    @Insert
+
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
     public abstract long insertSync(Account item);
 
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
+    public abstract void insertSync(List<Account> items);
+
+    @Transaction
+    public void insertSync(@NonNull AccountWithAmounts accountWithAmounts) {
+        final AccountValueDAO valueDAO = DB.get()
+                                           .getAccountValueDAO();
+        Account account = accountWithAmounts.account;
+        Account existingAccount = getByNameSync(account.getProfileId(), account.getName());
+        if (existingAccount != null) {
+            existingAccount.setGeneration(account.getGeneration());
+            account = existingAccount;
+            updateSync(account);
+        }
+        else {
+            long accountId = insertSync(account);
+            account.setId(accountId);
+        }
+        for (AccountValue value : accountWithAmounts.amounts) {
+            value.setAccountId(account.getId());
+            value.setGeneration(account.getGeneration());
+            value.setId(valueDAO.insertSync(value));
+        }
+    }
     @Update
     public abstract void updateSync(Account item);
 
@@ -72,6 +101,9 @@ public abstract class AccountDAO extends BaseDAO<Account> {
     @Query("SELECT * FROM accounts WHERE profile_id = :profileId AND name = :accountName")
     public abstract LiveData<Account> getByName(long profileId, @NonNull String accountName);
 
+    @Query("SELECT * FROM accounts WHERE profile_id = :profileId AND name = :accountName")
+    public abstract Account getByNameSync(long profileId, @NonNull String accountName);
+
     @Transaction
     @Query("SELECT * FROM accounts WHERE profile_id = :profileId AND name = :accountName")
     public abstract LiveData<AccountWithAmounts> getByNameWithAmounts(long profileId,
@@ -113,10 +145,48 @@ public abstract class AccountDAO extends BaseDAO<Account> {
     @Query("SELECT * FROM accounts WHERE profile_id = :profileId")
     public abstract List<Account> allForProfileSync(long profileId);
 
+    @Query("SELECT generation FROM accounts WHERE profile_id = :profileId LIMIT 1")
+    protected abstract AccountGenerationContainer getGenerationPOJOSync(long profileId);
+    public long getGenerationSync(long profileId) {
+        AccountGenerationContainer result = getGenerationPOJOSync(profileId);
+
+        if (result == null)
+            return 0;
+        return result.generation;
+    }
+    @Query("DELETE FROM accounts WHERE profile_id = :profileId AND generation <> " +
+           ":currentGeneration")
+    public abstract void purgeOldAccountsSync(long profileId, long currentGeneration);
+
+    @Query("DELETE FROM account_values WHERE EXISTS (SELECT 1 FROM accounts a WHERE a" +
+           ".id=account_values.account_id AND a.profile_id=:profileId) AND generation <> " +
+           ":currentGeneration")
+    public abstract void purgeOldAccountValuesSync(long profileId, long currentGeneration);
+    @Transaction
+    public void storeAccountsSync(List<AccountWithAmounts> accounts, long profileId) {
+        long generation = getGenerationSync(profileId) + 1;
+
+        for (AccountWithAmounts rec : accounts) {
+            rec.account.setGeneration(generation);
+            rec.account.setProfileId(profileId);
+            insertSync(rec);
+        }
+        purgeOldAccountsSync(profileId, generation);
+        purgeOldAccountValuesSync(profileId, generation);
+    }
+
     static public class AccountNameContainer {
         @ColumnInfo
         public String name;
         @ColumnInfo
         public int ordering;
     }
+
+    static class AccountGenerationContainer {
+        @ColumnInfo
+        long generation;
+        public AccountGenerationContainer(long generation) {
+            this.generation = generation;
+        }
+    }
 }
index 5ac559d63d616ef292c491a80f666e7a78ce2d1a..54a42c12ded9943dc5764344efbe6a1f26bec45c 100644 (file)
@@ -22,6 +22,7 @@ import androidx.lifecycle.LiveData;
 import androidx.room.Dao;
 import androidx.room.Delete;
 import androidx.room.Insert;
+import androidx.room.OnConflictStrategy;
 import androidx.room.Query;
 import androidx.room.Update;
 
@@ -31,7 +32,7 @@ import java.util.List;
 
 @Dao
 public abstract class AccountValueDAO extends BaseDAO<AccountValue> {
-    @Insert
+    @Insert(onConflict = OnConflictStrategy.REPLACE)
     public abstract long insertSync(AccountValue item);
 
     @Update
diff --git a/app/src/main/java/net/ktnx/mobileledger/dao/DescriptionHistoryDAO.java b/app/src/main/java/net/ktnx/mobileledger/dao/DescriptionHistoryDAO.java
new file mode 100644 (file)
index 0000000..26d0cf4
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright © 2021 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 <https://www.gnu.org/licenses/>.
+ */
+
+package net.ktnx.mobileledger.dao;
+
+import androidx.annotation.NonNull;
+import androidx.lifecycle.LiveData;
+import androidx.room.ColumnInfo;
+import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
+
+import net.ktnx.mobileledger.db.DescriptionHistory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Dao
+public abstract class DescriptionHistoryDAO extends BaseDAO<DescriptionHistory> {
+    static public List<String> unbox(List<DescriptionContainer> list) {
+        ArrayList<String> result = new ArrayList<>(list.size());
+        for (DescriptionContainer item : list) {
+            result.add(item.description);
+        }
+
+        return result;
+    }
+    @Insert
+    public abstract long insertSync(DescriptionHistory item);
+
+    @Update
+    public abstract void updateSync(DescriptionHistory item);
+
+    @Delete
+    public abstract void deleteSync(DescriptionHistory item);
+
+    @Delete
+    public abstract void deleteSync(List<DescriptionHistory> items);
+
+    @Query("DELETE FROM description_history where not exists (select 1 from transactions tr where" +
+           " upper(tr.description)=description_history.description_upper)")
+    public abstract void sweepSync();
+
+    @Query("SELECT * FROM description_history")
+    public abstract LiveData<List<DescriptionHistory>> getAll();
+
+    @Query("SELECT DISTINCT description, CASE WHEN description_upper LIKE :term||'%%' THEN 1 " +
+           "               WHEN description_upper LIKE '%%:'||:term||'%%' THEN 2 " +
+           "               WHEN description_upper LIKE '%% '||:term||'%%' THEN 3 " +
+           "               ELSE 9 END AS ordering " + "FROM description_history " +
+           "WHERE description_upper LIKE '%%'||:term||'%%' " +
+           "ORDER BY ordering, description_upper, rowid ")
+    public abstract List<DescriptionContainer> lookupSync(@NonNull String term);
+
+    static public class DescriptionContainer {
+        @ColumnInfo
+        public String description;
+        @ColumnInfo
+        public int ordering;
+    }
+}
index ac51ecc2bf53ec019902f733b9f12584706038e3..b4eaf93572bf1b93934526869811fa2ef82ca8d1 100644 (file)
 package net.ktnx.mobileledger.dao;
 
 import androidx.room.Dao;
+import androidx.room.Delete;
+import androidx.room.Insert;
+import androidx.room.Query;
+import androidx.room.Update;
 
 import net.ktnx.mobileledger.db.Profile;
 
 @Dao
-abstract class ProfileDAO extends BaseDAO<Profile> {
-    @Override
+public abstract class ProfileDAO extends BaseDAO<Profile> {
+    @Insert
     abstract long insertSync(Profile item);
 
-    @Override
+    @Update
     abstract void updateSync(Profile item);
 
-    @Override
-    abstract void deleteSync(Profile item);
+    @Delete
+    public abstract void deleteSync(Profile item);
+
+    @Query("select * from profiles where id = :profileId")
+    public abstract Profile getByIdSync(long profileId);
 }
index 185caa18b1873f8d7f9fb9b259f7b2da7225c2f5..485f65f10ecdce2ef5847bdc5bbefd35c22da3b2 100644 (file)
@@ -27,6 +27,7 @@ import androidx.room.Query;
 import androidx.room.Update;
 
 import net.ktnx.mobileledger.db.Transaction;
+import net.ktnx.mobileledger.db.TransactionWithAccounts;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -63,6 +64,10 @@ public abstract class TransactionDAO extends BaseDAO<Transaction> {
     @Query("SELECT * FROM transactions WHERE id = :id")
     public abstract LiveData<Transaction> getById(long id);
 
+    @androidx.room.Transaction
+    @Query("SELECT * FROM transactions WHERE id = :transactionId")
+    public abstract LiveData<TransactionWithAccounts> getByIdWithAccounts(long transactionId);
+
     @Query("SELECT DISTINCT description, CASE WHEN description_upper LIKE :term||'%%' THEN 1 " +
            "               WHEN description_upper LIKE '%%:'||:term||'%%' THEN 2 " +
            "               WHEN description_upper LIKE '%% '||:term||'%%' THEN 3 " +
index cc8075644974c9092aeeb93f74f03737309de202..2ebc3ec483b9ca214609f99fd7c472a42d98ac6e 100644 (file)
@@ -44,7 +44,7 @@ public class AccountValue {
     @ColumnInfo
     private float value;
     @ColumnInfo(defaultValue = "0")
-    private int generation = 0;
+    private long generation = 0;
     public long getId() {
         return id;
     }
@@ -70,10 +70,10 @@ public class AccountValue {
     public void setValue(float value) {
         this.value = value;
     }
-    public int getGeneration() {
+    public long getGeneration() {
         return generation;
     }
-    public void setGeneration(int generation) {
+    public void setGeneration(long generation) {
         this.generation = generation;
     }
 }
index c67e1a136f5a5edfb2b7f8594205ea817689dc7b..2e7ca655c8cf8271d5c446dba8e14b906dd2e1c0 100644 (file)
@@ -31,7 +31,9 @@ import net.ktnx.mobileledger.App;
 import net.ktnx.mobileledger.dao.AccountDAO;
 import net.ktnx.mobileledger.dao.AccountValueDAO;
 import net.ktnx.mobileledger.dao.CurrencyDAO;
+import net.ktnx.mobileledger.dao.DescriptionHistoryDAO;
 import net.ktnx.mobileledger.dao.OptionDAO;
+import net.ktnx.mobileledger.dao.ProfileDAO;
 import net.ktnx.mobileledger.dao.TemplateAccountDAO;
 import net.ktnx.mobileledger.dao.TemplateHeaderDAO;
 import net.ktnx.mobileledger.dao.TransactionDAO;
@@ -175,4 +177,8 @@ abstract public class DB extends RoomDatabase {
     public abstract TransactionDAO getTransactionDAO();
 
     public abstract OptionDAO getOptionDAO();
+
+    public abstract DescriptionHistoryDAO getDescriptionHistoryDAO();
+
+    public abstract ProfileDAO getProfileDAO();
 }
diff --git a/app/src/main/java/net/ktnx/mobileledger/db/TransactionWithAccounts.java b/app/src/main/java/net/ktnx/mobileledger/db/TransactionWithAccounts.java
new file mode 100644 (file)
index 0000000..5e91e4e
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright © 2021 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 <https://www.gnu.org/licenses/>.
+ */
+
+package net.ktnx.mobileledger.db;
+
+import androidx.room.Embedded;
+import androidx.room.Relation;
+
+import java.util.List;
+
+public class TransactionWithAccounts {
+    @Embedded
+    public Transaction transaction;
+    @Relation(parentColumn = "id", entityColumn = "transaction_id")
+    public List<TransactionAccount> accounts;
+}
index eef71a32b1a11490a513fdcf0156bb44b078edbe..0016bb374cb4c7f94bf594a1f7f19fc39c68a5e8 100644 (file)
@@ -24,7 +24,6 @@ import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.util.SparseArray;
 
 import androidx.annotation.Nullable;
@@ -34,8 +33,12 @@ import net.ktnx.mobileledger.App;
 import net.ktnx.mobileledger.R;
 import net.ktnx.mobileledger.async.DbOpQueue;
 import net.ktnx.mobileledger.dao.AccountDAO;
+import net.ktnx.mobileledger.dao.DescriptionHistoryDAO;
 import net.ktnx.mobileledger.dao.OptionDAO;
+import net.ktnx.mobileledger.dao.ProfileDAO;
 import net.ktnx.mobileledger.dao.TransactionDAO;
+import net.ktnx.mobileledger.db.AccountValue;
+import net.ktnx.mobileledger.db.AccountWithAmounts;
 import net.ktnx.mobileledger.db.DB;
 import net.ktnx.mobileledger.json.API;
 import net.ktnx.mobileledger.ui.profiles.ProfileDetailActivity;
@@ -49,7 +52,6 @@ import org.jetbrains.annotations.Contract;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
-import java.util.Locale;
 import java.util.Map;
 import java.util.Objects;
 
@@ -160,7 +162,7 @@ public final class MobileLedgerProfile {
         try {
             int orderNo = 0;
             for (MobileLedgerProfile p : Objects.requireNonNull(Data.profiles.getValue())) {
-                db.execSQL("update profiles set order_no=? where uuid=?",
+                db.execSQL("update profiles set order_no=? where id=?",
                         new Object[]{orderNo, p.getId()});
                 p.orderNo = orderNo;
                 orderNo++;
@@ -384,49 +386,6 @@ public final class MobileLedgerProfile {
                 });
 //        debug("accounts", String.format("Stored account '%s' in DB [%s]", acc.getName(), uuid));
     }
-    public void storeAccountValue(SQLiteDatabase db, int generation, String name, String currency,
-                                  Float amount) {
-        if (!TextUtils.isEmpty(currency)) {
-            boolean exists;
-            try (Cursor c = db.rawQuery("select 1 from currencies where name=?",
-                    new String[]{currency}))
-            {
-                exists = c.moveToFirst();
-            }
-            if (!exists) {
-                db.execSQL(
-                        "insert into currencies(id, name, position, has_gap) values((select max" +
-                        "(id) from currencies)+1, ?, ?, ?)", new Object[]{currency,
-                                                                          Objects.requireNonNull(
-                                                                                  Data.currencySymbolPosition.getValue()).toString(),
-                                                                          Data.currencyGap.getValue()
-                        });
-            }
-        }
-
-        long accId = findAddAccount(db, name);
-
-        db.execSQL("replace into account_values(account_id, " +
-                   "currency, value, generation) values(?, ?, ?, ?);",
-                new Object[]{accId, Misc.emptyIsNull(currency), amount, generation});
-    }
-    private long findAddAccount(SQLiteDatabase db, String accountName) {
-        try (Cursor c = db.rawQuery("select id from accounts where profile_id=? and name=?",
-                new String[]{String.valueOf(id), accountName}))
-        {
-            if (c.moveToFirst())
-                return c.getLong(0);
-
-        }
-
-        try (Cursor c = db.rawQuery(
-                "insert into accounts(profile_id, name, name_upper) values(?, ?, ?) returning id",
-                new String[]{String.valueOf(id), accountName, accountName.toUpperCase()}))
-        {
-            c.moveToFirst();
-            return c.getInt(0);
-        }
-    }
     public void storeTransaction(SQLiteDatabase db, int generation, LedgerTransaction tr) {
         tr.fillDataHash();
 //        Logger.debug("storeTransaction", String.format(Locale.US, "ID %d", tr.getId()));
@@ -520,20 +479,9 @@ public final class MobileLedgerProfile {
         setOption(name, String.valueOf(value));
     }
     public void removeFromDB() {
-        SQLiteDatabase db = App.getDatabase();
-        debug("db", String.format(Locale.ROOT, "removing profile %d from DB", id));
-        db.beginTransactionNonExclusive();
-        try {
-            Object[] id_param = new Object[]{id};
-            db.execSQL("delete from transactions where profile_id=?", id_param);
-            db.execSQL("delete from accounts where profile=?", id_param);
-            db.execSQL("delete from options where profile=?", id_param);
-            db.execSQL("delete from profiles where id=?", id_param);
-            db.setTransactionSuccessful();
-        }
-        finally {
-            db.endTransaction();
-        }
+        ProfileDAO dao = DB.get()
+                           .getProfileDAO();
+        AsyncTask.execute(() -> dao.deleteSync(dao.getByIdSync(id)));
     }
     public LedgerTransaction loadTransaction(int transactionId) {
         LedgerTransaction tr = new LedgerTransaction(transactionId, this.id);
@@ -562,24 +510,6 @@ public final class MobileLedgerProfile {
         }
         return 1;
     }
-    private int getNextAccountsGeneration(SQLiteDatabase db) {
-        try (Cursor c = db.rawQuery("SELECT generation FROM accounts WHERE profile_id=? LIMIT 1",
-                new String[]{String.valueOf(id)}))
-        {
-            if (c.moveToFirst())
-                return c.getInt(0) + 1;
-        }
-        return 1;
-    }
-    private void deleteNotPresentAccounts(SQLiteDatabase db, int generation) {
-        Logger.debug("db/benchmark", "Deleting obsolete accounts");
-        db.execSQL("DELETE FROM account_values WHERE (select a.profile_id from accounts a where a" +
-                   ".id=account_values.account_id)=? AND generation <> ?",
-                new Object[]{id, generation});
-        db.execSQL("DELETE FROM accounts WHERE profile_id=? AND generation <> ?",
-                new Object[]{id, generation});
-        Logger.debug("db/benchmark", "Done deleting obsolete accounts");
-    }
     private void deleteNotPresentTransactions(SQLiteDatabase db, int generation) {
         Logger.debug("db/benchmark", "Deleting obsolete transactions");
         db.execSQL(
@@ -603,6 +533,10 @@ public final class MobileLedgerProfile {
         TransactionDAO trnDao = DB.get()
                                   .getTransactionDAO();
         trnDao.deleteSync(trnDao.allForProfileSync(id));
+
+        DescriptionHistoryDAO descDao = DB.get()
+                                          .getDescriptionHistoryDAO();
+        descDao.sweepSync();
     }
     public void wipeAllData() {
         AsyncTask.execute(this::wipeAllDataSync);
@@ -751,26 +685,10 @@ public final class MobileLedgerProfile {
             SQLiteDatabase db = App.getDatabase();
             db.beginTransactionNonExclusive();
             try {
-                int accountsGeneration = profile.getNextAccountsGeneration(db);
-                if (isInterrupted())
-                    return;
-
                 int transactionsGeneration = profile.getNextTransactionsGeneration(db);
                 if (isInterrupted())
                     return;
 
-                for (LedgerAccount acc : accounts) {
-                    profile.storeAccount(db, accountsGeneration, acc, false);
-                    if (isInterrupted())
-                        return;
-                    for (LedgerAmount amt : acc.getAmounts()) {
-                        profile.storeAccountValue(db, accountsGeneration, acc.getName(),
-                                amt.getCurrency(), amt.getAmount());
-                        if (isInterrupted())
-                            return;
-                    }
-                }
-
                 for (LedgerTransaction tr : transactions) {
                     profile.storeTransaction(db, transactionsGeneration, tr);
                     if (isInterrupted())
@@ -781,9 +699,6 @@ public final class MobileLedgerProfile {
                 if (isInterrupted()) {
                     return;
                 }
-                profile.deleteNotPresentAccounts(db, accountsGeneration);
-                if (isInterrupted())
-                    return;
 
                 Map<String, Boolean> unique = new HashMap<>();
 
@@ -810,6 +725,37 @@ public final class MobileLedgerProfile {
             finally {
                 db.endTransaction();
             }
+
+            AsyncTask.execute(() -> {
+                List<AccountWithAmounts> list = new ArrayList<>();
+
+                final AccountDAO dao = DB.get()
+                                         .getAccountDAO();
+
+                for (LedgerAccount acc : accounts) {
+                    AccountWithAmounts rec = new AccountWithAmounts();
+                    rec.account = acc.toDBO();
+
+                    if (isInterrupted())
+                        return;
+
+                    rec.amounts = new ArrayList<>();
+                    for (LedgerAmount amt : acc.getAmounts()) {
+                        AccountValue av = new AccountValue();
+                        av.setCurrency(amt.getCurrency());
+                        av.setValue(amt.getAmount());
+
+                        rec.amounts.add(av);
+                    }
+
+                    list.add(rec);
+                }
+
+                if (isInterrupted())
+                    return;
+
+                dao.storeAccountsSync(list, profile.getId());
+            });
         }
         private void storeDescription(SQLiteDatabase db, int generation, String description,
                                       String descriptionUpper) {
index aec736c48cca1a93dd7997e8b73160a4c5fe1837..eb7a064160556a4479375acdc82ab2ba55fae7c5 100644 (file)
 package net.ktnx.mobileledger.ui;
 
 import android.os.AsyncTask;
-import android.os.Build;
 import android.text.TextUtils;
 
-import androidx.annotation.Nullable;
 import androidx.lifecycle.LiveData;
 import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.ViewModel;
@@ -35,7 +33,6 @@ import net.ktnx.mobileledger.model.LedgerAccount;
 import net.ktnx.mobileledger.model.LedgerTransaction;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
 import net.ktnx.mobileledger.model.TransactionListItem;
-import net.ktnx.mobileledger.utils.LockHolder;
 import net.ktnx.mobileledger.utils.Locker;
 import net.ktnx.mobileledger.utils.Logger;
 import net.ktnx.mobileledger.utils.MLDB;
@@ -43,11 +40,8 @@ import net.ktnx.mobileledger.utils.SimpleDate;
 
 import java.util.ArrayList;
 import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Locale;
-import java.util.Map;
 
 import static net.ktnx.mobileledger.utils.Logger.debug;
 
@@ -61,65 +55,13 @@ public class MainModel extends ViewModel {
             new MutableLiveData<>();
     private final Locker accountsLocker = new Locker();
     private final MutableLiveData<String> updateError = new MutableLiveData<>();
-    private final Map<String, LedgerAccount> accountMap = new HashMap<>();
     private MobileLedgerProfile profile;
-    private List<LedgerAccount> allAccounts = new ArrayList<>();
+    private final List<LedgerAccount> allAccounts = new ArrayList<>();
     private SimpleDate firstTransactionDate;
     private SimpleDate lastTransactionDate;
     transient private RetrieveTransactionsTask retrieveTransactionsTask;
     transient private Thread displayedAccountsUpdater;
     private TransactionsDisplayedFilter displayedTransactionsUpdater;
-    public static ArrayList<LedgerAccount> mergeAccountListsFromWeb(List<LedgerAccount> oldList,
-                                                                    List<LedgerAccount> newList) {
-        LedgerAccount oldAcc, newAcc;
-        ArrayList<LedgerAccount> merged = new ArrayList<>();
-
-        Iterator<LedgerAccount> oldIterator = oldList.iterator();
-        Iterator<LedgerAccount> newIterator = newList.iterator();
-
-        while (true) {
-            if (!oldIterator.hasNext()) {
-                // the rest of the incoming are new
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
-                    newIterator.forEachRemaining(merged::add);
-                }
-                else {
-                    while (newIterator.hasNext())
-                        merged.add(newIterator.next());
-                }
-                break;
-            }
-            oldAcc = oldIterator.next();
-
-            if (!newIterator.hasNext()) {
-                // no more incoming accounts. ignore the rest of the old
-                break;
-            }
-            newAcc = newIterator.next();
-
-            // ignore now missing old items
-            if (oldAcc.getName()
-                      .compareTo(newAcc.getName()) < 0)
-                continue;
-
-            // add newly found items
-            if (oldAcc.getName()
-                      .compareTo(newAcc.getName()) > 0)
-            {
-                merged.add(newAcc);
-                continue;
-            }
-
-            // two items with same account names; forward-merge UI-controlled fields
-            // it is important that the result list contains a new LedgerAccount instance
-            // so that the change is propagated to the UI
-            newAcc.setExpanded(oldAcc.isExpanded());
-            newAcc.setAmountsExpanded(oldAcc.amountsExpanded());
-            merged.add(newAcc);
-        }
-
-        return merged;
-    }
     private void setLastUpdateStamp(long transactionCount) {
         debug("db", "Updating transaction value stamp");
         Date now = new Date();
@@ -200,13 +142,6 @@ public class MainModel extends ViewModel {
         accountsLocker.lockForWriting();
         return accountsLocker;
     }
-    public void mergeAccountListFromWeb(List<LedgerAccount> newList) {
-
-        try (LockHolder l = accountsLocker.lockForWriting()) {
-            allAccounts = mergeAccountListsFromWeb(allAccounts, newList);
-            updateAccountsMap(allAccounts);
-        }
-    }
     public LiveData<List<AccountListItem>> getDisplayedAccounts() {
         return displayedAccounts;
     }
@@ -216,18 +151,8 @@ public class MainModel extends ViewModel {
 
         setLastUpdateStamp(transactions.size());
 
-        mergeAccountListFromWeb(accounts);
-        updateDisplayedAccounts();
-
         updateDisplayedTransactionsFromWeb(transactions);
     }
-    synchronized public void updateDisplayedAccounts() {
-        if (displayedAccountsUpdater != null) {
-            displayedAccountsUpdater.interrupt();
-        }
-        displayedAccountsUpdater = new AccountListDisplayedFilter(this, allAccounts);
-        displayedAccountsUpdater.start();
-    }
     synchronized public void updateDisplayedTransactionsFromWeb(List<LedgerTransaction> list) {
         if (displayedTransactionsUpdater != null) {
             displayedTransactionsUpdater.interrupt();
@@ -235,19 +160,6 @@ public class MainModel extends ViewModel {
         displayedTransactionsUpdater = new TransactionsDisplayedFilter(this, list);
         displayedTransactionsUpdater.start();
     }
-    public List<LedgerAccount> getAllAccounts() {
-        return allAccounts;
-    }
-    private void updateAccountsMap(List<LedgerAccount> newAccounts) {
-        accountMap.clear();
-        for (LedgerAccount acc : newAccounts) {
-            accountMap.put(acc.getName(), acc);
-        }
-    }
-    @Nullable
-    public LedgerAccount locateAccount(String name) {
-        return accountMap.get(name);
-    }
     public void clearUpdateError() {
         updateError.postValue(null);
     }
@@ -255,38 +167,6 @@ public class MainModel extends ViewModel {
     public void clearTransactions() {
         displayedTransactions.setValue(new ArrayList<>());
     }
-    static class AccountListDisplayedFilter extends Thread {
-        private final MainModel model;
-        private final List<LedgerAccount> list;
-        AccountListDisplayedFilter(MainModel model, List<LedgerAccount> list) {
-            this.model = model;
-            this.list = list;
-        }
-        @Override
-        public void run() {
-            List<AccountListItem> newDisplayed = new ArrayList<>();
-            Logger.debug("dFilter", "waiting for synchronized block");
-            Logger.debug("dFilter", String.format(Locale.US,
-                    "entered synchronized block (about to examine %d accounts)", list.size()));
-            newDisplayed.add(new AccountListItem.Header(Data.lastAccountsUpdateText));    // header
-
-            int count = 0;
-            for (LedgerAccount a : list) {
-                if (isInterrupted())
-                    return;
-
-                if (a.isVisible()) {
-                    newDisplayed.add(new AccountListItem.Account(a));
-                    count++;
-                }
-            }
-            if (!isInterrupted()) {
-                model.displayedAccounts.postValue(newDisplayed);
-                Data.lastUpdateAccountCount.postValue(count);
-            }
-            Logger.debug("dFilter", "left synchronized block");
-        }
-    }
 
     static class TransactionsDisplayedFilter extends Thread {
         private final MainModel model;