]> git.ktnx.net Git - mobile-ledger.git/blobdiff - app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsViewModel.java
Default template name given at save time
[mobile-ledger.git] / app / src / main / java / net / ktnx / mobileledger / ui / templates / TemplateDetailsViewModel.java
index 6090d12138cd94a85f0b4fe0e5320466da9474aa..8d0e29e64792eee5548e1072883e3b26dbe7cae1 100644 (file)
@@ -24,6 +24,7 @@ import androidx.lifecycle.MutableLiveData;
 import androidx.lifecycle.Observer;
 import androidx.lifecycle.ViewModel;
 
+import net.ktnx.mobileledger.BuildConfig;
 import net.ktnx.mobileledger.dao.TemplateAccountDAO;
 import net.ktnx.mobileledger.dao.TemplateHeaderDAO;
 import net.ktnx.mobileledger.db.DB;
@@ -32,59 +33,120 @@ import net.ktnx.mobileledger.db.TemplateHeader;
 import net.ktnx.mobileledger.db.TemplateWithAccounts;
 import net.ktnx.mobileledger.model.TemplateDetailsItem;
 import net.ktnx.mobileledger.utils.Logger;
+import net.ktnx.mobileledger.utils.Misc;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.concurrent.atomic.AtomicInteger;
 
 public class TemplateDetailsViewModel extends ViewModel {
     private final MutableLiveData<List<TemplateDetailsItem>> items =
             new MutableLiveData<>(Collections.emptyList());
+    private final AtomicInteger syntheticItemId = new AtomicInteger(0);
     private Long mPatternId;
-    private String mDefaultPatternName;
+    private String mDefaultTemplateName;
     private boolean itemsLoaded = false;
-
-    public String getDefaultPatternName() {
-        return mDefaultPatternName;
+    public String getDefaultTemplateName() {
+        return mDefaultTemplateName;
     }
-    public void setDefaultPatternName(String name) {
-        mDefaultPatternName = name;
+    public void setDefaultTemplateName(String name) {
+        mDefaultTemplateName = name;
     }
 
     public void resetItems() {
-        ArrayList<TemplateDetailsItem> newList = new ArrayList<>();
-        final TemplateDetailsItem.Header header = TemplateDetailsItem.createHeader();
-        header.setName(mDefaultPatternName);
-        header.setId(0);
-        newList.add(header);
+        applyList(new ArrayList<>());
+    }
+    public void applyList(List<TemplateDetailsItem> srcList) {
+        applyList(srcList, false);
+    }
+    public void applyList(List<TemplateDetailsItem> srcList, boolean async) {
+        boolean changes;
+        if (srcList == null) {
+            srcList = new ArrayList<>(items.getValue());
+            changes = false;
+        }
+        else
+            changes = true;
 
-        while (newList.size() < 3) {
-            final TemplateDetailsItem.AccountRow aRow = TemplateDetailsItem.createAccountRow();
-            aRow.setId(newList.size() + 1);
-            newList.add(aRow);
+        srcList = Collections.unmodifiableList(srcList);
+
+        {
+            Logger.debug("tmpl", "Considering old list");
+            for (TemplateDetailsItem item : srcList)
+                Logger.debug("tmpl", String.format(Locale.US, " id %d pos %d", item.getId(),
+                        item.getPosition()));
         }
 
-        items.setValue(newList);
-    }
-    private void checkItemConsistency() {
-        ArrayList<TemplateDetailsItem> newList = new ArrayList<>(items.getValue());
-        boolean changes = false;
-        if (newList.size() < 1) {
+        ArrayList<TemplateDetailsItem> newList = new ArrayList<>();
+
+        boolean hasEmptyItem = false;
+
+        if (srcList.size() < 1) {
             final TemplateDetailsItem.Header header = TemplateDetailsItem.createHeader();
-            header.setName(mDefaultPatternName);
+            header.setId(0);
             newList.add(header);
             changes = true;
         }
+        else {
+            newList.add(srcList.get(0));
+        }
+
+        for (int i = 1; i < srcList.size(); i++) {
+            final TemplateDetailsItem.AccountRow accRow = srcList.get(i)
+                                                                 .asAccountRowItem();
+            if (accRow.isEmpty()) {
+                // it is normal to have two empty rows if they are at the
+                // top (position 1 and 2)
+                if (!hasEmptyItem || i < 3) {
+                    accRow.setPosition(newList.size());
+                    newList.add(accRow);
+                }
+                else
+                    changes = true; // row skipped
+
+                hasEmptyItem = true;
+            }
+            else {
+                accRow.setPosition(newList.size());
+                newList.add(accRow);
+            }
+        }
 
         while (newList.size() < 3) {
-            newList.add(TemplateDetailsItem.createAccountRow());
+            final TemplateDetailsItem.AccountRow accountRow =
+                    TemplateDetailsItem.createAccountRow();
+            accountRow.setId(genItemId());
+            accountRow.setPosition(newList.size());
+            newList.add(accountRow);
+            changes = true;
+            hasEmptyItem = true;
+        }
+
+        if (!hasEmptyItem) {
+            final TemplateDetailsItem.AccountRow accountRow =
+                    TemplateDetailsItem.createAccountRow();
+            accountRow.setId(genItemId());
+            accountRow.setPosition(newList.size());
+            newList.add(accountRow);
             changes = true;
         }
 
-        if (changes)
-            items.setValue(newList);
+        if (changes) {
+            Logger.debug("tmpl", "Changes detected, applying new list");
+
+            if (async)
+                items.postValue(newList);
+            else
+                items.setValue(newList);
+        }
+        else
+            Logger.debug("tmpl", "No changes, ignoring new list");
+    }
+    public int genItemId() {
+        return syntheticItemId.decrementAndGet();
     }
     public LiveData<List<TemplateDetailsItem>> getItems(Long patternId) {
         if (itemsLoaded && Objects.equals(patternId, this.mPatternId))
@@ -110,15 +172,18 @@ public class TemplateDetailsViewModel extends ViewModel {
                 ArrayList<TemplateDetailsItem> l = new ArrayList<>();
 
                 TemplateDetailsItem header = TemplateDetailsItem.fromRoomObject(src.header);
+                Logger.debug("tmpl-db", "Got header template item with id of " + header.getId());
                 l.add(header);
+                Collections.sort(src.accounts,
+                        (o1, o2) -> Long.compare(o1.getPosition(), o2.getPosition()));
                 for (TemplateAccount acc : src.accounts) {
                     l.add(TemplateDetailsItem.fromRoomObject(acc));
                 }
 
                 for (TemplateDetailsItem i : l) {
-                    Logger.debug("patterns-db", "Loaded pattern item " + i);
+                    Logger.debug("tmpl-db", "Loaded pattern item " + i);
                 }
-                items.postValue(l);
+                applyList(l, true);
                 itemsLoaded = true;
 
                 dbList.removeObserver(this);
@@ -146,6 +211,9 @@ public class TemplateDetailsViewModel extends ViewModel {
 
             TemplateDetailsItem.Header modelHeader = list.get(0)
                                                          .asHeaderItem();
+            modelHeader.setName(Misc.trim(modelHeader.getName()));
+            if (modelHeader.getName().isEmpty())
+                modelHeader.setName(getDefaultTemplateName());
             TemplateHeaderDAO headerDAO = DB.get()
                                             .getTemplateDAO();
             TemplateHeader dbHeader = modelHeader.toDBO();
@@ -170,7 +238,7 @@ public class TemplateDetailsViewModel extends ViewModel {
                 TemplateAccount dbAccount = accRowItem.toDBO(dbHeader.getId());
                 dbAccount.setTemplateId(mPatternId);
                 dbAccount.setPosition(i);
-                if (newPattern) {
+                if (dbAccount.getId() < 0) {
                     dbAccount.setId(null);
                     dbAccount.setId(taDAO.insertSync(dbAccount));
                 }
@@ -185,4 +253,78 @@ public class TemplateDetailsViewModel extends ViewModel {
             taDAO.finishSave(mPatternId);
         });
     }
+    private ArrayList<TemplateDetailsItem> copyItems() {
+        List<TemplateDetailsItem> oldList = items.getValue();
+        ArrayList<TemplateDetailsItem> result = new ArrayList<>(oldList.size());
+
+        for (TemplateDetailsItem item : oldList) {
+            if (item instanceof TemplateDetailsItem.Header)
+                result.add(new TemplateDetailsItem.Header(item.asHeaderItem()));
+            else if (item instanceof TemplateDetailsItem.AccountRow)
+                result.add(new TemplateDetailsItem.AccountRow(item.asAccountRowItem()));
+            else
+                throw new RuntimeException("Unexpected item " + item);
+        }
+
+        return result;
+    }
+    public void moveItem(int sourcePos, int targetPos) {
+        final List<TemplateDetailsItem> newList = copyItems();
+
+        if (BuildConfig.DEBUG) {
+            Logger.debug("drag", "Before move:");
+            for (int i = 1; i < newList.size(); i++) {
+                final TemplateDetailsItem item = newList.get(i);
+                Logger.debug("drag",
+                        String.format(Locale.US, "  %d: id %d, pos %d", i, item.getId(),
+                                item.getPosition()));
+            }
+        }
+
+        {
+            TemplateDetailsItem item = newList.remove(sourcePos);
+            newList.add(targetPos, item);
+        }
+
+        // adjust affected items' positions
+        {
+            int startPos, endPos;
+            if (sourcePos < targetPos) {
+                // moved down
+                startPos = sourcePos;
+                endPos = targetPos;
+            }
+            else {
+                // moved up
+                startPos = targetPos;
+                endPos = sourcePos;
+            }
+
+            for (int i = startPos; i <= endPos; i++) {
+                newList.get(i)
+                       .setPosition(i);
+            }
+        }
+
+        if (BuildConfig.DEBUG) {
+            Logger.debug("drag", "After move:");
+            for (int i = 1; i < newList.size(); i++) {
+                final TemplateDetailsItem item = newList.get(i);
+                Logger.debug("drag",
+                        String.format(Locale.US, "  %d: id %d, pos %d", i, item.getId(),
+                                item.getPosition()));
+            }
+        }
+
+        items.setValue(newList);
+    }
+    public void removeItem(int position) {
+        Logger.debug("tmpl", "Removing item at position " + position);
+        ArrayList<TemplateDetailsItem> newList = copyItems();
+        newList.remove(position);
+        for (int i = position; i < newList.size(); i++)
+            newList.get(i)
+                   .setPosition(i);
+        applyList(newList);
+    }
 }
\ No newline at end of file