]> git.ktnx.net Git - mobile-ledger.git/commitdiff
finish support for multiple server APIs when retrieving data
authorDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 27 Dec 2020 21:21:37 +0000 (23:21 +0200)
committerDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 27 Dec 2020 21:21:37 +0000 (23:21 +0200)
this also adds support for the last JSON API change introduced in
1.19.1 (see gh#1360)

exceptions from the low-level json parser are interpreted as version
incompatibility and a pointer is made to profile details

36 files changed:
app/src/main/java/net/ktnx/mobileledger/async/RetrieveTransactionsTask.java
app/src/main/java/net/ktnx/mobileledger/async/SendTransactionTask.java
app/src/main/java/net/ktnx/mobileledger/json/AccountListParser.java
app/src/main/java/net/ktnx/mobileledger/json/ApiNotSupportedException.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/ParsedLedgerAccount.java
app/src/main/java/net/ktnx/mobileledger/json/ParsedStyle.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/TransactionListParser.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_14/AccountListParser.java
app/src/main/java/net/ktnx/mobileledger/json/v1_14/ParsedBalance.java
app/src/main/java/net/ktnx/mobileledger/json/v1_14/ParsedLedgerAccount.java
app/src/main/java/net/ktnx/mobileledger/json/v1_14/ParsedStyle.java
app/src/main/java/net/ktnx/mobileledger/json/v1_14/TransactionListParser.java
app/src/main/java/net/ktnx/mobileledger/json/v1_15/AccountListParser.java
app/src/main/java/net/ktnx/mobileledger/json/v1_15/ParsedLedgerAccount.java
app/src/main/java/net/ktnx/mobileledger/json/v1_15/ParsedStyle.java
app/src/main/java/net/ktnx/mobileledger/json/v1_15/TransactionListParser.java
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/AccountListParser.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedAmount.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedBalance.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedLedgerAccount.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedLedgerTransaction.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPosting.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPrecision.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPrice.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedQuantity.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedSourcePos.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedStyle.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/TransactionListParser.java [new file with mode: 0644]
app/src/main/java/net/ktnx/mobileledger/model/HledgerVersion.java
app/src/main/java/net/ktnx/mobileledger/model/MobileLedgerProfile.java
app/src/main/java/net/ktnx/mobileledger/ui/activity/MainActivity.java
app/src/main/java/net/ktnx/mobileledger/ui/profiles/ProfileDetailFragment.java
app/src/main/res/layout/profile_detail.xml
app/src/main/res/menu/api_version.xml
app/src/main/res/values-bg/strings.xml
app/src/main/res/values/strings.xml

index 85f7665146b556303edfbe8435738b740394e50b..d092a1cbfc55f1f0294cef1f6fc583248e14efa6 100644 (file)
@@ -24,17 +24,20 @@ import android.os.OperationCanceledException;
 
 import androidx.annotation.NonNull;
 
+import com.fasterxml.jackson.databind.RuntimeJsonMappingException;
+
 import net.ktnx.mobileledger.App;
 import net.ktnx.mobileledger.err.HTTPException;
-import net.ktnx.mobileledger.json.v1_15.AccountListParser;
-import net.ktnx.mobileledger.json.v1_15.ParsedLedgerTransaction;
-import net.ktnx.mobileledger.json.v1_15.TransactionListParser;
+import net.ktnx.mobileledger.json.AccountListParser;
+import net.ktnx.mobileledger.json.ApiNotSupportedException;
+import net.ktnx.mobileledger.json.TransactionListParser;
 import net.ktnx.mobileledger.model.Data;
 import net.ktnx.mobileledger.model.LedgerAccount;
 import net.ktnx.mobileledger.model.LedgerTransaction;
 import net.ktnx.mobileledger.model.LedgerTransactionAccount;
 import net.ktnx.mobileledger.model.MobileLedgerProfile;
 import net.ktnx.mobileledger.ui.MainModel;
+import net.ktnx.mobileledger.utils.Logger;
 import net.ktnx.mobileledger.utils.NetworkUtil;
 
 import java.io.BufferedReader;
@@ -381,7 +384,40 @@ public class RetrieveTransactionsTask extends
     public void addNumberOfPostings(int number) {
         expectedPostingsCount += number;
     }
-    private List<LedgerAccount> retrieveAccountList() throws IOException, HTTPException {
+    private List<LedgerAccount> retrieveAccountList()
+            throws IOException, HTTPException, ApiNotSupportedException {
+        final SendTransactionTask.API apiVersion = profile.getApiVersion();
+        if (apiVersion.equals(SendTransactionTask.API.auto)) {
+            return retrieveAccountListAnyVersion();
+        }
+        else if (apiVersion.equals(SendTransactionTask.API.html)) {
+            Logger.debug("json",
+                    "Declining using JSON API for /accounts with configured legacy API version");
+            return null;
+        }
+        else {
+            return retrieveAccountListForVersion(apiVersion);
+        }
+    }
+    private List<LedgerAccount> retrieveAccountListAnyVersion()
+            throws HTTPException, ApiNotSupportedException {
+        for (SendTransactionTask.API ver : SendTransactionTask.API.allVersions) {
+            try {
+                return retrieveAccountListForVersion(ver);
+            }
+            catch (Exception e) {
+                Logger.debug("json",
+                        String.format(Locale.US, "Error during account list retrieval using API %s",
+                                ver.getDescription()));
+            }
+
+            throw new ApiNotSupportedException();
+        }
+
+        throw new RuntimeException("This should never be reached");
+    }
+    private List<LedgerAccount> retrieveAccountListForVersion(SendTransactionTask.API version)
+            throws IOException, HTTPException {
         HttpURLConnection http = NetworkUtil.prepareConnection(profile, "accounts");
         http.setAllowUserInteraction(false);
         switch (http.getResponseCode()) {
@@ -405,12 +441,12 @@ public class RetrieveTransactionsTask extends
             if (http.getResponseCode() != 200)
                 throw new IOException(String.format("HTTP error %d", http.getResponseCode()));
 
-            AccountListParser parser = new AccountListParser(resp);
+            AccountListParser parser = AccountListParser.forApiVersion(version, resp);
             expectedPostingsCount = 0;
 
             while (true) {
                 throwIfCancelled();
-                LedgerAccount acc = parser.nextLedgerAccount(this, map);
+                LedgerAccount acc = parser.nextAccount(this, map);
                 if (acc == null)
                     break;
                 list.add(acc);
@@ -430,7 +466,40 @@ public class RetrieveTransactionsTask extends
         return list;
     }
     private List<LedgerTransaction> retrieveTransactionList()
-            throws IOException, ParseException, HTTPException {
+            throws ParseException, HTTPException, IOException, ApiNotSupportedException {
+        final SendTransactionTask.API apiVersion = profile.getApiVersion();
+        if (apiVersion.equals(SendTransactionTask.API.auto)) {
+            return retrieveTransactionListAnyVersion();
+        }
+        else if (apiVersion.equals(SendTransactionTask.API.html)) {
+            Logger.debug("json",
+                    "Declining using JSON API for /accounts with configured legacy API version");
+            return null;
+        }
+        else {
+            return retrieveTransactionListForVersion(apiVersion);
+        }
+
+    }
+    private List<LedgerTransaction> retrieveTransactionListAnyVersion()
+            throws ApiNotSupportedException {
+        for (SendTransactionTask.API ver : SendTransactionTask.API.allVersions) {
+            try {
+                return retrieveTransactionListForVersion(ver);
+            }
+            catch (Exception | HTTPException e) {
+                Logger.debug("json",
+                        String.format(Locale.US, "Error during account list retrieval using API %s",
+                                ver.getDescription()));
+            }
+
+            throw new ApiNotSupportedException();
+        }
+
+        throw new RuntimeException("This should never be reached");
+    }
+    private List<LedgerTransaction> retrieveTransactionListForVersion(
+            SendTransactionTask.API apiVersion) throws IOException, ParseException, HTTPException {
         Progress progress = new Progress();
         progress.setTotal(expectedPostingsCount);
 
@@ -449,18 +518,17 @@ public class RetrieveTransactionsTask extends
         try (InputStream resp = http.getInputStream()) {
             throwIfCancelled();
 
-            TransactionListParser parser = new TransactionListParser(resp);
+            TransactionListParser parser = TransactionListParser.forApiVersion(apiVersion, resp);
 
             int processedPostings = 0;
 
             while (true) {
                 throwIfCancelled();
-                ParsedLedgerTransaction parsedTransaction = parser.nextTransaction();
+                LedgerTransaction transaction = parser.nextTransaction();
                 throwIfCancelled();
-                if (parsedTransaction == null)
+                if (transaction == null)
                     break;
 
-                LedgerTransaction transaction = parsedTransaction.asLedgerTransaction();
                 trList.add(transaction);
 
                 progress.setProgress(processedPostings += transaction.getAccounts()
@@ -499,10 +567,15 @@ public class RetrieveTransactionsTask extends
         List<LedgerTransaction> transactions;
         try {
             accounts = retrieveAccountList();
+            // accounts is null in API-version auto-detection and means
+            // requesting 'html' API version via the JSON classes
+            // this can't work, and the null results in the legacy code below
+            // being called
             if (accounts == null)
                 transactions = null;
             else
                 transactions = retrieveTransactionList();
+
             if (accounts == null || transactions == null) {
                 accounts = new ArrayList<>();
                 transactions = new ArrayList<>();
@@ -525,6 +598,10 @@ public class RetrieveTransactionsTask extends
             e.printStackTrace();
             return new Result(e.getLocalizedMessage());
         }
+        catch (RuntimeJsonMappingException e) {
+            e.printStackTrace();
+            return new Result(Result.ERR_JSON_PARSER_ERROR);
+        }
         catch (ParseException e) {
             e.printStackTrace();
             return new Result("Network error");
@@ -533,6 +610,10 @@ public class RetrieveTransactionsTask extends
             e.printStackTrace();
             return new Result("Operation cancelled");
         }
+        catch (ApiNotSupportedException e) {
+            e.printStackTrace();
+            return new Result("Server version not supported");
+        }
         finally {
             Data.backgroundTaskFinished();
         }
@@ -622,6 +703,7 @@ public class RetrieveTransactionsTask extends
     }
 
     public static class Result {
+        public static String ERR_JSON_PARSER_ERROR = "err_json_parser";
         public String error;
         public List<LedgerAccount> accounts;
         public List<LedgerTransaction> transactions;
index 1c4be5c47fea6789c6a22c3baa1b93928294775b..9f441f9ca6148b5ddbabd0e24a6059ae9eaecc10 100644 (file)
@@ -293,10 +293,10 @@ public class SendTransactionTask extends AsyncTask<LedgerTransaction, Void, Void
                 case html:
                     legacySendOkWithRetry();
                     break;
-                case pre_1_15:
+                case v1_14:
                     send_1_14_OK();
                     break;
-                case post_1_14:
+                case v1_15:
                     send_1_15_OK();
                     break;
                 default:
@@ -327,8 +327,9 @@ public class SendTransactionTask extends AsyncTask<LedgerTransaction, Void, Void
     }
 
     public enum API {
-        auto(0), html(-1), pre_1_15(-2), post_1_14(-3);
+        auto(0), html(-1), v1_14(-2), v1_15(-3), v1_19_1(-4);
         private static final SparseArray<API> map = new SparseArray<>();
+        public static API[] allVersions = {v1_19_1, v1_15, v1_14};
 
         static {
             for (API item : API.values()) {
@@ -336,7 +337,7 @@ public class SendTransactionTask extends AsyncTask<LedgerTransaction, Void, Void
             }
         }
 
-        private int value;
+        private final int value;
 
         API(int value) {
             this.value = value;
@@ -353,13 +354,31 @@ public class SendTransactionTask extends AsyncTask<LedgerTransaction, Void, Void
                     return resources.getString(R.string.api_auto);
                 case html:
                     return resources.getString(R.string.api_html);
-                case pre_1_15:
-                    return resources.getString(R.string.api_pre_1_15);
-                case post_1_14:
-                    return resources.getString(R.string.api_post_1_14);
+                case v1_14:
+                    return resources.getString(R.string.api_1_14);
+                case v1_15:
+                    return resources.getString(R.string.api_1_15);
+                case v1_19_1:
+                    return resources.getString(R.string.api_1_19_1);
                 default:
                     throw new IllegalStateException("Unexpected value: " + value);
             }
         }
+        public String getDescription() {
+            switch (this) {
+                case auto:
+                    return "(automatic)";
+                case html:
+                    return "(HTML)";
+                case v1_14:
+                    return "1.14";
+                case v1_15:
+                    return "1.15";
+                case v1_19_1:
+                    return "1.19.1";
+                default:
+                    throw new IllegalStateException("Unexpected value: " + this);
+            }
+        }
     }
-}
+}
\ No newline at end of file
index 053b1e9074c6561359daf0b4d235cdd91e5775cf..783142e5df0985de21994c24e80ecf140afa66c8 100644 (file)
@@ -20,79 +20,47 @@ package net.ktnx.mobileledger.json;
 import com.fasterxml.jackson.databind.MappingIterator;
 
 import net.ktnx.mobileledger.async.RetrieveTransactionsTask;
+import net.ktnx.mobileledger.async.SendTransactionTask;
 import net.ktnx.mobileledger.model.LedgerAccount;
 
-import java.util.ArrayList;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
 
 import static net.ktnx.mobileledger.utils.Logger.debug;
 
 abstract public class AccountListParser {
     protected MappingIterator<net.ktnx.mobileledger.json.ParsedLedgerAccount> iterator;
+    public static AccountListParser forApiVersion(SendTransactionTask.API version,
+                                                  InputStream input) throws IOException {
+        switch (version) {
+            case v1_14:
+                return new net.ktnx.mobileledger.json.v1_14.AccountListParser(input);
+            case v1_15:
+                return new net.ktnx.mobileledger.json.v1_15.AccountListParser(input);
+            case v1_19_1:
+                return new net.ktnx.mobileledger.json.v1_19_1.AccountListParser(input);
+            default:
+                throw new RuntimeException("Unsupported version " + version.toString());
+        }
 
-    public ParsedLedgerAccount nextAccount() {
+    }
+    public abstract SendTransactionTask.API getApiVersion();
+    public LedgerAccount nextAccount(RetrieveTransactionsTask task,
+                                     HashMap<String, LedgerAccount> map) {
         if (!iterator.hasNext())
             return null;
 
-        ParsedLedgerAccount next = iterator.next();
+        LedgerAccount next = iterator.next()
+                                     .toLedgerAccount(task, map);
 
-        if (next.getAname()
+        if (next.getName()
                 .equalsIgnoreCase("root"))
-            return nextAccount();
+            return nextAccount(task, map);
 
-        debug("accounts", String.format("Got account '%s' [v1.15]", next.getAname()));
+        debug("accounts", String.format("Got account '%s' [%s]", next.getName(),
+                getApiVersion().getDescription()));
         return next;
     }
-    public LedgerAccount nextLedgerAccount(RetrieveTransactionsTask task,
-                                           HashMap<String, LedgerAccount> map) {
-        ParsedLedgerAccount parsedAccount = nextAccount();
-        if (parsedAccount == null)
-            return null;
-
-        task.addNumberOfPostings(parsedAccount.getAnumpostings());
-        final String accName = parsedAccount.getAname();
-        LedgerAccount acc = map.get(accName);
-        if (acc != null)
-            throw new RuntimeException(
-                    String.format("Account '%s' already present", acc.getName()));
-        String parentName = LedgerAccount.extractParentName(accName);
-        ArrayList<LedgerAccount> createdParents = new ArrayList<>();
-        LedgerAccount parent;
-        if (parentName == null) {
-            parent = null;
-        }
-        else {
-            parent = task.ensureAccountExists(parentName, map, createdParents);
-            parent.setHasSubAccounts(true);
-        }
-        acc = new LedgerAccount(task.getProfile(), accName, parent);
-        map.put(accName, acc);
-
-        String lastCurrency = null;
-        float lastCurrencyAmount = 0;
-        for (ParsedBalance b : parsedAccount.getAibalance()) {
-            task.throwIfCancelled();
-            final String currency = b.getAcommodity();
-            final float amount = b.getAquantity()
-                                  .asFloat();
-            if (currency.equals(lastCurrency)) {
-                lastCurrencyAmount += amount;
-            }
-            else {
-                if (lastCurrency != null) {
-                    acc.addAmount(lastCurrencyAmount, lastCurrency);
-                }
-                lastCurrency = currency;
-                lastCurrencyAmount = amount;
-            }
-        }
-        if (lastCurrency != null) {
-            acc.addAmount(lastCurrencyAmount, lastCurrency);
-        }
-        for (LedgerAccount p : createdParents)
-            acc.propagateAmountsTo(p);
-
-        return acc;
-    }
 
 }
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/ApiNotSupportedException.java b/app/src/main/java/net/ktnx/mobileledger/json/ApiNotSupportedException.java
new file mode 100644 (file)
index 0000000..d552a68
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright © 2020 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.json;
+
+public class ApiNotSupportedException extends Throwable {}
index aff5775358d7e393cb82fea7116e844150ecab01..04eff28f29e7cef40b9386bbc56bd5cd14e60012 100644 (file)
 
 package net.ktnx.mobileledger.json;
 
-import net.ktnx.mobileledger.json.ParsedBalance;
+import net.ktnx.mobileledger.async.RetrieveTransactionsTask;
+import net.ktnx.mobileledger.model.LedgerAccount;
 
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 
-public class ParsedLedgerAccount {
+public abstract class ParsedLedgerAccount {
     private String aname;
     private int anumpostings;
-    private List<ParsedBalance> aibalance;
+    public abstract List<SimpleBalance> getSimpleBalance();
     public String getAname() {
         return aname;
     }
@@ -37,10 +40,71 @@ public class ParsedLedgerAccount {
     public void setAnumpostings(int anumpostings) {
         this.anumpostings = anumpostings;
     }
-    public List<ParsedBalance> getAibalance() {
-        return aibalance;
+    public LedgerAccount toLedgerAccount(RetrieveTransactionsTask task,
+                                         HashMap<String, LedgerAccount> map) {
+        task.addNumberOfPostings(getAnumpostings());
+        final String accName = getAname();
+        LedgerAccount acc = map.get(accName);
+        if (acc != null)
+            throw new RuntimeException(
+                    String.format("Account '%s' already present", acc.getName()));
+        String parentName = LedgerAccount.extractParentName(accName);
+        ArrayList<LedgerAccount> createdParents = new ArrayList<>();
+        LedgerAccount parent;
+        if (parentName == null) {
+            parent = null;
+        }
+        else {
+            parent = task.ensureAccountExists(parentName, map, createdParents);
+            parent.setHasSubAccounts(true);
+        }
+        acc = new LedgerAccount(task.getProfile(), accName, parent);
+        map.put(accName, acc);
+
+        String lastCurrency = null;
+        float lastCurrencyAmount = 0;
+        for (SimpleBalance b : getSimpleBalance()) {
+            task.throwIfCancelled();
+            final String currency = b.getCommodity();
+            final float amount = b.getAmount();
+            if (currency.equals(lastCurrency)) {
+                lastCurrencyAmount += amount;
+            }
+            else {
+                if (lastCurrency != null) {
+                    acc.addAmount(lastCurrencyAmount, lastCurrency);
+                }
+                lastCurrency = currency;
+                lastCurrencyAmount = amount;
+            }
+        }
+        if (lastCurrency != null) {
+            acc.addAmount(lastCurrencyAmount, lastCurrency);
+        }
+        for (LedgerAccount p : createdParents)
+            acc.propagateAmountsTo(p);
+
+        return acc;
     }
-    public void setAibalance(List<ParsedBalance> aibalance) {
-        this.aibalance = aibalance;
+
+    static public class SimpleBalance {
+        private String commodity;
+        private float amount;
+        public SimpleBalance(String commodity, float amount) {
+            this.commodity = commodity;
+            this.amount = amount;
+        }
+        public String getCommodity() {
+            return commodity;
+        }
+        public void setCommodity(String commodity) {
+            this.commodity = commodity;
+        }
+        public float getAmount() {
+            return amount;
+        }
+        public void setAmount(float amount) {
+            this.amount = amount;
+        }
     }
 }
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/ParsedStyle.java b/app/src/main/java/net/ktnx/mobileledger/json/ParsedStyle.java
new file mode 100644 (file)
index 0000000..c22cd3f
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2020 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.json;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedStyle {
+    private char asdecimalpoint;
+    private char ascommodityside;
+    private int digitgroups;
+    private boolean ascommodityspaced;
+    public ParsedStyle() {
+    }
+    public char getAsdecimalpoint() {
+        return asdecimalpoint;
+    }
+    public void setAsdecimalpoint(char asdecimalpoint) {
+        this.asdecimalpoint = asdecimalpoint;
+    }
+    public char getAscommodityside() {
+        return ascommodityside;
+    }
+    public void setAscommodityside(char ascommodityside) {
+        this.ascommodityside = ascommodityside;
+    }
+    public int getDigitgroups() {
+        return digitgroups;
+    }
+    public void setDigitgroups(int digitgroups) {
+        this.digitgroups = digitgroups;
+    }
+    public boolean isAscommodityspaced() {
+        return ascommodityspaced;
+    }
+    public void setAscommodityspaced(boolean ascommodityspaced) {
+        this.ascommodityspaced = ascommodityspaced;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/TransactionListParser.java b/app/src/main/java/net/ktnx/mobileledger/json/TransactionListParser.java
new file mode 100644 (file)
index 0000000..99841f8
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2020 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.json;
+
+import net.ktnx.mobileledger.async.SendTransactionTask;
+import net.ktnx.mobileledger.model.LedgerTransaction;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+
+public abstract class TransactionListParser {
+    public static TransactionListParser forApiVersion(SendTransactionTask.API apiVersion,
+                                                      InputStream input) throws IOException {
+        switch (apiVersion) {
+            case v1_14:
+                return new net.ktnx.mobileledger.json.v1_14.TransactionListParser(input);
+            case v1_15:
+                return new net.ktnx.mobileledger.json.v1_15.TransactionListParser(input);
+            case v1_19_1:
+                return new net.ktnx.mobileledger.json.v1_19_1.TransactionListParser(input);
+            default:
+                throw new RuntimeException("Unsupported version " + apiVersion.toString());
+        }
+
+    }
+    abstract public LedgerTransaction nextTransaction() throws ParseException;
+}
index f3773a52850d5c354c8a9c163469a80fb27bc7df..1df52924ca397b4fced7fbe73a57a9294e37fd8f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
 
 package net.ktnx.mobileledger.json.v1_14;
 
-import com.fasterxml.jackson.databind.MappingIterator;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectReader;
 
+import net.ktnx.mobileledger.async.SendTransactionTask;
+
 import java.io.IOException;
 import java.io.InputStream;
 
-import static net.ktnx.mobileledger.utils.Logger.debug;
-
-public class AccountListParser {
-
-    private final MappingIterator<ParsedLedgerAccount> iterator;
+public class AccountListParser extends net.ktnx.mobileledger.json.AccountListParser {
 
     public AccountListParser(InputStream input) throws IOException {
         ObjectMapper mapper = new ObjectMapper();
@@ -36,14 +33,8 @@ public class AccountListParser {
 
         iterator = reader.readValues(input);
     }
-    public ParsedLedgerAccount nextAccount() {
-        if (!iterator.hasNext()) return null;
-
-        ParsedLedgerAccount next = iterator.next();
-
-        if (next.getAname().equalsIgnoreCase("root")) return nextAccount();
-
-        debug("accounts", String.format("Got account '%s'", next.getAname()));
-        return next;
+    @Override
+    public SendTransactionTask.API getApiVersion() {
+        return SendTransactionTask.API.v1_14;
     }
 }
index 39cd1908ff308f1f450b9453c577d98180e38835..cb8b5f5fbe3bdf9ab225e8f258e326bcc785c0dd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
 
 package net.ktnx.mobileledger.json.v1_14;
 
-import androidx.annotation.NonNull;
-
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class ParsedBalance {
-    private ParsedQuantity aquantity;
-    private String acommodity;
+public class ParsedBalance extends net.ktnx.mobileledger.json.ParsedBalance {
     private ParsedStyle astyle;
     public ParsedBalance() {
     }
-    public ParsedQuantity getAquantity() {
-        return aquantity;
-    }
-    public void setAquantity(ParsedQuantity aquantity) {
-        this.aquantity = aquantity;
-    }
-    @NonNull
-    public String getAcommodity() {
-        return (acommodity == null) ? "" : acommodity;
-    }
-    public void setAcommodity(String acommodity) {
-        this.acommodity = acommodity;
-    }
     public ParsedStyle getAstyle() {
         return astyle;
     }
index ab982b4e52883872f4cb6f130900a0c814ad141c..476e9cd713936c8c3474151b5b2e00216ac87424 100644 (file)
@@ -19,22 +19,15 @@ package net.ktnx.mobileledger.json.v1_14;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
+import java.util.ArrayList;
 import java.util.List;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class ParsedLedgerAccount {
+public class ParsedLedgerAccount extends net.ktnx.mobileledger.json.ParsedLedgerAccount {
     private List<ParsedBalance> aebalance;
     private List<ParsedBalance> aibalance;
-    private String aname;
-    private int anumpostings;
     public ParsedLedgerAccount() {
     }
-    public int getAnumpostings() {
-        return anumpostings;
-    }
-    public void setAnumpostings(int anumpostings) {
-        this.anumpostings = anumpostings;
-    }
     public List<ParsedBalance> getAebalance() {
         return aebalance;
     }
@@ -47,11 +40,14 @@ public class ParsedLedgerAccount {
     public void setAibalance(List<ParsedBalance> aibalance) {
         this.aibalance = aibalance;
     }
-    public String getAname() {
-        return aname;
-    }
-    public void setAname(String aname) {
-        this.aname = aname;
-    }
+    @Override
+    public List<SimpleBalance> getSimpleBalance() {
+        List<SimpleBalance> result = new ArrayList<SimpleBalance>();
+        for (ParsedBalance b : getAibalance()) {
+            result.add(new SimpleBalance(b.getAcommodity(), b.getAquantity()
+                                                             .asFloat()));
+        }
 
+        return result;
+    }
 }
index 798cb81c8bff5d03ff4b9b489bee2e236f2f90bb..74b02a5090de22278eaafaec1dc70b42e1ad9974 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
@@ -20,12 +20,8 @@ package net.ktnx.mobileledger.json.v1_14;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class ParsedStyle {
+public class ParsedStyle extends net.ktnx.mobileledger.json.ParsedStyle {
     private int asprecision;
-    private char asdecimalpoint;
-    private char ascommodityside;
-    private int digitgroups;
-    private boolean ascommodityspaced;
     public ParsedStyle() {
     }
     public int getAsprecision() {
@@ -34,28 +30,4 @@ public class ParsedStyle {
     public void setAsprecision(int asprecision) {
         this.asprecision = asprecision;
     }
-    public char getAsdecimalpoint() {
-        return asdecimalpoint;
-    }
-    public void setAsdecimalpoint(char asdecimalpoint) {
-        this.asdecimalpoint = asdecimalpoint;
-    }
-    public char getAscommodityside() {
-        return ascommodityside;
-    }
-    public void setAscommodityside(char ascommodityside) {
-        this.ascommodityside = ascommodityside;
-    }
-    public int getDigitgroups() {
-        return digitgroups;
-    }
-    public void setDigitgroups(int digitgroups) {
-        this.digitgroups = digitgroups;
-    }
-    public boolean isAscommodityspaced() {
-        return ascommodityspaced;
-    }
-    public void setAscommodityspaced(boolean ascommodityspaced) {
-        this.ascommodityspaced = ascommodityspaced;
-    }
 }
index 742c595757103ce34cb94ea1458a8cac09cee47e..f9be5a3ae4fda936ee40675b424736fe79180cbf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
@@ -21,10 +21,13 @@ import com.fasterxml.jackson.databind.MappingIterator;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectReader;
 
+import net.ktnx.mobileledger.model.LedgerTransaction;
+
 import java.io.IOException;
 import java.io.InputStream;
+import java.text.ParseException;
 
-public class TransactionListParser {
+public class TransactionListParser extends net.ktnx.mobileledger.json.TransactionListParser {
 
     private final MappingIterator<ParsedLedgerTransaction> iterator;
 
@@ -34,7 +37,8 @@ public class TransactionListParser {
         ObjectReader reader = mapper.readerFor(ParsedLedgerTransaction.class);
         iterator = reader.readValues(input);
     }
-    public ParsedLedgerTransaction nextTransaction() {
-        return iterator.hasNext() ? iterator.next() : null;
+    public LedgerTransaction nextTransaction() throws ParseException {
+        return iterator.hasNext() ? iterator.next()
+                                            .asLedgerTransaction() : null;
     }
 }
index 33c554c85b41f0406a5cff7197ce1826a4c94e02..005cd5bad7324349ebc731319278d7e388c19357 100644 (file)
@@ -20,6 +20,8 @@ package net.ktnx.mobileledger.json.v1_15;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectReader;
 
+import net.ktnx.mobileledger.async.SendTransactionTask;
+
 import java.io.IOException;
 import java.io.InputStream;
 
@@ -31,4 +33,8 @@ public class AccountListParser extends net.ktnx.mobileledger.json.AccountListPar
 
         iterator = reader.readValues(input);
     }
+    @Override
+    public SendTransactionTask.API getApiVersion() {
+        return SendTransactionTask.API.v1_15;
+    }
 }
index 085c32b3817f504befb07def2626d4be27d60f29..8e762cabe8a5060969d1f12625bbd8420da0a36b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
@@ -19,17 +19,5 @@ package net.ktnx.mobileledger.json.v1_15;
 
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
-import java.util.List;
-
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class ParsedLedgerAccount extends net.ktnx.mobileledger.json.ParsedLedgerAccount {
-    private List<ParsedBalance> aebalance;
-    public ParsedLedgerAccount() {
-    }
-    public List<ParsedBalance> getAebalance() {
-        return aebalance;
-    }
-    public void setAebalance(List<ParsedBalance> aebalance) {
-        this.aebalance = aebalance;
-    }
-}
+public class ParsedLedgerAccount extends net.ktnx.mobileledger.json.v1_14.ParsedLedgerAccount {}
index 554133c5105c72f18fcd9abe89e9218a59cbfa0d..b2f0f742acfb4ff394fede8ae7ad6003e83ca14a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
@@ -20,42 +20,4 @@ package net.ktnx.mobileledger.json.v1_15;
 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
 
 @JsonIgnoreProperties(ignoreUnknown = true)
-public class ParsedStyle {
-    private int asprecision;
-    private char asdecimalpoint;
-    private char ascommodityside;
-    private int digitgroups;
-    private boolean ascommodityspaced;
-    public ParsedStyle() {
-    }
-    public int getAsprecision() {
-        return asprecision;
-    }
-    public void setAsprecision(int asprecision) {
-        this.asprecision = asprecision;
-    }
-    public char getAsdecimalpoint() {
-        return asdecimalpoint;
-    }
-    public void setAsdecimalpoint(char asdecimalpoint) {
-        this.asdecimalpoint = asdecimalpoint;
-    }
-    public char getAscommodityside() {
-        return ascommodityside;
-    }
-    public void setAscommodityside(char ascommodityside) {
-        this.ascommodityside = ascommodityside;
-    }
-    public int getDigitgroups() {
-        return digitgroups;
-    }
-    public void setDigitgroups(int digitgroups) {
-        this.digitgroups = digitgroups;
-    }
-    public boolean isAscommodityspaced() {
-        return ascommodityspaced;
-    }
-    public void setAscommodityspaced(boolean ascommodityspaced) {
-        this.ascommodityspaced = ascommodityspaced;
-    }
-}
+public class ParsedStyle extends net.ktnx.mobileledger.json.v1_14.ParsedStyle {}
index 940deee4ff02de44385187524c74455fffd3c6fb..aab1bc41de499197e3d10f227583672825a78189 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2019 Damyan Ivanov.
+ * Copyright © 2020 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
@@ -21,10 +21,13 @@ import com.fasterxml.jackson.databind.MappingIterator;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.ObjectReader;
 
+import net.ktnx.mobileledger.model.LedgerTransaction;
+
 import java.io.IOException;
 import java.io.InputStream;
+import java.text.ParseException;
 
-public class TransactionListParser {
+public class TransactionListParser extends net.ktnx.mobileledger.json.TransactionListParser {
 
     private final MappingIterator<ParsedLedgerTransaction> iterator;
 
@@ -34,7 +37,8 @@ public class TransactionListParser {
         ObjectReader reader = mapper.readerFor(ParsedLedgerTransaction.class);
         iterator = reader.readValues(input);
     }
-    public ParsedLedgerTransaction nextTransaction() {
-        return iterator.hasNext() ? iterator.next() : null;
+    public LedgerTransaction nextTransaction() throws ParseException {
+        return iterator.hasNext() ? iterator.next()
+                                            .asLedgerTransaction() : null;
     }
 }
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/AccountListParser.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/AccountListParser.java
new file mode 100644 (file)
index 0000000..9ff89eb
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+
+import net.ktnx.mobileledger.async.SendTransactionTask;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class AccountListParser extends net.ktnx.mobileledger.json.AccountListParser {
+
+    public AccountListParser(InputStream input) throws IOException {
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectReader reader = mapper.readerFor(ParsedLedgerAccount.class);
+
+        iterator = reader.readValues(input);
+    }
+    @Override
+    public SendTransactionTask.API getApiVersion() {
+        return SendTransactionTask.API.v1_19_1;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedAmount.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedAmount.java
new file mode 100644 (file)
index 0000000..12cdbac
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedAmount {
+    private String acommodity;
+    private ParsedQuantity aquantity;
+    private boolean aismultiplier;
+    private ParsedStyle astyle;
+    private ParsedPrice aprice;
+    public ParsedAmount() {
+    }
+    public ParsedPrice getAprice() {
+        return aprice;
+    }
+    public void setAprice(ParsedPrice aprice) {
+        this.aprice = aprice;
+    }
+    public String getAcommodity() {
+        return acommodity;
+    }
+    public void setAcommodity(String acommodity) {
+        this.acommodity = acommodity;
+    }
+    public ParsedQuantity getAquantity() {
+        return aquantity;
+    }
+    public void setAquantity(ParsedQuantity aquantity) {
+        this.aquantity = aquantity;
+    }
+    public boolean isAismultiplier() {
+        return aismultiplier;
+    }
+    public void setAismultiplier(boolean aismultiplier) {
+        this.aismultiplier = aismultiplier;
+    }
+    public ParsedStyle getAstyle() {
+        return astyle;
+    }
+    public void setAstyle(ParsedStyle astyle) {
+        this.astyle = astyle;
+    }
+
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedBalance.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedBalance.java
new file mode 100644 (file)
index 0000000..5defe08
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedBalance extends net.ktnx.mobileledger.json.ParsedBalance {
+    private ParsedStyle astyle;
+    public ParsedBalance() {
+    }
+    public ParsedStyle getAstyle() {
+        return astyle;
+    }
+    public void setAstyle(ParsedStyle astyle) {
+        this.astyle = astyle;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedLedgerAccount.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedLedgerAccount.java
new file mode 100644 (file)
index 0000000..5fabdb5
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedLedgerAccount extends net.ktnx.mobileledger.json.ParsedLedgerAccount {
+    private List<ParsedBalance> aebalance;
+    private List<ParsedBalance> aibalance;
+    public ParsedLedgerAccount() {
+    }
+    public List<ParsedBalance> getAibalance() {
+        return aibalance;
+    }
+    public void setAibalance(List<ParsedBalance> aibalance) {
+        this.aibalance = aibalance;
+    }
+    public List<ParsedBalance> getAebalance() {
+        return aebalance;
+    }
+    public void setAebalance(List<ParsedBalance> aebalance) {
+        this.aebalance = aebalance;
+    }
+    @Override
+    public List<SimpleBalance> getSimpleBalance() {
+        List<SimpleBalance> result = new ArrayList<SimpleBalance>();
+        for (ParsedBalance b : getAibalance()) {
+            result.add(new SimpleBalance(b.getAcommodity(), b.getAquantity()
+                                                             .asFloat()));
+        }
+
+        return result;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedLedgerTransaction.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedLedgerTransaction.java
new file mode 100644 (file)
index 0000000..74af233
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import net.ktnx.mobileledger.model.LedgerTransaction;
+import net.ktnx.mobileledger.model.LedgerTransactionAccount;
+import net.ktnx.mobileledger.utils.Globals;
+import net.ktnx.mobileledger.utils.Misc;
+import net.ktnx.mobileledger.utils.SimpleDate;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedLedgerTransaction implements net.ktnx.mobileledger.json.ParsedLedgerTransaction {
+    private String tdate;
+    private String tdate2 = null;
+    private String tdescription;
+    private String tcomment;
+    private String tcode = "";
+    private String tstatus = "Unmarked";
+    private String tprecedingcomment = "";
+    private int tindex;
+    private List<ParsedPosting> tpostings;
+    private List<List<String>> ttags = new ArrayList<>();
+    private ParsedSourcePos tsourcepos = new ParsedSourcePos();
+    public ParsedLedgerTransaction() {
+    }
+    public static ParsedLedgerTransaction fromLedgerTransaction(LedgerTransaction tr) {
+        ParsedLedgerTransaction result = new ParsedLedgerTransaction();
+        result.setTcomment(tr.getComment());
+        result.setTprecedingcomment("");
+
+        ArrayList<ParsedPosting> postings = new ArrayList<>();
+        for (LedgerTransactionAccount acc : tr.getAccounts()) {
+            if (!acc.getAccountName()
+                    .isEmpty())
+                postings.add(ParsedPosting.fromLedgerAccount(acc));
+        }
+
+        result.setTpostings(postings);
+        SimpleDate transactionDate = tr.getDateIfAny();
+        if (transactionDate == null) {
+            transactionDate = SimpleDate.today();
+        }
+        result.setTdate(Globals.formatIsoDate(transactionDate));
+        result.setTdate2(null);
+        result.setTindex(1);
+        result.setTdescription(tr.getDescription());
+        return result;
+    }
+    public String getTcode() {
+        return tcode;
+    }
+    public void setTcode(String tcode) {
+        this.tcode = tcode;
+    }
+    public String getTstatus() {
+        return tstatus;
+    }
+    public void setTstatus(String tstatus) {
+        this.tstatus = tstatus;
+    }
+    public List<List<String>> getTtags() {
+        return ttags;
+    }
+    public void setTtags(List<List<String>> ttags) {
+        this.ttags = ttags;
+    }
+    public ParsedSourcePos getTsourcepos() {
+        return tsourcepos;
+    }
+    public void setTsourcepos(ParsedSourcePos tsourcepos) {
+        this.tsourcepos = tsourcepos;
+    }
+    public String getTprecedingcomment() {
+        return tprecedingcomment;
+    }
+    public void setTprecedingcomment(String tprecedingcomment) {
+        this.tprecedingcomment = tprecedingcomment;
+    }
+    public String getTdate() {
+        return tdate;
+    }
+    public void setTdate(String tdate) {
+        this.tdate = tdate;
+    }
+    public String getTdate2() {
+        return tdate2;
+    }
+    public void setTdate2(String tdate2) {
+        this.tdate2 = tdate2;
+    }
+    public String getTdescription() {
+        return tdescription;
+    }
+    public void setTdescription(String tdescription) {
+        this.tdescription = tdescription;
+    }
+    public String getTcomment() {
+        return tcomment;
+    }
+    public void setTcomment(String tcomment) {
+        this.tcomment = tcomment;
+    }
+    public int getTindex() {
+        return tindex;
+    }
+    public void setTindex(int tindex) {
+        this.tindex = tindex;
+        if (tpostings != null)
+            for (ParsedPosting p : tpostings) {
+                p.setPtransaction_(tindex);
+            }
+    }
+    public List<ParsedPosting> getTpostings() {
+        return tpostings;
+    }
+    public void setTpostings(List<ParsedPosting> tpostings) {
+        this.tpostings = tpostings;
+    }
+    public void addPosting(ParsedPosting posting) {
+        posting.setPtransaction_(tindex);
+        tpostings.add(posting);
+    }
+    public LedgerTransaction asLedgerTransaction() throws ParseException {
+        SimpleDate date = Globals.parseIsoDate(tdate);
+        LedgerTransaction tr = new LedgerTransaction(tindex, date, tdescription);
+        tr.setComment(Misc.trim(Misc.emptyIsNull(tcomment)));
+
+        List<ParsedPosting> postings = tpostings;
+
+        if (postings != null) {
+            for (ParsedPosting p : postings) {
+                tr.addAccount(p.asLedgerAccount());
+            }
+        }
+
+        tr.markDataAsLoaded();
+        return tr;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPosting.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPosting.java
new file mode 100644 (file)
index 0000000..e233062
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+import net.ktnx.mobileledger.model.LedgerTransactionAccount;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedPosting extends net.ktnx.mobileledger.json.ParsedPosting {
+    private Void pbalanceassertion;
+    private String pstatus = "Unmarked";
+    private String paccount;
+    private List<ParsedAmount> pamount;
+    private String pdate = null;
+    private String pdate2 = null;
+    private String ptype = "RegularPosting";
+    private String pcomment = "";
+    private List<List<String>> ptags = new ArrayList<>();
+    private String poriginal = null;
+    private int ptransaction_;
+    public ParsedPosting() {
+    }
+    public static ParsedPosting fromLedgerAccount(LedgerTransactionAccount acc) {
+        ParsedPosting result = new ParsedPosting();
+        result.setPaccount(acc.getAccountName());
+
+        String comment = acc.getComment();
+        if (comment == null)
+            comment = "";
+        result.setPcomment(comment);
+
+        ArrayList<ParsedAmount> amounts = new ArrayList<>();
+        ParsedAmount amt = new ParsedAmount();
+        amt.setAcommodity((acc.getCurrency() == null) ? "" : acc.getCurrency());
+        amt.setAismultiplier(false);
+        ParsedQuantity qty = new ParsedQuantity();
+        qty.setDecimalPlaces(2);
+        qty.setDecimalMantissa(Math.round(acc.getAmount() * 100));
+        amt.setAquantity(qty);
+        ParsedStyle style = new ParsedStyle();
+        style.setAscommodityside(getCommoditySide());
+        style.setAscommodityspaced(getCommoditySpaced());
+        style.setAsprecision(new ParsedPrecision(2));
+        style.setAsdecimalpoint('.');
+        amt.setAstyle(style);
+        if (acc.getCurrency() != null)
+            amt.setAcommodity(acc.getCurrency());
+        amounts.add(amt);
+        result.setPamount(amounts);
+        return result;
+    }
+    public String getPdate2() {
+        return pdate2;
+    }
+    public void setPdate2(String pdate2) {
+        this.pdate2 = pdate2;
+    }
+    public int getPtransaction_() {
+        return ptransaction_;
+    }
+    public void setPtransaction_(int ptransaction_) {
+        this.ptransaction_ = ptransaction_;
+    }
+    public String getPdate() {
+        return pdate;
+    }
+    public void setPdate(String pdate) {
+        this.pdate = pdate;
+    }
+    public String getPtype() {
+        return ptype;
+    }
+    public void setPtype(String ptype) {
+        this.ptype = ptype;
+    }
+    public String getPcomment() {
+        return pcomment;
+    }
+    public void setPcomment(String pcomment) {
+        this.pcomment = (pcomment == null) ? null : pcomment.trim();
+    }
+    public List<List<String>> getPtags() {
+        return ptags;
+    }
+    public void setPtags(List<List<String>> ptags) {
+        this.ptags = ptags;
+    }
+    public String getPoriginal() {
+        return poriginal;
+    }
+    public void setPoriginal(String poriginal) {
+        this.poriginal = poriginal;
+    }
+    public String getPstatus() {
+        return pstatus;
+    }
+    public void setPstatus(String pstatus) {
+        this.pstatus = pstatus;
+    }
+    public Void getPbalanceassertion() {
+        return pbalanceassertion;
+    }
+    public void setPbalanceassertion(Void pbalanceassertion) {
+        this.pbalanceassertion = pbalanceassertion;
+    }
+    public String getPaccount() {
+        return paccount;
+    }
+    public void setPaccount(String paccount) {
+        this.paccount = paccount;
+    }
+    public List<ParsedAmount> getPamount() {
+        return pamount;
+    }
+    public void setPamount(List<ParsedAmount> pamount) {
+        this.pamount = pamount;
+    }
+    public LedgerTransactionAccount asLedgerAccount() {
+        ParsedAmount amt = pamount.get(0);
+        return new LedgerTransactionAccount(paccount, amt.getAquantity()
+                                                         .asFloat(), amt.getAcommodity(),
+                getPcomment());
+    }
+
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPrecision.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPrecision.java
new file mode 100644 (file)
index 0000000..4472cf4
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+class ParsedPrecision {
+    private int contents;
+    private String tag;
+    ParsedPrecision() {
+        tag = "NaturalPrecision";
+    }
+    ParsedPrecision(int contents) {
+        this.contents = contents;
+        tag = "Precision";
+    }
+    public int getContents() {
+        return contents;
+    }
+    public void setContents(int contents) {
+        this.contents = contents;
+    }
+    public String getTag() {
+        return tag;
+    }
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPrice.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedPrice.java
new file mode 100644 (file)
index 0000000..0e1ea54
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+class ParsedPrice {
+    private String tag;
+    private Contents contents;
+    public ParsedPrice() {
+        tag = "NoPrice";
+    }
+    public Contents getContents() {
+        return contents;
+    }
+    public void setContents(Contents contents) {
+        this.contents = contents;
+    }
+    public String getTag() {
+        return tag;
+    }
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+    private static class Contents {
+        private ParsedPrice aprice;
+        private ParsedQuantity aquantity;
+        private String acommodity;
+        private boolean aismultiplier;
+        private ParsedStyle astyle;
+        public Contents() {
+            acommodity = "";
+        }
+        public ParsedPrice getAprice() {
+            return aprice;
+        }
+        public void setAprice(ParsedPrice aprice) {
+            this.aprice = aprice;
+        }
+        public ParsedQuantity getAquantity() {
+            return aquantity;
+        }
+        public void setAquantity(ParsedQuantity aquantity) {
+            this.aquantity = aquantity;
+        }
+        public String getAcommodity() {
+            return acommodity;
+        }
+        public void setAcommodity(String acommodity) {
+            this.acommodity = acommodity;
+        }
+        public boolean isAismultiplier() {
+            return aismultiplier;
+        }
+        public void setAismultiplier(boolean aismultiplier) {
+            this.aismultiplier = aismultiplier;
+        }
+        public ParsedStyle getAstyle() {
+            return astyle;
+        }
+        public void setAstyle(ParsedStyle astyle) {
+            this.astyle = astyle;
+        }
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedQuantity.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedQuantity.java
new file mode 100644 (file)
index 0000000..951bb56
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedQuantity extends net.ktnx.mobileledger.json.ParsedQuantity {}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedSourcePos.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedSourcePos.java
new file mode 100644 (file)
index 0000000..650f97c
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import java.util.ArrayList;
+import java.util.List;
+
+class ParsedSourcePos {
+    private String tag = "JournalSourcePos";
+    private List<Object> contents;
+    public ParsedSourcePos() {
+        contents = new ArrayList<>();
+        contents.add("");
+        contents.add(new Integer[]{1, 1});
+    }
+    public String getTag() {
+        return tag;
+    }
+    public void setTag(String tag) {
+        this.tag = tag;
+    }
+    public List<Object> getContents() {
+        return contents;
+    }
+    public void setContents(List<Object> contents) {
+        this.contents = contents;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedStyle.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/ParsedStyle.java
new file mode 100644 (file)
index 0000000..b0398a1
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class ParsedStyle extends net.ktnx.mobileledger.json.ParsedStyle {
+    private ParsedPrecision asprecision;
+    public ParsedStyle() {
+    }
+    public ParsedPrecision getAsprecision() {
+        return asprecision;
+    }
+    public void setAsprecision(ParsedPrecision asprecision) {
+        this.asprecision = asprecision;
+    }
+}
diff --git a/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/TransactionListParser.java b/app/src/main/java/net/ktnx/mobileledger/json/v1_19_1/TransactionListParser.java
new file mode 100644 (file)
index 0000000..12564a2
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2020 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.json.v1_19_1;
+
+import com.fasterxml.jackson.databind.MappingIterator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.ObjectReader;
+
+import net.ktnx.mobileledger.model.LedgerTransaction;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.text.ParseException;
+
+public class TransactionListParser extends net.ktnx.mobileledger.json.TransactionListParser {
+
+    private final MappingIterator<ParsedLedgerTransaction> iterator;
+
+    public TransactionListParser(InputStream input) throws IOException {
+
+        ObjectMapper mapper = new ObjectMapper();
+        ObjectReader reader = mapper.readerFor(ParsedLedgerTransaction.class);
+        iterator = reader.readValues(input);
+    }
+    public LedgerTransaction nextTransaction() throws ParseException {
+        return iterator.hasNext() ? iterator.next()
+                                            .asLedgerTransaction() : null;
+    }
+}
index ae9e77c83acdbfd657d584863feeb55a70d7df9c..835c5c1a95173327d9910b1241fb8830f1d1c6d3 100644 (file)
@@ -20,39 +20,41 @@ package net.ktnx.mobileledger.model;
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import net.ktnx.mobileledger.async.SendTransactionTask;
+
 import java.util.Locale;
 
 public class HledgerVersion {
     private final int major;
     private final int minor;
     private final int patch;
-    private final boolean isPre_1_20;
+    private final boolean isPre_1_20_1;
     private final boolean hasPatch;
     public HledgerVersion(int major, int minor) {
         this.major = major;
         this.minor = minor;
         this.patch = 0;
-        this.isPre_1_20 = false;
+        this.isPre_1_20_1 = false;
         this.hasPatch = false;
     }
     public HledgerVersion(int major, int minor, int patch) {
         this.major = major;
         this.minor = minor;
         this.patch = patch;
-        this.isPre_1_20 = false;
+        this.isPre_1_20_1 = false;
         this.hasPatch = true;
     }
-    public HledgerVersion(boolean pre_1_20) {
-        if (!pre_1_20)
-            throw new IllegalArgumentException("pre_1_20 argument must be true");
+    public HledgerVersion(boolean pre_1_20_1) {
+        if (!pre_1_20_1)
+            throw new IllegalArgumentException("pre_1_20_1 argument must be true");
         this.major = this.minor = this.patch = 0;
-        this.isPre_1_20 = true;
+        this.isPre_1_20_1 = true;
         this.hasPatch = false;
     }
     public HledgerVersion(HledgerVersion origin) {
         this.major = origin.major;
         this.minor = origin.minor;
-        this.isPre_1_20 = origin.isPre_1_20;
+        this.isPre_1_20_1 = origin.isPre_1_20_1;
         this.patch = origin.patch;
         this.hasPatch = origin.hasPatch;
     }
@@ -64,12 +66,12 @@ public class HledgerVersion {
             return false;
         HledgerVersion that = (HledgerVersion) obj;
 
-        return (this.isPre_1_20 == that.isPre_1_20 && this.major == that.major &&
+        return (this.isPre_1_20_1 == that.isPre_1_20_1 && this.major == that.major &&
                 this.minor == that.minor && this.patch == that.patch &&
                 this.hasPatch == that.hasPatch);
     }
-    public boolean isPre_1_20() {
-        return isPre_1_20;
+    public boolean isPre_1_20_1() {
+        return isPre_1_20_1;
     }
     public int getMajor() {
         return major;
@@ -83,9 +85,19 @@ public class HledgerVersion {
     @NonNull
     @Override
     public String toString() {
-        if (isPre_1_20)
+        if (isPre_1_20_1)
             return "(before 1.20)";
         return hasPatch ? String.format(Locale.ROOT, "%d.%d.%d", major, minor, patch)
                         : String.format(Locale.ROOT, "%d.%d", major, minor);
     }
+    public boolean atLeast(int major, int minor) {
+        return ((this.major == major) && (this.minor >= minor)) || (this.major > major);
+    }
+    @org.jetbrains.annotations.Nullable
+    public SendTransactionTask.API getSuitableApiVersion() {
+        if (isPre_1_20_1)
+            return null;
+
+        return SendTransactionTask.API.v1_19_1;
+    }
 }
index 55746dddd1279f803798357fd4441190ea5f9452..fcbd9203ef0852dcd3cf52d95e947ef0c3265155 100644 (file)
@@ -330,7 +330,7 @@ public final class MobileLedgerProfile {
                                  authEnabled ? authPassword : null, themeHue, orderNo,
                                  preferredAccountsFilter, futureDates.toInt(), apiVersion.toInt(),
                                  showCommodityByDefault, defaultCommodity, showCommentsByDefault,
-                                 (detectedVersion != null) && detectedVersion.isPre_1_20(),
+                                 (detectedVersion != null) && detectedVersion.isPre_1_20_1(),
                                  (detectedVersion == null) ? 0 : detectedVersion.getMajor(),
                                  (detectedVersion == null) ? 0 : detectedVersion.getMinor()
                     });
@@ -625,7 +625,7 @@ public final class MobileLedgerProfile {
             }
         }
 
-        private int value;
+        private final int value;
         FutureDates(int value) {
             this.value = value;
         }
index 94c21bf369dc85811611dce2cdaeef3d673f022a..9cb68cb85a49d146a37e538bfa0fc5cb171edfe5 100644 (file)
@@ -36,6 +36,7 @@ import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.appcompat.app.ActionBarDrawerToggle;
+import androidx.appcompat.app.AlertDialog;
 import androidx.appcompat.widget.Toolbar;
 import androidx.core.view.GravityCompat;
 import androidx.drawerlayout.widget.DrawerLayout;
@@ -237,7 +238,8 @@ public class MainActivity extends ProfileThemedActivity {
         findViewById(R.id.nav_new_profile_button).setOnClickListener(
                 v -> startEditProfileActivity(null));
 
-        findViewById(R.id.transaction_list_cancel_download).setOnClickListener(this::onStopTransactionRefreshClick);
+        findViewById(R.id.transaction_list_cancel_download).setOnClickListener(
+                this::onStopTransactionRefreshClick);
 
         RecyclerView root = findViewById(R.id.nav_profile_list);
         if (root == null)
@@ -619,9 +621,19 @@ public class MainActivity extends ProfileThemedActivity {
 
             mainModel.transactionRetrievalDone();
 
-            if (progress.getError() != null) {
-                Snackbar.make(mViewPager, progress.getError(), Snackbar.LENGTH_LONG)
-                        .show();
+            String error = progress.getError();
+            if (error != null) {
+                if (error.equals(RetrieveTransactionsTask.Result.ERR_JSON_PARSER_ERROR))
+                    error = getResources().getString(R.string.err_json_parser_error);
+
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                builder.setMessage(error);
+                builder.setPositiveButton(R.string.btn_profile_options, (dialog, which) -> {
+                    Logger.debug("error", "will start profile editor");
+                    startEditProfileActivity(profile);
+                });
+                builder.create()
+                       .show();
                 return;
             }
 
index 672acf0ec4a58cb37d7ba0a897c8065b9433feae..10f43667992fb27bfb17e5e74fe404230de26b92 100644 (file)
@@ -287,19 +287,23 @@ public class ProfileDetailFragment extends Fragment {
         context.findViewById(R.id.api_version_text)
                .setOnClickListener(this::chooseAPIVersion);
 
-        TextView detectedApiVersion = context.findViewById(R.id.detected_version_text);
+        context.findViewById(R.id.server_version_label)
+               .setOnClickListener(v -> model.triggerVersionDetection());
+        TextView detectedServerVersion = context.findViewById(R.id.detected_server_version_text);
         model.observeDetectedVersion(viewLifecycleOwner, ver -> {
             if (ver == null)
-                detectedApiVersion.setText(context.getResources()
-                                                  .getString(R.string.api_version_unknown_label));
-            else if (ver.isPre_1_20())
-                detectedApiVersion.setText(context.getResources()
-                                                  .getString(R.string.api_pre_1_19));
+                detectedServerVersion.setText(context.getResources()
+                                                     .getString(
+                                                             R.string.server_version_unknown_label));
+            else if (ver.isPre_1_20_1())
+                detectedServerVersion.setText(context.getResources()
+                                                     .getString(
+                                                             R.string.detected_server_pre_1_20_1));
             else
-                detectedApiVersion.setText(ver.toString());
+                detectedServerVersion.setText(ver.toString());
         });
-        detectedApiVersion.setOnClickListener(v -> model.triggerVersionDetection());
-        final View detectButton = context.findViewById(R.id.api_version_detect_button);
+        detectedServerVersion.setOnClickListener(v -> model.triggerVersionDetection());
+        final View detectButton = context.findViewById(R.id.server_version_detect_button);
         detectButton.setOnClickListener(v -> model.triggerVersionDetection());
         model.observeDetectingHledgerVersion(viewLifecycleOwner, running -> {
             detectButton.setVisibility(running ? View.VISIBLE : View.INVISIBLE);
@@ -394,11 +398,14 @@ public class ProfileDetailFragment extends Fragment {
                 case R.id.api_version_menu_html:
                     apiVer = SendTransactionTask.API.html;
                     break;
-                case R.id.api_version_menu_post_1_14:
-                    apiVer = SendTransactionTask.API.post_1_14;
+                case R.id.api_version_menu_1_19_1:
+                    apiVer = SendTransactionTask.API.v1_19_1;
                     break;
-                case R.id.api_version_menu_pre_1_15:
-                    apiVer = SendTransactionTask.API.pre_1_15;
+                case R.id.api_version_menu_1_15:
+                    apiVer = SendTransactionTask.API.v1_15;
+                    break;
+                case R.id.api_version_menu_1_14:
+                    apiVer = SendTransactionTask.API.v1_14;
                     break;
                 case R.id.api_version_menu_auto:
                 default:
index 83c4f22863a787214358dda2765ab62e52aa03af..46222f628b48ab4cd41677ce7f154018b99f6fbc 100644 (file)
         </LinearLayout>
 
         <androidx.constraintlayout.widget.ConstraintLayout
-            android:id="@+id/api_version_layout"
+            android:id="@+id/server_version_layout"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_marginBottom="16dp"
             >
 
             <TextView
-                android:id="@+id/api_version_label"
+                android:id="@+id/server_version_label"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:text="@string/profile_api_version_title"
+                android:text="@string/profile_server_version_title"
                 android:textAppearance="?android:textAppearanceListItem"
-                android:layout_marginEnd="24dp"
-                app:layout_constraintEnd_toStartOf="@id/detected_version_text"
+                app:layout_constraintEnd_toStartOf="@id/server_version_detect_button"
                 app:layout_constraintStart_toStartOf="parent"
                 app:layout_constraintTop_toTopOf="parent"
                 />
 
             <TextView
-                android:id="@+id/api_version_text"
+                android:id="@+id/detected_server_version_text"
                 android:layout_width="0dp"
                 android:layout_height="wrap_content"
-                android:textAppearance="?android:textAppearanceListItemSecondary"
-                android:textColor="?attr/textColor"
-                app:layout_constraintEnd_toStartOf="@id/detected_version_text"
-                android:layout_marginEnd="24dp"
-                app:layout_constraintStart_toStartOf="parent"
-                app:layout_constraintTop_toBottomOf="@id/api_version_label"
-                />
-            <TextView
-                android:id="@+id/detected_version_text"
-                android:layout_width="wrap_content"
-                android:layout_height="0dp"
                 android:layout_marginEnd="8dp"
-                android:text="@string/api_version_unknown_label"
+                android:gravity="start"
                 android:textAppearance="?android:textAppearanceListItemSecondary"
                 android:textColor="?attr/textColor"
-                app:layout_constraintEnd_toStartOf="@id/api_version_detect_button"
-                android:gravity="bottom"
+                android:text="@string/server_version_unknown_label"
+                app:layout_constraintEnd_toStartOf="@id/server_version_detect_button"
                 app:layout_constraintBottom_toBottomOf="parent"
-                app:layout_constraintTop_toTopOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@id/server_version_label"
                 />
             <ProgressBar
                 android:layout_height="24dp"
-                android:id="@+id/api_version_detect_button"
+                android:id="@+id/server_version_detect_button"
                 android:layout_width="24dp"
                 android:indeterminate="true"
                 android:foregroundGravity="bottom"
                 app:layout_constraintBottom_toBottomOf="parent"
                 app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toEndOf="@id/detected_server_version_text"
                 android:visibility="invisible"
                 />
         </androidx.constraintlayout.widget.ConstraintLayout>
 
+        <androidx.constraintlayout.widget.ConstraintLayout
+            android:id="@+id/api_version_layout"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_marginBottom="16dp"
+            >
+
+            <TextView
+                android:id="@+id/api_version_label"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="24dp"
+                android:text="@string/profile_api_version_title"
+                android:textAppearance="?android:textAppearanceListItem"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toTopOf="parent"
+                />
+
+            <TextView
+                android:id="@+id/api_version_text"
+                android:layout_width="0dp"
+                android:layout_height="wrap_content"
+                android:layout_marginEnd="24dp"
+                android:textAppearance="?android:textAppearanceListItemSecondary"
+                android:textColor="?attr/textColor"
+                app:layout_constraintEnd_toEndOf="parent"
+                app:layout_constraintStart_toStartOf="parent"
+                app:layout_constraintTop_toBottomOf="@id/api_version_label"
+                />
+        </androidx.constraintlayout.widget.ConstraintLayout>
+
         <com.google.android.material.switchmaterial.SwitchMaterial
             android:id="@+id/profile_permit_posting"
             android:layout_width="match_parent"
index 5fcb1de9b156a5125a984dc2d1707e0237353675..cdcb09f277b651f34a489fba7971566ea6aa0b5d 100644 (file)
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ Copyright © 2019 Damyan Ivanov.
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright © 2020 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
 
     <item
         android:id="@+id/api_version_menu_auto"
-        android:title="@string/api_auto" />
+        android:title="@string/api_auto"
+        />
     <item
-        android:id="@+id/api_version_menu_post_1_14"
-        android:title="@string/api_post_1_14" />
+        android:id="@+id/api_version_menu_1_19_1"
+        android:title="@string/api_1_19_1"
+        />
     <item
-        android:id="@+id/api_version_menu_pre_1_15"
-        android:title="@string/api_pre_1_15" />
+        android:id="@+id/api_version_menu_1_15"
+        android:title="@string/api_1_15"
+        />
+    <item
+        android:id="@+id/api_version_menu_1_14"
+        android:title="@string/api_1_14"
+        />
     <item
         android:id="@+id/api_version_menu_html"
-        android:title="@string/api_html" />
+        android:title="@string/api_html"
+        />
 </menu>
\ No newline at end of file
index 81623c5764114920bd97ea43bac4c5fada67a1b6..dbdbb99180d3896a3ce82f249beb9eadc1d2a6ed 100644 (file)
     <string name="future_dates_all">Без ограничения</string>
     <string name="future_dates_none">Без въвеждане на бъдещи дати</string>
     <string name="profile_future_dates_label">Въвеждане на дати в бъдещето</string>
-    <string name="api_auto">Ð\90вÑ\82омаÑ\82иÑ\87но Ð¾Ñ\82кÑ\80иване</string>
+    <string name="api_auto">Ð\90вÑ\82омаÑ\82иÑ\87на</string>
     <string name="api_html">Версия преди 1.14</string>
-    <string name="api_post_1_14">Версия 1.15 или по-нова</string>
-    <string name="api_pre_1_15">Версия 1.14.x</string>
-    <string name="profile_api_version_title">Версия на сървъра</string>
+    <string name="api_1_15">Версия 1.15</string>
+    <string name="api_1_14">Версия 1.14</string>
+    <string name="profile_api_version_title">Версия на протокола</string>
     <string name="add_button">Добавяне…</string>
     <string name="close_button">Затваряне</string>
     <string name="transaction_account_comment_hint">бележка</string>
     <string name="nav_header_desc">Заглавна част на страничния панел</string>
     <string name="transaction_count_summary">%,d движения към %s</string>
     <string name="account_count_summary">%,d сметки към %s</string>
-    <string name="api_version_unknown_label">Неизвестна</string>
-    <string name="api_pre_1_19">Преди 1.20.?</string>
+    <string name="server_version_unknown_label">Неизвестна</string>
+    <string name="detected_server_pre_1_20_1">Преди 1.20.1</string>
     <string name="detected_version_label">Открита версия</string>
     <string name="new_transaction_fab_description">Знак плюс</string>
+    <string name="api_1_19_1">Версия 1.19.1</string>
+    <string name="profile_server_version_title">Версия на сървъра</string>
+    <string name="err_json_parser_error">Грешка при разчитане на отговора от сървъра. Вероятно настроената врсия на протокола е грешна.</string>
+    <string name="btn_profile_options">Настройка на профила</string>
 </resources>
index 7c73afb7442e0011d40429d1d626f50767f9f817..ea7d15482180d3f559118e2b986baf624a32c92f 100644 (file)
     <string name="future_dates_365">Up to a year</string>
     <string name="future_dates_all">Without restrictions</string>
     <string name="api_html">Version before 1.14</string>
-    <string name="api_pre_1_15">Version 1.14.x</string>
-    <string name="api_post_1_14">Version 1.15 and above</string>
-    <string name="api_auto">Detect automatically</string>
-    <string name="profile_api_version_title">Backend server version</string>
+    <string name="api_1_14">Version 1.14</string>
+    <string name="api_1_15">Version 1.15</string>
+    <string name="api_auto">Automatic</string>
+    <string name="profile_api_version_title">Protocol version</string>
     <string name="currency_symbol" translatable="false">¤</string>
     <string name="add_button">Add…</string>
     <string name="close_button">Close</string>
     <string name="sub_accounts_expand_collapse_trigger_description">Sub-accounts expand/collapse trigger</string>
     <string name="transaction_count_summary">%,d transactions as of %s</string>
     <string name="account_count_summary">%,d accounts as of %s</string>
-    <string name="api_version_unknown_label">Unknown</string>
-    <string name="api_pre_1_19">Before 1.20.?</string>
+    <string name="server_version_unknown_label">Unknown</string>
+    <string name="detected_server_pre_1_20_1">Before 1.20.1</string>
     <string name="detected_version_label">Detected version</string>
     <string name="new_transaction_fab_description">Plus icon</string>
+    <string name="api_1_19_1">Version 1.19.1</string>
+    <string name="profile_server_version_title">Server version</string>
+    <string name="err_json_parser_error">Error parsing packend JSON response. Perhaps the configured API version doesn\'t match</string>
+    <string name="btn_profile_options">Configure profile</string>
 </resources>