]> git.ktnx.net Git - mobile-ledger.git/commitdiff
more pronounced day/month delimiters in the transaction list master
authorDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 31 Mar 2024 11:13:26 +0000 (14:13 +0300)
committerDamyan Ivanov <dam+mobileledger@ktnx.net>
Sun, 31 Mar 2024 11:13:26 +0000 (14:13 +0300)
26 files changed:
CHANGES.md
TODO.txt [new file with mode: 0644]
app/build.gradle
app/src/main/AndroidManifest.xml
app/src/main/java/net/ktnx/mobileledger/async/SendTransactionTask.java
app/src/main/java/net/ktnx/mobileledger/dao/AccountDAO.java
app/src/main/java/net/ktnx/mobileledger/model/AccountListItem.java
app/src/main/java/net/ktnx/mobileledger/model/LedgerAccount.java
app/src/main/java/net/ktnx/mobileledger/ui/MainModel.java
app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryAdapter.java
app/src/main/java/net/ktnx/mobileledger/ui/account_summary/AccountSummaryFragment.java
app/src/main/java/net/ktnx/mobileledger/ui/transaction_list/TransactionListDelimiterRowHolder.java
app/src/main/java/net/ktnx/mobileledger/utils/Colors.java
app/src/main/res/menu/account_list.xml [new file with mode: 0644]
app/src/main/res/values-bg/strings.xml
app/src/main/res/values/strings.xml
app/src/main/res/xml/network_security_config.xml
build.gradle
gradle.properties
gradle/wrapper/gradle-wrapper.properties
metadata/bg-BG/changelogs/54.txt [new file with mode: 0644]
metadata/bg-BG/changelogs/55.txt [new file with mode: 0644]
metadata/bg-BG/changelogs/56.txt [new file with mode: 0644]
metadata/en-US/changelogs/54.txt [new file with mode: 0644]
metadata/en-US/changelogs/55.txt [new file with mode: 0644]
metadata/en-US/changelogs/56.txt [new file with mode: 0644]

index 5bdb50310284ede3445ef1b201b1e53b39f00f95..02f84284cacf6943424f157b78ec8e114eb5dd6f 100644 (file)
@@ -1,5 +1,22 @@
 # Changes
 
 # Changes
 
+## [0.21.7] = 2024-03-19
+
+* FIXES:
+    + allow user certificates in network security config
+* OTHERS:
+    + bump gradle version
+
+## [0.21.6] - 2023-06-20
+
+* FIXES
+    + fix sending transations to hledger-web 1.23+
+
+## [0.21.5] - 2022-09-03
+
+* FIXES
+    + fix cloud backup
+
 ## [0.21.4] - 2022-06-18
 
 * FIXES
 ## [0.21.4] - 2022-06-18
 
 * FIXES
diff --git a/TODO.txt b/TODO.txt
new file mode 100644 (file)
index 0000000..e229e17
--- /dev/null
+++ b/TODO.txt
@@ -0,0 +1,7 @@
+* Easy way to add tag:value pairs to transactions and transaction accounts
+
+* Filter by tag:value pairs
+
+* Refresh button in account/transaction list
+
+* Top button in account/transaction list
index 056bb631ae9d18cb292e87025e29df5d796c1957..71673f6eb8dca03508bc0f12f40580f9893fda37 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2022 Damyan Ivanov.
+ * Copyright © 2023 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
  * 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
@@ -24,8 +24,8 @@ android {
         minSdkVersion 22
         targetSdkVersion 31
         vectorDrawables.useSupportLibrary true
         minSdkVersion 22
         targetSdkVersion 31
         vectorDrawables.useSupportLibrary true
-        versionCode 53
-        versionName '0.21.4'
+        versionCode 56
+        versionName '0.21.7'
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         javaCompileOptions {
             annotationProcessorOptions {
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
         javaCompileOptions {
             annotationProcessorOptions {
@@ -62,6 +62,7 @@ android {
     }
     buildFeatures.viewBinding = true
     buildToolsVersion '30.0.3'
     }
     buildFeatures.viewBinding = true
     buildToolsVersion '30.0.3'
+    namespace 'net.ktnx.mobileledger'
 }
 
 dependencies {
 }
 
 dependencies {
index 6d4948bc3f61e59f4f56eea1bc76c91bad420e4c..b17a1ecfcacfaec410eee37f6be145c34c967ac7 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?><!--
 <?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright © 2022 Damyan Ivanov.
+  ~ Copyright © 2024 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
   ~ 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
@@ -15,8 +15,7 @@
   ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   ~ along with MoLe. If not, see <https://www.gnu.org/licenses/>.
   -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:tools="http://schemas.android.com/tools"
-    package="net.ktnx.mobileledger">
+    xmlns:tools="http://schemas.android.com/tools">
 
     <uses-permission android:name="android.permission.INTERNET" />
 
 
     <uses-permission android:name="android.permission.INTERNET" />
 
index 79a58173f10e502d11dfbd752fcfdef355aeb4b3..0e700cca9a510be8e210fafccbe548b88c2a427a 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2023 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
  * 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
@@ -17,6 +17,8 @@
 
 package net.ktnx.mobileledger.async;
 
 
 package net.ktnx.mobileledger.async;
 
+import static net.ktnx.mobileledger.utils.Logger.debug;
+
 import android.util.Log;
 
 import net.ktnx.mobileledger.db.Profile;
 import android.util.Log;
 
 import net.ktnx.mobileledger.db.Profile;
@@ -45,8 +47,6 @@ import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static net.ktnx.mobileledger.utils.Logger.debug;
-
 /* TODO: get rid of the custom session/cookie and auth code?
  *       (the last problem with the POST was the missing content-length header)
  *       This will resolve itself when hledger-web 1.14+ is released with Debian/stable,
 /* TODO: get rid of the custom session/cookie and auth code?
  *       (the last problem with the POST was the missing content-length header)
  *       This will resolve itself when hledger-web 1.14+ is released with Debian/stable,
@@ -275,6 +275,7 @@ public class SendTransactionTask extends Thread {
                 case v1_14:
                 case v1_15:
                 case v1_19_1:
                 case v1_14:
                 case v1_15:
                 case v1_19_1:
+                case v1_23:
                     sendOK(profileApiVersion);
                     break;
                 default:
                     sendOK(profileApiVersion);
                     break;
                 default:
@@ -286,9 +287,7 @@ public class SendTransactionTask extends Thread {
             error = e.getMessage();
         }
 
             error = e.getMessage();
         }
 
-        Misc.onMainThread(()->{
-            taskCallback.onTransactionSaveDone(error, transaction);
-        });
+        Misc.onMainThread(() -> taskCallback.onTransactionSaveDone(error, transaction));
     }
     private void legacySendOkWithRetry() throws IOException {
         int tried = 0;
     }
     private void legacySendOkWithRetry() throws IOException {
         int tried = 0;
index 0c581787a30a2fac55c605674904eebdd7441995..5ad4c90fb4138487b9626648dd9b1191d19c188b 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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
@@ -78,12 +78,19 @@ public abstract class AccountDAO extends BaseDAO<Account> {
     @Query("DELETE FROM accounts")
     public abstract void deleteAllSync();
 
     @Query("DELETE FROM accounts")
     public abstract void deleteAllSync();
 
-    @Query("SELECT * FROM accounts WHERE profile_id=:profileId ORDER BY name")
-    public abstract LiveData<List<Account>> getAll(long profileId);
+    @Query("SELECT * FROM accounts WHERE profile_id=:profileId AND IIF(:includeZeroBalances=1, 1," +
+           " (EXISTS(SELECT 1 FROM account_values av WHERE av.account_id=accounts.id AND av.value" +
+           " <> 0) OR EXISTS(SELECT 1 FROM accounts a WHERE a.parent_name = accounts.name))) " +
+           "ORDER BY name")
+    public abstract LiveData<List<Account>> getAll(long profileId, boolean includeZeroBalances);
 
     @Transaction
 
     @Transaction
-    @Query("SELECT * FROM accounts WHERE profile_id = :profileId ORDER BY name")
-    public abstract LiveData<List<AccountWithAmounts>> getAllWithAmounts(long profileId);
+    @Query("SELECT * FROM accounts WHERE profile_id = :profileId AND IIF(:includeZeroBalances=1, " +
+           "1, (EXISTS(SELECT 1 FROM account_values av WHERE av.account_id=accounts.id AND av" +
+           ".value <> 0) OR EXISTS(SELECT 1 FROM accounts a WHERE a.parent_name = accounts.name))" +
+           ") ORDER BY name")
+    public abstract LiveData<List<AccountWithAmounts>> getAllWithAmounts(long profileId,
+                                                                         boolean includeZeroBalances);
 
     @Query("SELECT * FROM accounts WHERE id=:id")
     public abstract Account getByIdSync(long id);
 
     @Query("SELECT * FROM accounts WHERE id=:id")
     public abstract Account getByIdSync(long id);
index dfd3d982011a105191f5e801bea2fcc5e276c4d6..807e93d348b1e182d81090d94fc097b32cd4be8f 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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
@@ -34,12 +34,19 @@ public abstract class AccountListItem {
         else
             throw new RuntimeException("Unsupported sub-class " + this);
     }
         else
             throw new RuntimeException("Unsupported sub-class " + this);
     }
-    @NotNull
-    public LedgerAccount getAccount() {
-        if (this instanceof Account)
-            return ((Account) this).account;
-
-        throw new IllegalStateException(String.format("Item type is not Account, but %s", this));
+    public boolean isAccount() {
+        return this instanceof Account;
+    }
+    public Account toAccount() {
+        assert isAccount();
+        return ((Account) this);
+    }
+    public boolean isHeader() {
+        return this instanceof Header;
+    }
+    public Header toHeader() {
+        assert isHeader();
+        return ((Header) this);
     }
     public enum Type {ACCOUNT, HEADER}
 
     }
     public enum Type {ACCOUNT, HEADER}
 
@@ -59,6 +66,13 @@ public abstract class AccountListItem {
                    ((Account) other).account.getAmountsString()
                                             .equals(account.getAmountsString());
         }
                    ((Account) other).account.getAmountsString()
                                             .equals(account.getAmountsString());
         }
+        @NotNull
+        public LedgerAccount getAccount() {
+            return account;
+        }
+        public boolean allAmountsAreZero() {
+            return account.allAmountsAreZero();
+        }
     }
 
     public static class Header extends AccountListItem {
     }
 
     public static class Header extends AccountListItem {
index 1be684cf1b0d1bcb700485384a3a068963576610..c2e62772f5990ef911854c838218edde70e50f82 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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
@@ -201,13 +201,21 @@ public class LedgerAccount {
         if (amounts != null)
             amounts.clear();
     }
         if (amounts != null)
             amounts.clear();
     }
-    public boolean amountsExpanded() { return amountsExpanded; }
-    public void setAmountsExpanded(boolean flag) { amountsExpanded = flag; }
-    public void toggleAmountsExpanded() { amountsExpanded = !amountsExpanded; }
+    public boolean amountsExpanded() {return amountsExpanded;}
+    public void setAmountsExpanded(boolean flag) {amountsExpanded = flag;}
+    public void toggleAmountsExpanded() {amountsExpanded = !amountsExpanded;}
     public void propagateAmountsTo(LedgerAccount acc) {
         for (LedgerAmount a : amounts)
             a.propagateToAccount(acc);
     }
     public void propagateAmountsTo(LedgerAccount acc) {
         for (LedgerAmount a : amounts)
             a.propagateToAccount(acc);
     }
+    public boolean allAmountsAreZero() {
+        for (LedgerAmount a : amounts) {
+            if (a.getAmount() != 0)
+                return false;
+        }
+
+        return true;
+    }
     public List<LedgerAmount> getAmounts() {
         return amounts;
     }
     public List<LedgerAmount> getAmounts() {
         return amounts;
     }
index 329109fdccf3947f578e0eb2ac20a6abd58fcb14..a8b957dc330be48f6a304cce50bd5f5012468b11 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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
@@ -38,6 +38,7 @@ import java.util.Locale;
 public class MainModel extends ViewModel {
     public final MutableLiveData<Integer> foundTransactionItemIndex = new MutableLiveData<>(null);
     private final MutableLiveData<Boolean> updatingFlag = new MutableLiveData<>(false);
 public class MainModel extends ViewModel {
     public final MutableLiveData<Integer> foundTransactionItemIndex = new MutableLiveData<>(null);
     private final MutableLiveData<Boolean> updatingFlag = new MutableLiveData<>(false);
+    private final MutableLiveData<Boolean> showZeroBalanceAccounts = new MutableLiveData<>(true);
     private final MutableLiveData<String> accountFilter = new MutableLiveData<>(null);
     private final MutableLiveData<List<TransactionListItem>> displayedTransactions =
             new MutableLiveData<>(new ArrayList<>());
     private final MutableLiveData<String> accountFilter = new MutableLiveData<>(null);
     private final MutableLiveData<List<TransactionListItem>> displayedTransactions =
             new MutableLiveData<>(new ArrayList<>());
@@ -45,7 +46,6 @@ public class MainModel extends ViewModel {
     private SimpleDate firstTransactionDate;
     private SimpleDate lastTransactionDate;
     transient private RetrieveTransactionsTask retrieveTransactionsTask;
     private SimpleDate firstTransactionDate;
     private SimpleDate lastTransactionDate;
     transient private RetrieveTransactionsTask retrieveTransactionsTask;
-    transient private Thread displayedAccountsUpdater;
     private TransactionsDisplayedFilter displayedTransactionsUpdater;
     public LiveData<Boolean> getUpdatingFlag() {
         return updatingFlag;
     private TransactionsDisplayedFilter displayedTransactionsUpdater;
     public LiveData<Boolean> getUpdatingFlag() {
         return updatingFlag;
@@ -66,6 +66,7 @@ public class MainModel extends ViewModel {
     public void setFirstTransactionDate(SimpleDate earliestDate) {
         this.firstTransactionDate = earliestDate;
     }
     public void setFirstTransactionDate(SimpleDate earliestDate) {
         this.firstTransactionDate = earliestDate;
     }
+    public MutableLiveData<Boolean> getShowZeroBalanceAccounts() {return showZeroBalanceAccounts;}
     public MutableLiveData<String> getAccountFilter() {
         return accountFilter;
     }
     public MutableLiveData<String> getAccountFilter() {
         return accountFilter;
     }
@@ -81,6 +82,7 @@ public class MainModel extends ViewModel {
             return;
         }
         Profile profile = Data.getProfile();
             return;
         }
         Profile profile = Data.getProfile();
+        assert profile != null;
 
         retrieveTransactionsTask = new RetrieveTransactionsTask(profile);
         Logger.debug("db", "Created a background transaction retrieval task");
 
         retrieveTransactionsTask = new RetrieveTransactionsTask(profile);
         Logger.debug("db", "Created a background transaction retrieval task");
index d7da335d675a19da8e1c273f717badb72488ce0c..dcc16f3678ed3885605d4b85de77653f1f957b9c 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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
@@ -17,6 +17,8 @@
 
 package net.ktnx.mobileledger.ui.account_summary;
 
 
 package net.ktnx.mobileledger.ui.account_summary;
 
+import static net.ktnx.mobileledger.utils.Logger.debug;
+
 import android.content.res.Resources;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.content.res.Resources;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -48,8 +50,6 @@ import org.jetbrains.annotations.NotNull;
 import java.util.List;
 import java.util.Locale;
 
 import java.util.List;
 import java.util.Locale;
 
-import static net.ktnx.mobileledger.utils.Logger.debug;
-
 public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAdapter.RowHolder> {
     public static final int AMOUNT_LIMIT = 3;
     private static final int ITEM_TYPE_HEADER = 1;
 public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAdapter.RowHolder> {
     public static final int AMOUNT_LIMIT = 3;
     private static final int ITEM_TYPE_HEADER = 1;
@@ -66,8 +66,10 @@ public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAd
                                            @NonNull AccountListItem newItem) {
                 Change changes = new Change();
 
                                            @NonNull AccountListItem newItem) {
                 Change changes = new Change();
 
-                final LedgerAccount oldAcc = oldItem.getAccount();
-                final LedgerAccount newAcc = newItem.getAccount();
+                final LedgerAccount oldAcc = oldItem.toAccount()
+                                                    .getAccount();
+                final LedgerAccount newAcc = newItem.toAccount()
+                                                    .getAccount();
 
                 if (!Misc.equalStrings(oldAcc.getName(), newAcc.getName()))
                     changes.add(Change.NAME);
 
                 if (!Misc.equalStrings(oldAcc.getName(), newAcc.getName()))
                     changes.add(Change.NAME);
@@ -97,8 +99,10 @@ public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAd
                 if (oldType == AccountListItem.Type.HEADER)
                     return true;
 
                 if (oldType == AccountListItem.Type.HEADER)
                     return true;
 
-                return oldItem.getAccount()
-                              .getId() == newItem.getAccount()
+                return oldItem.toAccount()
+                              .getAccount()
+                              .getId() == newItem.toAccount()
+                                                 .getAccount()
                                                  .getId();
             }
             @Override
                                                  .getId();
             }
             @Override
@@ -114,6 +118,7 @@ public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAd
             return 0;
         return listDiffer.getCurrentList()
                          .get(position)
             return 0;
         return listDiffer.getCurrentList()
                          .get(position)
+                         .toAccount()
                          .getAccount()
                          .getId();
     }
                          .getAccount()
                          .getId();
     }
@@ -258,6 +263,7 @@ public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAd
         private LedgerAccount getAccount() {
             return listDiffer.getCurrentList()
                              .get(getBindingAdapterPosition())
         private LedgerAccount getAccount() {
             return listDiffer.getCurrentList()
                              .get(getBindingAdapterPosition())
+                             .toAccount()
                              .getAccount();
         }
         private void toggleAmountsExpanded() {
                              .getAccount();
         }
         private void toggleAmountsExpanded() {
@@ -301,7 +307,8 @@ public class AccountSummaryAdapter extends RecyclerView.Adapter<AccountSummaryAd
         }
         @Override
         public void bind(AccountListItem item, @Nullable List<Object> payloads) {
         }
         @Override
         public void bind(AccountListItem item, @Nullable List<Object> payloads) {
-            LedgerAccount acc = item.getAccount();
+            LedgerAccount acc = item.toAccount()
+                                    .getAccount();
 
             Change changes = new Change();
             if (payloads != null) {
 
             Change changes = new Change();
             if (payloads != null) {
index 35a9edb7205c84bd16889468d90416b6018d547b..807c16daf8540af877827e2729d0e848f733d3c3 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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.ui.account_summary;
 
 
 package net.ktnx.mobileledger.ui.account_summary;
 
+import static net.ktnx.mobileledger.utils.Logger.debug;
+
 import android.content.Context;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.content.Context;
 import android.os.Bundle;
 import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 
 import android.view.View;
 import android.view.ViewGroup;
 
@@ -31,6 +36,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
 import androidx.recyclerview.widget.RecyclerView;
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
+import net.ktnx.mobileledger.R;
 import net.ktnx.mobileledger.async.GeneralBackgroundTasks;
 import net.ktnx.mobileledger.databinding.AccountSummaryFragmentBinding;
 import net.ktnx.mobileledger.db.AccountWithAmounts;
 import net.ktnx.mobileledger.async.GeneralBackgroundTasks;
 import net.ktnx.mobileledger.databinding.AccountSummaryFragmentBinding;
 import net.ktnx.mobileledger.db.AccountWithAmounts;
@@ -51,11 +57,11 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 
 import java.util.HashMap;
 import java.util.List;
 
-import static net.ktnx.mobileledger.utils.Logger.debug;
-
 public class AccountSummaryFragment extends MobileLedgerListFragment {
     public AccountSummaryAdapter modelAdapter;
     private AccountSummaryFragmentBinding b;
 public class AccountSummaryFragment extends MobileLedgerListFragment {
     public AccountSummaryAdapter modelAdapter;
     private AccountSummaryFragmentBinding b;
+    private MenuItem menuShowZeroBalances;
+    private MainModel model;
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
     @Override
     public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -82,7 +88,7 @@ public class AccountSummaryFragment extends MobileLedgerListFragment {
         debug("flow", "AccountSummaryFragment.onActivityCreated()");
         super.onViewCreated(view, savedInstanceState);
 
         debug("flow", "AccountSummaryFragment.onActivityCreated()");
         super.onViewCreated(view, savedInstanceState);
 
-        MainModel model = new ViewModelProvider(requireActivity()).get(MainModel.class);
+        model = new ViewModelProvider(requireActivity()).get(MainModel.class);
 
         Data.backgroundTasksRunning.observe(this.getViewLifecycleOwner(),
                 this::onBackgroundTaskRunningChanged);
 
         Data.backgroundTasksRunning.observe(this.getViewLifecycleOwner(),
                 this::onBackgroundTaskRunningChanged);
@@ -109,15 +115,40 @@ public class AccountSummaryFragment extends MobileLedgerListFragment {
             model.scheduleTransactionListRetrieval();
         });
 
             model.scheduleTransactionListRetrieval();
         });
 
-        Data.observeProfile(this, this::onProfileChanged);
+        Data.observeProfile(this, profile -> onProfileChanged(profile, Boolean.TRUE.equals(
+                model.getShowZeroBalanceAccounts()
+                     .getValue())));
+    }
+    @Override
+    public void onCreateOptionsMenu(@NotNull Menu menu, @NotNull MenuInflater inflater) {
+        inflater.inflate(R.menu.account_list, menu);
+
+        menuShowZeroBalances = menu.findItem(R.id.menu_account_list_show_zero_balances);
+        if ((menuShowZeroBalances == null))
+            throw new AssertionError();
+
+        menuShowZeroBalances.setOnMenuItemClickListener(menuItem -> {
+            model.getShowZeroBalanceAccounts()
+                 .setValue(Boolean.FALSE.equals(model.getShowZeroBalanceAccounts()
+                                                     .getValue()));
+            return true;
+        });
+
+        model.getShowZeroBalanceAccounts()
+             .observe(this, v -> {
+                 menuShowZeroBalances.setChecked(v);
+                 onProfileChanged(Data.getProfile(), v);
+             });
+
+        super.onCreateOptionsMenu(menu, inflater);
     }
     }
-    private void onProfileChanged(Profile profile) {
+    private void onProfileChanged(Profile profile, boolean showZeroBalanceAccounts) {
         if (profile == null)
             return;
 
         DB.get()
           .getAccountDAO()
         if (profile == null)
             return;
 
         DB.get()
           .getAccountDAO()
-          .getAllWithAmounts(profile.getId())
+          .getAllWithAmounts(profile.getId(), showZeroBalanceAccounts)
           .observe(getViewLifecycleOwner(), list -> GeneralBackgroundTasks.run(() -> {
               List<AccountListItem> adapterList = new ArrayList<>();
               adapterList.add(new AccountListItem.Header(Data.lastAccountsUpdateText));
           .observe(getViewLifecycleOwner(), list -> GeneralBackgroundTasks.run(() -> {
               List<AccountListItem> adapterList = new ArrayList<>();
               adapterList.add(new AccountListItem.Header(Data.lastAccountsUpdateText));
@@ -134,8 +165,57 @@ public class AccountSummaryFragment extends MobileLedgerListFragment {
                       adapterList.add(new AccountListItem.Account(account));
                   accMap.put(dbAcc.account.getName(), account);
               }
                       adapterList.add(new AccountListItem.Account(account));
                   accMap.put(dbAcc.account.getName(), account);
               }
+
+              if (!showZeroBalanceAccounts) {
+                  removeZeroAccounts(adapterList);
+              }
               modelAdapter.setAccounts(adapterList);
               Data.lastUpdateAccountCount.postValue(adapterList.size() - 1);
           }));
     }
               modelAdapter.setAccounts(adapterList);
               Data.lastUpdateAccountCount.postValue(adapterList.size() - 1);
           }));
     }
+    private void removeZeroAccounts(List<AccountListItem> list) {
+        boolean removed = true;
+
+        while (removed) {
+            AccountListItem last = null;
+            removed = false;
+            List<AccountListItem> newList = new ArrayList<>();
+
+            for (AccountListItem item : list) {
+                if (last == null) {
+                    last = item;
+                    continue;
+                }
+
+                if (!last.isAccount() || !last.toAccount()
+                                              .allAmountsAreZero() || last.toAccount()
+                                                                          .getAccount()
+                                                                          .isParentOf(
+                                                                                  item.toAccount()
+                                                                                      .getAccount()))
+                {
+                    newList.add(last);
+                }
+                else {
+                    removed = true;
+                }
+
+                last = item;
+            }
+
+            if (last != null) {
+                if (!last.isAccount() || !last.toAccount()
+                                              .allAmountsAreZero())
+                {
+                    newList.add(last);
+                }
+                else {
+                    removed = true;
+                }
+            }
+
+            list.clear();
+            list.addAll(newList);
+        }
+    }
 }
 }
index 390b4941719c2eca9b5d4c4e992086131ac3525e..b5fe883d14a74cc2d92cf308d6382838155b3bb0 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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,9 +19,12 @@ package net.ktnx.mobileledger.ui.transaction_list;
 
 import android.view.View;
 
 
 import android.view.View;
 
+import androidx.constraintlayout.widget.ConstraintLayout;
+
 import net.ktnx.mobileledger.App;
 import net.ktnx.mobileledger.databinding.TransactionDelimiterBinding;
 import net.ktnx.mobileledger.model.TransactionListItem;
 import net.ktnx.mobileledger.App;
 import net.ktnx.mobileledger.databinding.TransactionDelimiterBinding;
 import net.ktnx.mobileledger.model.TransactionListItem;
+import net.ktnx.mobileledger.utils.DimensionUtils;
 import net.ktnx.mobileledger.utils.Globals;
 import net.ktnx.mobileledger.utils.SimpleDate;
 
 import net.ktnx.mobileledger.utils.Globals;
 import net.ktnx.mobileledger.utils.SimpleDate;
 
@@ -46,15 +49,21 @@ class TransactionListDelimiterRowHolder extends TransactionRowHolderBase {
             b.transactionDelimiterMonth.setText(
                     Globals.monthNames[cal.get(GregorianCalendar.MONTH)]);
             b.transactionDelimiterMonth.setVisibility(View.VISIBLE);
             b.transactionDelimiterMonth.setText(
                     Globals.monthNames[cal.get(GregorianCalendar.MONTH)]);
             b.transactionDelimiterMonth.setVisibility(View.VISIBLE);
-            //                holder.vDelimiterLine.setBackgroundResource(R.drawable
-            //                .dashed_border_8dp);
             b.transactionDelimiterThick.setVisibility(View.VISIBLE);
             b.transactionDelimiterThick.setVisibility(View.VISIBLE);
+            ConstraintLayout.LayoutParams lp =
+                    (ConstraintLayout.LayoutParams) b.transactionDelimiterThick.getLayoutParams();
+            lp.height = DimensionUtils.dp2px(b.getRoot()
+                                              .getContext(), 4);
+            b.transactionDelimiterThick.setLayoutParams(lp);
         }
         else {
             b.transactionDelimiterMonth.setVisibility(View.GONE);
         }
         else {
             b.transactionDelimiterMonth.setVisibility(View.GONE);
-            //                holder.vDelimiterLine.setBackgroundResource(R.drawable
-            //                .dashed_border_1dp);
-            b.transactionDelimiterThick.setVisibility(View.GONE);
+            ConstraintLayout.LayoutParams lp =
+                    (ConstraintLayout.LayoutParams) b.transactionDelimiterThick.getLayoutParams();
+            lp.height = DimensionUtils.dp2px(b.getRoot()
+                                              .getContext(), 1.3f);
+            b.transactionDelimiterThick.setLayoutParams(lp);
+            b.transactionDelimiterThick.setVisibility(View.VISIBLE);
         }
 
     }
         }
 
     }
index 7cf710ac0067b3b90319190c4f5524679beb38b6..348a5598a324073ea2415f353cd32a1019b72542 100644 (file)
@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2024 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
  * 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
@@ -17,6 +17,8 @@
 
 package net.ktnx.mobileledger.utils;
 
 
 package net.ktnx.mobileledger.utils;
 
+import static net.ktnx.mobileledger.utils.Logger.debug;
+
 import android.app.Activity;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.app.Activity;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -38,8 +40,6 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
 
 import java.util.Locale;
 import java.util.Objects;
 
-import static net.ktnx.mobileledger.utils.Logger.debug;
-
 public class Colors {
     public static final int DEFAULT_HUE_DEG = 261;
     public static final MutableLiveData<Integer> themeWatch = new MutableLiveData<>(0);
 public class Colors {
     public static final int DEFAULT_HUE_DEG = 261;
     public static final MutableLiveData<Integer> themeWatch = new MutableLiveData<>(0);
@@ -76,7 +76,7 @@ public class Colors {
         TypedValue tv = new TypedValue();
         theme.resolveAttribute(R.attr.table_row_dark_bg, tv, true);
         tableRowDarkBG = tv.data;
         TypedValue tv = new TypedValue();
         theme.resolveAttribute(R.attr.table_row_dark_bg, tv, true);
         tableRowDarkBG = tv.data;
-        theme.resolveAttribute(R.attr.colorPrimary, tv, true);
+        theme.resolveAttribute(androidx.appcompat.R.attr.colorPrimary, tv, true);
         primary = tv.data;
 
         if (themePrimaryColor.size() == 0) {
         primary = tv.data;
 
         if (themePrimaryColor.size() == 0) {
@@ -84,7 +84,7 @@ public class Colors {
                 Resources.Theme tmpTheme = theme.getResources()
                                                 .newTheme();
                 tmpTheme.applyStyle(themeId, true);
                 Resources.Theme tmpTheme = theme.getResources()
                                                 .newTheme();
                 tmpTheme.applyStyle(themeId, true);
-                tmpTheme.resolveAttribute(R.attr.colorPrimary, tv, false);
+                tmpTheme.resolveAttribute(androidx.appcompat.R.attr.colorPrimary, tv, false);
                 themePrimaryColor.put(themeId, tv.data);
             }
         }
                 themePrimaryColor.put(themeId, tv.data);
             }
         }
@@ -180,7 +180,7 @@ public class Colors {
                         huesSB.append(", ");
                     huesSB.append(h);
                 }
                         huesSB.append(", ");
                     huesSB.append(h);
                 }
-                debug("profiles", String.format("used hues: %s", huesSB.toString()));
+                debug("profiles", String.format("used hues: %s", huesSB));
             }
             hues.add(hues.get(0));
 
             }
             hues.add(hues.get(0));
 
diff --git a/app/src/main/res/menu/account_list.xml b/app/src/main/res/menu/account_list.xml
new file mode 100644 (file)
index 0000000..5a76161
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+  ~ Copyright © 2024 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/>.
+  -->
+
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    >
+
+    <item
+        android:id="@+id/menu_account_list_show_zero_balances"
+        android:checkable="true"
+        android:enabled="true"
+        android:menuCategory="container"
+        android:title="@string/accounts_menu_show_zero"
+        android:titleCondensed="@string/accounts_menu_show_zero_condensed"
+        android:visible="true"
+        app:showAsAction="withText"
+        />
+</menu>
\ No newline at end of file
index 4ba6fe385256fd8800789ee1d432d21e7861b36a..ccb47516c7ce94db047f23881c99479810dc84c8 100644 (file)
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright © 2021 Damyan Ivanov.
+  ~ Copyright © 2024 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
   ~ 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
     <string name="no_profile_restore_hint">… а може и да възстановите настройките от резервно копие</string>
     <string name="profile_not_available">Недостъпен профил</string>
     <string name="api_1_23">Версия 1.23</string>
     <string name="no_profile_restore_hint">… а може и да възстановите настройките от резервно копие</string>
     <string name="profile_not_available">Недостъпен профил</string>
     <string name="api_1_23">Версия 1.23</string>
+    <string name="accounts_menu_show_zero">Сметки с нулев баланс</string>
+    <string name="accounts_menu_show_zero_condensed">Нулеви сметки</string>
 </resources>
 </resources>
index d4fec3ac4f274ac8f9043784ab829101603aebc8..52d84690005411a968feef747c3b8d94bf881da9 100644 (file)
@@ -1,5 +1,5 @@
 <!--
 <!--
-  ~ Copyright © 2021 Damyan Ivanov.
+  ~ Copyright © 2024 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
   ~ 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
     <string name="no_profile_restore_hint">… or, you may restore from backup</string>
     <string name="profile_not_available">Profile not available</string>
     <string name="api_1_23">Version 1.23</string>
     <string name="no_profile_restore_hint">… or, you may restore from backup</string>
     <string name="profile_not_available">Profile not available</string>
     <string name="api_1_23">Version 1.23</string>
+    <string name="accounts_menu_show_zero">Show zero balances</string>
+    <string name="accounts_menu_show_zero_condensed">Zero balances</string>
 </resources>
 </resources>
index 223e12e8fbcb0f28f1559e621f1ebf197a23dbc2..c1da32275828ef31c0ccca046348a72b5a50e47f 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?><!--
 <?xml version="1.0" encoding="utf-8"?><!--
-  ~ Copyright © 2019 Damyan Ivanov.
+  ~ Copyright © 2024 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
   ~ 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
   -->
 
 <network-security-config>
   -->
 
 <network-security-config>
-    <base-config cleartextTrafficPermitted="true" />
+    <base-config cleartextTrafficPermitted="true">
+        <trust-anchors>
+            <certificates src="system" />
+            <certificates src="user" />
+        </trust-anchors>
+    </base-config>
 </network-security-config>
\ No newline at end of file
 </network-security-config>
\ No newline at end of file
index acc8190a2f325dc1294955ee400cfe018b3b5776..e9d71576e71beaaba39d96d67f402a45e9f63e69 100644 (file)
@@ -24,7 +24,7 @@ buildscript {
         mavenCentral()
     }
     dependencies {
         mavenCentral()
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:7.1.2'
+        classpath 'com.android.tools.build:gradle:8.0.2'
         
 
         // NOTE: Do not place your application dependencies here; they belong
         
 
         // NOTE: Do not place your application dependencies here; they belong
index 048e816edeb7bd5d8292f38228ae641cf4edf448..db96c7725ba87fd8ea2d7a50722e54fe5ebacccf 100644 (file)
@@ -1,5 +1,5 @@
 #
 #
-# Copyright © 2019 Damyan Ivanov.
+# Copyright © 2024 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
 # 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
 # along with MoLe. If not, see <https://www.gnu.org/licenses/>.
 #
 
 # along with MoLe. If not, see <https://www.gnu.org/licenses/>.
 #
 
-# Project-wide Gradle settings.
-# IDE (e.g. Android Studio) users:
-# Gradle settings configured through the IDE *will override*
-# any settings specified in this file.
-# For more details on how to configure your build environment visit
+## For more details on how to configure your build environment visit
 # http://www.gradle.org/docs/current/userguide/build_environment.html
 # http://www.gradle.org/docs/current/userguide/build_environment.html
+#
 # Specifies the JVM arguments used for the daemon process.
 # The setting is particularly useful for tweaking memory settings.
 # Specifies the JVM arguments used for the daemon process.
 # The setting is particularly useful for tweaking memory settings.
-org.gradle.jvmargs=-Xmx1536m
+# Default value: -Xmx1024m -XX:MaxPermSize=256m
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
+#
 # When configured, Gradle will run in incubating parallel mode.
 # This option should only be used with decoupled projects. More details, visit
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 # org.gradle.parallel=true
 # When configured, Gradle will run in incubating parallel mode.
 # This option should only be used with decoupled projects. More details, visit
 # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
 # org.gradle.parallel=true
+#Sun Mar 17 11:29:00 EET 2024
 android.debug.obsoleteApi=true
 android.debug.obsoleteApi=true
+android.defaults.buildfeatures.buildconfig=true
+android.enableJetifier=false
+android.enableR8.fullMode=false
+android.nonFinalResIds=false
+android.nonTransitiveRClass=true
 android.useAndroidX=true
 android.useAndroidX=true
-android.enableJetifier=true
\ No newline at end of file
+org.gradle.jvmargs=-Xmx1024M -Dkotlin.daemon.jvm.options\="-Xmx1536M"
+org.gradle.unsafe.configuration-cache=true
index 08b1a0c0f020a68d20ab5b7322042a95c70ebdbb..855f89cc8328ec83f5f1cf99a034a4c0aa8cd550 100644 (file)
@@ -1,6 +1,21 @@
-#Sat Nov 28 08:24:27 EET 2020
+#
+# Copyright © 2024 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/>.
+#
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
diff --git a/metadata/bg-BG/changelogs/54.txt b/metadata/bg-BG/changelogs/54.txt
new file mode 100644 (file)
index 0000000..2e1dace
--- /dev/null
@@ -0,0 +1,2 @@
+* ПОПРАВКИ
+    + отстранен проблем с централизираното резервно копие на настройките
diff --git a/metadata/bg-BG/changelogs/55.txt b/metadata/bg-BG/changelogs/55.txt
new file mode 100644 (file)
index 0000000..208db92
--- /dev/null
@@ -0,0 +1,2 @@
+* ПОПРАВКИ
+    + отстранен проблем при изпращане на транзакции към hledger-web 1.23+
diff --git a/metadata/bg-BG/changelogs/56.txt b/metadata/bg-BG/changelogs/56.txt
new file mode 100644 (file)
index 0000000..218ba4a
--- /dev/null
@@ -0,0 +1,4 @@
+* ПОПРАВКИ
+    + Позволяване на потребителски сертификати в настройките за сигурността на мрежовите връзки
+* ДРУГИ
+    + Обновена версия на gradle
diff --git a/metadata/en-US/changelogs/54.txt b/metadata/en-US/changelogs/54.txt
new file mode 100644 (file)
index 0000000..a2e3a20
--- /dev/null
@@ -0,0 +1,2 @@
+* FIXES
+    + fix cloud backup
diff --git a/metadata/en-US/changelogs/55.txt b/metadata/en-US/changelogs/55.txt
new file mode 100644 (file)
index 0000000..3697ab5
--- /dev/null
@@ -0,0 +1,2 @@
+* FIXES:
+    + fixed sending of transactions to hledger-web 1.23+
diff --git a/metadata/en-US/changelogs/56.txt b/metadata/en-US/changelogs/56.txt
new file mode 100644 (file)
index 0000000..9b7d3ac
--- /dev/null
@@ -0,0 +1,4 @@
+* FIXES:
+    + allow user certificates in network security config
+* OTHERS:
+    + bump gradle version