X-Git-Url: https://git.ktnx.net/?p=mobile-ledger.git;a=blobdiff_plain;f=app%2Fsrc%2Fmain%2Fjava%2Fnet%2Fktnx%2Fmobileledger%2Fui%2Ftemplates%2FTemplateDetailsViewModel.java;h=5d3d743189ed1ed0916915fab9a6fdec1b16454e;hp=608bb6344cade07fab781509a1cdc37de1ade915;hb=e543f465bd9c7f340c4a572287ecf0a31caccee9;hpb=59ec619c8f3a34e90804067691854864d45d45e6 diff --git a/app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsViewModel.java b/app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsViewModel.java index 608bb634..5d3d7431 100644 --- a/app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsViewModel.java +++ b/app/src/main/java/net/ktnx/mobileledger/ui/templates/TemplateDetailsViewModel.java @@ -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; @@ -38,6 +39,7 @@ 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> items = @@ -45,6 +47,7 @@ public class TemplateDetailsViewModel extends ViewModel { private Long mPatternId; private String mDefaultPatternName; private boolean itemsLoaded = false; + private final AtomicInteger syntheticItemId = new AtomicInteger(0); public String getDefaultPatternName() { return mDefaultPatternName; @@ -54,37 +57,97 @@ public class TemplateDetailsViewModel extends ViewModel { } public void resetItems() { - ArrayList 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 srcList) { + applyList(srcList, false); + } + public void applyList(List 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 newList = new ArrayList<>(items.getValue()); - boolean changes = false; - if (newList.size() < 1) { + ArrayList 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> getItems(Long patternId) { if (itemsLoaded && Objects.equals(patternId, this.mPatternId)) @@ -111,6 +174,8 @@ public class TemplateDetailsViewModel extends ViewModel { TemplateDetailsItem header = TemplateDetailsItem.fromRoomObject(src.header); 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)); } @@ -118,7 +183,7 @@ public class TemplateDetailsViewModel extends ViewModel { for (TemplateDetailsItem i : l) { Logger.debug("patterns-db", "Loaded pattern item " + i); } - items.postValue(l); + applyList(l, true); itemsLoaded = true; dbList.removeObserver(this); @@ -163,13 +228,14 @@ public class TemplateDetailsViewModel extends ViewModel { TemplateAccountDAO taDAO = DB.get() .getTemplateAccountDAO(); + taDAO.prepareForSave(mPatternId); for (int i = 1; i < list.size(); i++) { final TemplateDetailsItem.AccountRow accRowItem = list.get(i) .asAccountRowItem(); 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)); } @@ -181,6 +247,81 @@ public class TemplateDetailsViewModel extends ViewModel { dbAccount.getId(), dbAccount.getAccountName(), dbAccount.getAccountComment(), dbAccount.getNegateAmount(), accRowItem)); } + taDAO.finishSave(mPatternId); }); } + private ArrayList copyItems() { + List oldList = items.getValue(); + ArrayList 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 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 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