# Changes
-## [0.21.2] = 2022-04-04
+## [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
+ + fix compatibility wuth hledger-web 1.23+ when submitting new transactions. Thanks to Faye Duxovni for the patch!
+ + fix a crash when deleting templates
+ + fix a rare crash when submitting transactions with multiple accounts with no amounts with zero remaining balance
+
+## [0.21.3] - 2022-04-06
+
+* FIXES
+ + sync gradle version requirements
+* OTHERS
+ + bump version of several dependent libraries
+ + bump SDK version to 31
+ + adjust deprecated constructor usage
+
+## [0.21.2] - 2022-04-04
* FIXES
+ fix crash when auto-balancing multi currency transaction
--- /dev/null
+* 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
/*
- * 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
minSdkVersion 22
targetSdkVersion 31
vectorDrawables.useSupportLibrary true
- versionCode 51
- versionName '0.21.2'
+ versionCode 56
+ versionName '0.21.7'
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
}
buildFeatures.viewBinding = true
buildToolsVersion '30.0.3'
+ namespace 'net.ktnx.mobileledger'
}
dependencies {
<?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
~ 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" />
android:name=".App"
android:allowBackup="true"
android:appCategory="productivity"
- android:fullBackupContent="@xml/backup_descriptor"
android:icon="@drawable/app_icon"
android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@drawable/app_icon_round"
android:supportsRtl="true"
- android:backupAgent="net.ktnx.mobileledger.backup.MobileLedgerBackupAgent"
+ android:backupAgent=".backup.MobileLedgerBackupAgent"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".BackupsActivity"
/*
- * 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
package net.ktnx.mobileledger.async;
+import static net.ktnx.mobileledger.utils.Logger.debug;
+
import android.util.Log;
import net.ktnx.mobileledger.db.Profile;
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,
case v1_14:
case v1_15:
case v1_19_1:
+ case v1_23:
sendOK(profileApiVersion);
break;
default:
error = e.getMessage();
}
- Misc.onMainThread(()->{
- taskCallback.onTransactionSaveDone(error, transaction);
- });
+ Misc.onMainThread(() -> taskCallback.onTransactionSaveDone(error, transaction));
}
private void legacySendOkWithRetry() throws IOException {
int tried = 0;
/*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2022 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.backup;
-import android.app.backup.BackupAgentHelper;
+import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.os.ParcelFileDescriptor;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
-class MobileLedgerBackupAgent extends BackupAgentHelper {
+public class MobileLedgerBackupAgent extends BackupAgent {
private static final int READ_BUF_LEN = 10;
public static String SETTINGS_KEY = "settings";
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
- super.onBackup(oldState, data, newState);
+ Logger.debug("backup", "onBackup()");
backupSettings(data);
newState.close();
}
import android.util.JsonReader;
import android.util.JsonToken;
+import net.ktnx.mobileledger.App;
import net.ktnx.mobileledger.backup.ConfigIO.Keys;
import net.ktnx.mobileledger.dao.CurrencyDAO;
import net.ktnx.mobileledger.dao.ProfileDAO;
import net.ktnx.mobileledger.db.TemplateAccount;
import net.ktnx.mobileledger.db.TemplateHeader;
import net.ktnx.mobileledger.db.TemplateWithAccounts;
+import net.ktnx.mobileledger.model.Data;
+import net.ktnx.mobileledger.utils.Logger;
import java.io.BufferedReader;
import java.io.IOException;
restoreCommodities();
restoreProfiles();
restoreTemplates();
+ restoreCurrentProfile();
}
private void restoreTemplates() {
if (templates == null)
dao.insert(c);
}
}
+ private void restoreCurrentProfile() {
+ if (currentProfile == null) {
+ Logger.debug("backup", "Not restoring current profile (not present in backup)");
+ return;
+ }
+
+ ProfileDAO dao = DB.get()
+ .getProfileDAO();
+
+ Profile p = dao.getByUuidSync(currentProfile);
+
+ if (p != null) {
+ Logger.debug("backup", "Restoring current profile "+p.getName());
+ Data.postCurrentProfile(p);
+ App.storeStartupProfileAndTheme(p.getId(), p.getTheme());
+ }
+ else {
+ Logger.debug("backup", "Not restoring profile "+currentProfile+": not found in DB");
+ }
+ }
}
private List<List<String>> ttags = new ArrayList<>();
private List<ParsedSourcePos> tsourcepos = new ArrayList<>();
public ParsedLedgerTransaction() {
+ ParsedSourcePos startPos = new ParsedSourcePos();
+ ParsedSourcePos endPos = new ParsedSourcePos();
+ endPos.setSourceLine(2);
+
+ tsourcepos.add(startPos);
+ tsourcepos.add(endPos);
}
public static ParsedLedgerTransaction fromLedgerTransaction(LedgerTransaction tr) {
ParsedLedgerTransaction result = new ParsedLedgerTransaction();
ParsedStyle style = new ParsedStyle();
style.setAscommodityside(getCommoditySide());
style.setAscommodityspaced(getCommoditySpaced());
- style.setAsprecision(new ParsedPrecision(2));
+ style.setAsprecision(2);
style.setAsdecimalpoint('.');
amt.setAstyle(style);
if (acc.getCurrency() != null)
+++ /dev/null
-/*
- * 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_23;
-
-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;
- }
-}
package net.ktnx.mobileledger.json.v1_23;
class ParsedSourcePos {
- private String sourceName;
- private int sourceLine;
- private int sourceColumn;
+ private String sourceName = "";
+ private int sourceLine = 1;
+ private int sourceColumn = 1;
public ParsedSourcePos() {
}
public String getSourceName() {
@JsonIgnoreProperties(ignoreUnknown = true)
public class ParsedStyle extends net.ktnx.mobileledger.json.ParsedStyle {
- private ParsedPrecision asprecision;
+ private int asprecision;
public ParsedStyle() {
}
- public ParsedPrecision getAsprecision() {
+ public int getAsprecision() {
return asprecision;
}
- public void setAsprecision(ParsedPrecision asprecision) {
+ public void setAsprecision(int asprecision) {
this.asprecision = asprecision;
}
}
if (emptyAmountAccounts.size() > 0) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
emptyAmountAccounts.forEach((currency, accounts) -> {
- if (accounts.size() != 1)
+ final Float balance = emptyAmountAccountBalance.get(currency);
+
+ if (balance != null && !Misc.isZero(balance) && accounts.size() != 1) {
throw new RuntimeException(String.format(Locale.US,
- "Should not happen: approved transaction has %d accounts for " +
- "currency %s", accounts.size(), currency));
- accounts.get(0)
- .setAmount(-Objects.requireNonNull(
- emptyAmountAccountBalance.get(currency)));
+ "Should not happen: approved transaction has %d accounts " +
+ "without amounts for currency '%s'", accounts.size(), currency));
+ }
+ accounts.forEach(acc -> acc.setAmount(balance == null ? 0 : -balance));
});
}
else {
for (String currency : emptyAmountAccounts.keySet()) {
List<LedgerTransactionAccount> accounts =
Objects.requireNonNull(emptyAmountAccounts.get(currency));
-
- if (accounts.size() != 1)
+ final Float balance = emptyAmountAccountBalance.get(currency);
+ if (balance != null && !Misc.isZero(balance) && accounts.size() != 1)
throw new RuntimeException(String.format(Locale.US,
"Should not happen: approved transaction has %d accounts for " +
"currency %s", accounts.size(), currency));
- accounts.get(0)
- .setAmount(-Objects.requireNonNull(
- emptyAmountAccountBalance.get(currency)));
+ for (LedgerTransactionAccount acc : accounts) {
+ acc.setAmount(balance == null ? 0 : -balance);
+ }
}
}
}
/*
- * Copyright © 2021 Damyan Ivanov.
+ * Copyright © 2022 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
* along with MoLe. If not, see <https://www.gnu.org/licenses/>.
*/
-//
-// Substantial portions taken from DividerItemDecoration subject to the following license terms:
-//
-// Copyright 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
package net.ktnx.mobileledger.ui.templates;
import android.content.Context;
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final int childAdapterPosition = parent.getChildAdapterPosition(child);
- if (adapter.getItemViewType(childAdapterPosition) ==
+ if (childAdapterPosition == RecyclerView.NO_POSITION ||
+ adapter.getItemViewType(childAdapterPosition) ==
TemplatesRecyclerViewAdapter.ITEM_TYPE_DIVIDER ||
childAdapterPosition + 1 < itemCount &&
adapter.getItemViewType(childAdapterPosition + 1) ==
}
private void drawHorizontal(Canvas canvas, RecyclerView parent) {
+ final RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
+ if (layoutManager == null)
+ return;
+
canvas.save();
final int top;
final int bottom;
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final int childAdapterPosition = parent.getChildAdapterPosition(child);
- if (adapter.getItemViewType(childAdapterPosition) ==
+ if (childAdapterPosition == RecyclerView.NO_POSITION ||
+ adapter.getItemViewType(childAdapterPosition) ==
TemplatesRecyclerViewAdapter.ITEM_TYPE_DIVIDER ||
childAdapterPosition + 1 < itemCount &&
adapter.getItemViewType(childAdapterPosition + 1) ==
TemplatesRecyclerViewAdapter.ITEM_TYPE_DIVIDER)
+ {
continue;
- parent.getLayoutManager()
- .getDecoratedBoundsWithMargins(child, mBounds);
+ }
+ layoutManager.getDecoratedBoundsWithMargins(child, mBounds);
final int right = mBounds.right + Math.round(child.getTranslationX());
final int left = right - divider.getIntrinsicWidth();
divider.setBounds(left, top, right, bottom);
(TemplatesRecyclerViewAdapter) Objects.requireNonNull(parent.getAdapter());
final int itemCount = adapter.getItemCount();
- if (adapter.getItemViewType(childAdapterPosition) ==
+ if (childAdapterPosition == RecyclerView.NO_POSITION ||
+ adapter.getItemViewType(childAdapterPosition) ==
TemplatesRecyclerViewAdapter.ITEM_TYPE_DIVIDER ||
childAdapterPosition + 1 < itemCount &&
adapter.getItemViewType(childAdapterPosition + 1) ==
+++ /dev/null
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright © 2019 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/>.
- -->
-
-<full-backup-content>
- <!-- Exclude specific shared preferences that contain GCM registration Id -->
-</full-backup-content>
<?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
-->
<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
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
#
-# 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
# 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
+#
# 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
+#Sun Mar 17 11:29:00 EET 2024
android.debug.obsoleteApi=true
+android.defaults.buildfeatures.buildconfig=true
+android.enableJetifier=false
+android.enableR8.fullMode=false
+android.nonFinalResIds=false
+android.nonTransitiveRClass=false
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
-#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
-distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
--- /dev/null
+* ПОПРАВКИ
+ + коригирани версии на gradle
+* ДРУГИ
+ + обновени версии на множество библиотеки
+ + прицелване във версия 31 на платформата
--- /dev/null
+* ПОПРАВКИ
+ + отстранен проблем със съвместимостта с hledger-web 1.23+ при изпращане на нови транзакции. Благодарности на Faye Duxovni за поправката!
+ + поправен срив при изтриване на шаблони
+ + поправен рядък срив при изпращане на транзакции, съдържащи повече от една сметка без сума и нулев остатъчен баланс
--- /dev/null
+* ПОПРАВКИ
+ + отстранен проблем с централизираното резервно копие на настройките
--- /dev/null
+* ПОПРАВКИ
+ + отстранен проблем при изпращане на транзакции към hledger-web 1.23+
--- /dev/null
+* ПОПРАВКИ
+ + Позволяване на потребителски сертификати в настройките за сигурността на мрежовите връзки
+* ДРУГИ
+ + Обновена версия на gradle
--- /dev/null
+* FIXES
+ + sync gradle version requirements
+* OTHERS
+ + bump version of several dependent libraries
+ + bump SDK version to 31
+ + adjust deprecated constructor usage
--- /dev/null
+* FIXES
+ + fix compatibility wuth hledger-web 1.23+ when submitting new transactions. Thanks to Faye Duxovni for the patch!
+ + fix a crash when deleting templates
+ + fix a rare crash when submitting transactions with multiple accounts with no amounts with zero remaining balance
--- /dev/null
+* FIXES
+ + fix cloud backup
--- /dev/null
+* FIXES:
+ + fixed sending of transactions to hledger-web 1.23+
--- /dev/null
+* FIXES:
+ + allow user certificates in network security config
+* OTHERS:
+ + bump gradle version