Skip to content

Commit

Permalink
Merge pull request #151 from flow-mn/main
Browse files Browse the repository at this point in the history
Release 0.5.2
  • Loading branch information
sadespresso authored May 4, 2024
2 parents b6d6afe + 169a0be commit 349de35
Show file tree
Hide file tree
Showing 12 changed files with 115 additions and 31 deletions.
10 changes: 8 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
## Next
## Beta 0.5.2

* Fixed transaction page date selector's time was always set to **zero** (12AM)
* Now uses [pie_menu](https://pub.dev/packages/pie_menu) from pub.dev since
fork's additional features have are in the new release
* Uses serializer from [`moment_dart`](https://github.com/sadespresso/moment_dart)
* Saves automated backups in app data, fixes [#131](https://github.com/flow-mn/flow/issues/131) for now
* Saves all backups in app data, fixes [#131](https://github.com/flow-mn/flow/issues/131)
* Backups are now deletable
* Minor improvements

## Beta 0.5.1

* [FEAT] Customize order of new transaction buttons by @sadespresso in https://github.com/flow-mn/flow/pull/148
* Reform account edit page by @sadespresso in https://github.com/flow-mn/flow/pull/149

## Beta 0.5.0

* Added calculator by @sadespresso in <https://github.com/flow-mn/flow/pull/147>
Expand Down
1 change: 1 addition & 0 deletions assets/l10n/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,6 @@
"error.sync.invalidBackupFile": "Invalid backup file",
"error.sync.safetyBackupFailed": "Unable to start import",
"error.sync.exportFailed": "Unable to export, please contact developer.",
"error.sync.fileDeleteFailed": "An error occured during backup deletion",
"error.transaction.missingAccount": "Please select an account"
}
1 change: 1 addition & 0 deletions assets/l10n/it_IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,6 @@
"error.sync.invalidBackupFile": "File di backup non valido",
"error.sync.safetyBackupFailed": "Impossibile avviare l'importazione",
"error.sync.exportFailed": "Impossibile esportare, si prega di contattare lo sviluppatore.",
"error.sync.fileDeleteFailed": "Impossibile eliminare il file",
"error.transaction.missingAccount": "Selezionare un account"
}
1 change: 1 addition & 0 deletions assets/l10n/mn_MN.json
Original file line number Diff line number Diff line change
Expand Up @@ -287,5 +287,6 @@
"error.sync.invalidBackupFile": "Нөөц файл алдаатай байна",
"error.sync.safetyBackupFailed": "Сэргээх үйлдэл эхлэх боломжгүй",
"error.sync.exportFailed": "Нөөцлөх явцад алдаа гарлаа, хөгжүүлэгчид хандана уу.",
"error.sync.fileDeleteFailed": "Нөөц устгах үед алдаа гарлаа",
"error.transaction.missingAccount": "Гүйлгээ хийх данс сонгоно уу"
}
8 changes: 8 additions & 0 deletions lib/entity/backup_entry.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,14 @@ class BackupEntry {

Future<bool> exists() => File(filePath).exists();
bool existsSync() => File(filePath).existsSync();
Future<int> getFileSize() => File(filePath).length();
int? getFileSizeSync() {
try {
return File(filePath).lengthSync();
} catch (e) {
return null;
}
}

BackupEntry({
this.id = 0,
Expand Down
18 changes: 18 additions & 0 deletions lib/objectbox/actions.dart
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import 'dart:developer';
import 'dart:io';
import 'dart:math' as math;

import 'package:flow/data/flow_analytics.dart';
import 'package:flow/data/memo.dart';
import 'package:flow/data/money_flow.dart';
import 'package:flow/data/prefs/frecency_group.dart';
import 'package:flow/entity/account.dart';
import 'package:flow/entity/backup_entry.dart';
import 'package:flow/entity/category.dart';
import 'package:flow/entity/transaction.dart';
import 'package:flow/entity/transaction/extensions/base.dart';
Expand Down Expand Up @@ -551,3 +553,19 @@ extension AccountActions on Account {
return id;
}
}

extension BackupEntryActions on BackupEntry {
Future<bool> delete() async {
try {
final File file = File(filePath);

if (await file.exists()) {
await file.delete();
}

return ObjectBox().box<BackupEntry>().remove(id);
} catch (e) {
return false;
}
}
}
7 changes: 4 additions & 3 deletions lib/routes/export/export_history_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ class _ExportHistoryPageState extends State<ExportHistoryPage> {
return switch ((backupEntires?.length ?? 0, snapshot.hasData)) {
(0, true) => const Text("empty"),
(_, true) => ListView.separated(
padding: const EdgeInsets.all(16.0),
itemBuilder: (context, index) =>
BackupEntryCard(entry: backupEntires[index]),
itemBuilder: (context, index) => BackupEntryCard(
entry: backupEntires[index],
dismissibleKey: ValueKey(backupEntires[index].id),
),
separatorBuilder: (context, index) => separator,
itemCount: backupEntires!.length,
),
Expand Down
11 changes: 2 additions & 9 deletions lib/sync/export.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import 'package:flow/sync/export/mode.dart';
import 'package:flow/sync/sync.dart';
import 'package:flow/utils/utils.dart';
import 'package:moment_dart/moment_dart.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:share_plus/share_plus.dart';

Expand Down Expand Up @@ -76,14 +75,8 @@ Future<String> saveBackupFile(
// Save to cache if it's possible to share later.
// Otherwise, save to documents directory, and reveal the file on system.

final Directory saveDir = switch (type) {
BackupEntryType.automated ||
BackupEntryType.preAccountDeletion ||
BackupEntryType.preImport =>
Directory(ObjectBox.appDataDirectory),
_ when isShareSupported => await getApplicationCacheDirectory(),
_ => await getApplicationDocumentsDirectory()
};
final Directory saveDir =
Directory(path.join(ObjectBox.appDataDirectory, 'backups'));

final String dateTime = Moment.now().lll.replaceAll(RegExp("\\s"), "_");
final String randomValue = math.Random().nextInt(536870912).toRadixString(36);
Expand Down
67 changes: 58 additions & 9 deletions lib/sync/export/history/backup_entry_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import 'dart:io';
import 'package:flow/entity/backup_entry.dart';
import 'package:flow/l10n/extensions.dart';
import 'package:flow/l10n/named_enum.dart';
import 'package:flow/objectbox/actions.dart';
import 'package:flow/theme/theme.dart';
import 'package:flow/utils/toast.dart';
import 'package:flow/utils/utils.dart';
import 'package:flow/widgets/general/flow_icon.dart';
import 'package:flow/widgets/general/surface.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:moment_dart/moment_dart.dart';
import 'package:share_plus/share_plus.dart';
Expand All @@ -16,21 +18,29 @@ class BackupEntryCard extends StatelessWidget {
final BackupEntry entry;

final BorderRadius borderRadius;
final EdgeInsets padding;

final Key? dismissibleKey;

const BackupEntryCard({
super.key,
required this.entry,
this.borderRadius = const BorderRadius.all(Radius.circular(16.0)),
this.padding = const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 4.0,
),
this.dismissibleKey,
});

@override
Widget build(BuildContext context) {
final bool fileExists = entry.existsSync();
final int? fileSize = entry.getFileSizeSync();

return Surface(
shape: RoundedRectangleBorder(borderRadius: borderRadius),
builder: (context) => InkWell(
borderRadius: borderRadius,
final Widget listTile = InkWell(
borderRadius: borderRadius,
child: Padding(
padding: padding,
child: Row(
children: [
FlowIcon(
Expand All @@ -48,9 +58,14 @@ class BackupEntryCard extends StatelessWidget {
entry.backupEntryType.localizedNameContext(context),
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: context.textTheme.labelLarge,
),
Text(
"${entry.fileExt} • ${entry.createdDate.toMoment().calendar()}",
[
entry.createdDate.toMoment().calendar(),
entry.fileExt,
fileSize?.binarySize
].nonNulls.join(" • "),
style: context.textTheme.bodyMedium?.semi(context),
maxLines: 2,
overflow: TextOverflow.ellipsis,
Expand All @@ -60,8 +75,8 @@ class BackupEntryCard extends StatelessWidget {
),
const SizedBox(width: 8.0),
IconButton(
onPressed: () => showShareSheet(context, fileExists),
icon: fileExists
onPressed: () => showShareSheet(context, fileSize != null),
icon: fileSize != null
? const Icon(Symbols.save_alt_rounded)
: Icon(
Symbols.error_circle_rounded_error,
Expand All @@ -73,6 +88,21 @@ class BackupEntryCard extends StatelessWidget {
),
),
);

return Slidable(
key: dismissibleKey,
endActionPane: ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (context) => delete(context),
icon: Symbols.delete_forever_rounded,
backgroundColor: context.flowColors.expense,
)
],
),
child: listTile,
);
}

Future<void> showShareSheet(BuildContext context, bool exists) async {
Expand All @@ -99,4 +129,23 @@ class BackupEntryCard extends StatelessWidget {
"date": entry.createdDate.toMoment().lll,
}));
}

Future<void> delete(BuildContext context) async {
final String title = entry.backupEntryType.localizedNameContext(context);

final confirmation = await context.showConfirmDialog(
isDeletionConfirmation: true,
title: "general.delete.confirmName".t(context, title),
);

if (confirmation == true) {
final bool deleted = await entry.delete();

if (!context.mounted) return;

if (!deleted) {
context.showErrorToast(error: "error.sync.fileDeleteFailed".t(context));
}
}
}
}
11 changes: 11 additions & 0 deletions lib/utils/extensions/num.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:math';

extension NumberFormatter on num {
/// Returns string with [decimalPlaces] decimal places.
///
Expand All @@ -24,4 +26,13 @@ extension NumberFormatter on num {
/// Example:
/// `0.42.percent2 => "42.00%"`
String get percent2 => percent(2);

String get binarySize {
const log1024 = 6.931471805599453;
const formats = ['B', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB'];

final int unitIndex = (log(toDouble()) / log1024).floor();

return "${(this / pow(1024, unitIndex)).round()} ${formats[unitIndex]}";
}
}
9 changes: 2 additions & 7 deletions lib/widgets/transaction_list_tile.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import 'dart:io';

import 'package:flow/constants.dart';
import 'package:flow/data/flow_icon.dart';
import 'package:flow/entity/transaction.dart';
import 'package:flow/entity/transaction/extensions/default/transfer.dart';
import 'package:flow/l10n/extensions.dart';
import 'package:flow/objectbox/actions.dart';
import 'package:flow/theme/theme.dart';
import 'package:flow/widgets/general/flow_icon.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:go_router/go_router.dart';
Expand Down Expand Up @@ -98,14 +94,13 @@ class TransactionListTile extends StatelessWidget {

return Slidable(
key: dismissibleKey,
enabled: flowDebugMode || Platform.isIOS,
endActionPane: ActionPane(
motion: const DrawerMotion(),
children: [
SlidableAction(
onPressed: (context) => deleteFn(),
icon: CupertinoIcons.delete,
backgroundColor: CupertinoColors.destructiveRed,
icon: Symbols.delete_forever_rounded,
backgroundColor: context.flowColors.expense,
)
],
),
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: A personal finance managing app

publish_to: "none" # Remove this line if you wish to publish to pub.dev

version: "0.5.2+45"
version: "0.5.2+46"

environment:
sdk: ">=3.1.3 <4.0.0"
Expand Down

0 comments on commit 349de35

Please sign in to comment.