Compare commits
2 commits
91be906894
...
6500c7e5e8
Author | SHA1 | Date | |
---|---|---|---|
|
6500c7e5e8 | ||
|
7fed91e811 |
14 changed files with 455 additions and 260 deletions
|
@ -2,6 +2,7 @@
|
|||
# 1.0.0-alpha+5
|
||||
- Add tests
|
||||
- Add searching through entries to homepage
|
||||
- Replace `PlatformDialog` with `AlertDialog.adaptive`
|
||||
# 1.0.0-alpha+4
|
||||
- Fix OCR downloads
|
||||
# 1.0.0-alpha+3
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:archive/archive_io.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:prasule/api/wallet.dart';
|
||||
import 'package:prasule/main.dart';
|
||||
|
@ -41,6 +45,126 @@ class WalletManager {
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a ZIP archive from all wallets
|
||||
static Future<void> exportAllWallets() async {
|
||||
if (kIsWeb) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
|
||||
final archive = Archive();
|
||||
for (final w in Directory(
|
||||
"${(await getApplicationDocumentsDirectory()).path}/wallets",
|
||||
).listSync()) {
|
||||
if (w is! File) continue;
|
||||
logger.i("Zipping ${w.path.split("/").last}");
|
||||
final wf = w;
|
||||
archive.addFile(
|
||||
ArchiveFile.stream(
|
||||
wf.path.split("/").last,
|
||||
wf.lengthSync(),
|
||||
InputFileStream(wf.path),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (!await FlutterFileDialog.isPickDirectorySupported()) {
|
||||
File(
|
||||
"${(await getApplicationDocumentsDirectory()).path}/export_${DateFormat("dd_MM_yyyy").format(DateTime.now())}.zip",
|
||||
).writeAsBytesSync(ZipEncoder().encode(archive) ?? []);
|
||||
return;
|
||||
}
|
||||
final dir = await FlutterFileDialog.pickDirectory();
|
||||
if (dir == null) return;
|
||||
await FlutterFileDialog.saveFileToDirectory(
|
||||
directory: dir,
|
||||
data: Uint8List.fromList(ZipEncoder().encode(archive) ?? []),
|
||||
fileName: "export_${DateFormat("dd_MM_yyyy").format(DateTime.now())}.zip",
|
||||
mimeType: "application/zip",
|
||||
);
|
||||
}
|
||||
|
||||
/// Exports a single [Wallet]
|
||||
static Future<void> exportWallet({Wallet? wallet, String? name}) async {
|
||||
if (wallet == null && name == null) {
|
||||
throw Exception("You need to specify either a wallet or a name");
|
||||
}
|
||||
final n = name ?? wallet!.name;
|
||||
|
||||
if (!await FlutterFileDialog.isPickDirectorySupported()) {
|
||||
File("${(await getApplicationDocumentsDirectory()).path}/wallets/$n")
|
||||
.copySync(
|
||||
"${await getApplicationDocumentsDirectory()}/export_${n.replaceAll(RegExp('[|\\?*<":>+\[\]/\' ]+'), '_')}_${DateFormat("dd_MM_yyyy").format(DateTime.now())}.json",
|
||||
);
|
||||
return;
|
||||
}
|
||||
final dir = await FlutterFileDialog.pickDirectory();
|
||||
if (dir == null) return;
|
||||
await FlutterFileDialog.saveFileToDirectory(
|
||||
directory: dir,
|
||||
data:
|
||||
File("${(await getApplicationDocumentsDirectory()).path}/wallets/$n")
|
||||
.readAsBytesSync(),
|
||||
fileName:
|
||||
"export_${n.replaceAll(RegExp('[|\\?*<":>+\[\]/\' ]+'), '_')}_${DateFormat("dd_MM_yyyy").format(DateTime.now())}.json",
|
||||
mimeType: "application/json",
|
||||
);
|
||||
}
|
||||
|
||||
/// Import a single wallet
|
||||
static Future<void> importWallet({String? data}) async {
|
||||
var d = data ?? "";
|
||||
if (data == null) {
|
||||
final filePath = await FlutterFileDialog.pickFile(
|
||||
params: const OpenFileDialogParams(
|
||||
mimeTypesFilter: ["application/json"],
|
||||
fileExtensionsFilter: ["json"],
|
||||
),
|
||||
);
|
||||
if (filePath == null) return;
|
||||
d = File(filePath).readAsStringSync();
|
||||
}
|
||||
final w = Wallet.fromJson(jsonDecode(d) as Map<String, dynamic>);
|
||||
if (await WalletManager.exists(w.name)) {
|
||||
throw Exception("Wallet already exists!");
|
||||
}
|
||||
await WalletManager.saveWallet(
|
||||
w,
|
||||
);
|
||||
}
|
||||
|
||||
/// Imports wallets from a ZIP archive
|
||||
static Future<void> importArchive() async {
|
||||
final filePath = await FlutterFileDialog.pickFile(
|
||||
params: const OpenFileDialogParams(
|
||||
mimeTypesFilter: ["application/zip"],
|
||||
fileExtensionsFilter: ["zip"],
|
||||
),
|
||||
);
|
||||
if (filePath == null) return;
|
||||
if (kIsWeb) {
|
||||
// TODO
|
||||
return;
|
||||
}
|
||||
final temp = Directory("${(await getTemporaryDirectory()).path}/data");
|
||||
if (temp.existsSync()) {
|
||||
temp.deleteSync();
|
||||
}
|
||||
temp.createSync(recursive: true);
|
||||
final archive = ZipDecoder().decodeBuffer(InputFileStream(filePath));
|
||||
for (final file in archive.files) {
|
||||
if (!file.isFile) {
|
||||
logger.d(file.name);
|
||||
continue;
|
||||
}
|
||||
file.writeContent(OutputFileStream("${temp.path}/${file.name}"));
|
||||
}
|
||||
for (final e in temp.listSync()) {
|
||||
logger.d(e.path);
|
||||
if (e is! File) continue;
|
||||
await importWallet(data: e.readAsStringSync());
|
||||
}
|
||||
}
|
||||
|
||||
/// Loads and returns a single [Wallet] by name
|
||||
static Future<Wallet> loadWallet(String name) async {
|
||||
final path =
|
||||
|
@ -76,4 +200,11 @@ class WalletManager {
|
|||
Directory("${(await getApplicationDocumentsDirectory()).path}/wallets");
|
||||
File("${path.path}/${w.name}").deleteSync();
|
||||
}
|
||||
|
||||
/// Checks if the wallet exists
|
||||
static Future<bool> exists(String name) async {
|
||||
return File(
|
||||
"${(await getApplicationDocumentsDirectory()).path}/wallets/$name",
|
||||
).existsSync();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,5 +91,18 @@
|
|||
"evenMoney":"Váš stav je stejný jako minulý měsíc.",
|
||||
"balanceStatusA": "Váš stav je ",
|
||||
"balanceStatusB": " oproti minulému měsíci.",
|
||||
"searchLabel":"Prohledat záznamy..."
|
||||
"searchLabel":"Prohledat záznamy...",
|
||||
"exportSingle":"Exportovat peněženku",
|
||||
"exportSingleDesc":"Uloží vybranou peněženku do složky Stažené",
|
||||
"exportArchive":"Exportovat archiv",
|
||||
"exportArchiveDesc":"Exportuje všechny peněženky do archivu do složky Stažené",
|
||||
"importSingle":"Importovat peněženku",
|
||||
"importSingleDesc":"Importuje jednu peněženku ze souboru",
|
||||
"importArchive":"Importovat archiv",
|
||||
"importArchiveDesc":"Importuje všechny nepoškozené peněženky z archivu",
|
||||
"settingsData":"Data",
|
||||
"selectExportWallet":"Zvolte peněženku k exportování",
|
||||
"exportError":"Při exportování peněženky nastala chyba",
|
||||
"exportCompleted":"Export dokončen",
|
||||
"importCompleted":"Import dokončen"
|
||||
}
|
|
@ -207,5 +207,18 @@
|
|||
"evenMoney":"You're on the same balance as last month.",
|
||||
"balanceStatusA": "Your balance is ",
|
||||
"balanceStatusB": " compared to last month.",
|
||||
"searchLabel":"Search entries..."
|
||||
"searchLabel":"Search entries...",
|
||||
"exportSingle":"Export a wallet",
|
||||
"exportSingleDesc":"Saves a single wallet into your downloads directory",
|
||||
"exportArchive":"Export archive",
|
||||
"exportArchiveDesc":"Exports all wallets into an archive to your downloads directory",
|
||||
"importSingle":"Import a wallet",
|
||||
"importSingleDesc":"Imports a single wallet from file",
|
||||
"importArchive":"Import archive",
|
||||
"importArchiveDesc":"Imports all valid wallets inside an archive",
|
||||
"settingsData":"Data",
|
||||
"selectExportWallet":"Select a wallet to export",
|
||||
"exportError":"An error occured trying to export wallet",
|
||||
"exportCompleted":"Export completed",
|
||||
"importCompleted":"Import completed"
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
// ignore_for_file: public_member_api_docs
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:prasule/pw/platformwidget.dart';
|
||||
|
||||
/// A [PlatformWidget] implementation of a dialog
|
||||
class PlatformDialog extends PlatformWidget<AlertDialog, CupertinoAlertDialog> {
|
||||
const PlatformDialog(
|
||||
{required this.title, super.key, this.content, this.actions = const [],});
|
||||
final String title;
|
||||
final Widget? content;
|
||||
final List<Widget> actions;
|
||||
|
||||
@override
|
||||
AlertDialog createAndroidWidget(BuildContext context) => AlertDialog(
|
||||
title: Text(title),
|
||||
content:
|
||||
(content != null) ? SingleChildScrollView(child: content) : null,
|
||||
actions: actions,
|
||||
);
|
||||
|
||||
@override
|
||||
CupertinoAlertDialog createIosWidget(BuildContext context) =>
|
||||
CupertinoAlertDialog(
|
||||
title: Text(title),
|
||||
content:
|
||||
(content != null) ? SingleChildScrollView(child: content) : null,
|
||||
actions: actions,
|
||||
);
|
||||
}
|
|
@ -5,12 +5,12 @@ import 'dart:async';
|
|||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_file_dialog/flutter_file_dialog.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
|
||||
import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
|
||||
import 'package:grouped_list/grouped_list.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:intl/date_symbol_data_local.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:prasule/api/category.dart';
|
||||
|
@ -21,7 +21,6 @@ import 'package:prasule/api/wallet_manager.dart';
|
|||
import 'package:prasule/main.dart';
|
||||
import 'package:prasule/network/tessdata.dart';
|
||||
import 'package:prasule/pw/platformbutton.dart';
|
||||
import 'package:prasule/pw/platformdialog.dart';
|
||||
import 'package:prasule/pw/platformfield.dart';
|
||||
import 'package:prasule/pw/platformroute.dart';
|
||||
import 'package:prasule/util/drawer.dart';
|
||||
|
@ -126,18 +125,15 @@ class _HomeViewState extends State<HomeView> {
|
|||
SpeedDialChild(
|
||||
child: const Icon(Icons.camera_alt),
|
||||
label: AppLocalizations.of(context).addCamera,
|
||||
onTap: () async {
|
||||
final picker = ImagePicker();
|
||||
final media =
|
||||
await picker.pickImage(source: ImageSource.camera);
|
||||
logger.i(media?.name);
|
||||
onTap: () {
|
||||
startOcr(SourceType.camera);
|
||||
},
|
||||
),
|
||||
SpeedDialChild(
|
||||
child: const Icon(Icons.image),
|
||||
label: AppLocalizations.of(context).addGallery,
|
||||
onTap: () {
|
||||
startOcr(ImageSource.gallery);
|
||||
startOcr(SourceType.photoLibrary);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
@ -218,6 +214,7 @@ class _HomeViewState extends State<HomeView> {
|
|||
),
|
||||
)
|
||||
.then((value) async {
|
||||
wallets = await WalletManager.listWallets();
|
||||
selectedWallet =
|
||||
await WalletManager.loadWallet(selectedWallet!.name);
|
||||
});
|
||||
|
@ -448,12 +445,15 @@ class _HomeViewState extends State<HomeView> {
|
|||
.onError,
|
||||
icon: Icons.delete,
|
||||
onPressed: (c) {
|
||||
showDialog(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (cx) => PlatformDialog(
|
||||
title: AppLocalizations.of(
|
||||
context,
|
||||
).sureDialog,
|
||||
builder: (cx) =>
|
||||
AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(
|
||||
context,
|
||||
).sureDialog,
|
||||
),
|
||||
content: Text(
|
||||
AppLocalizations.of(context)
|
||||
.deleteSure,
|
||||
|
@ -591,14 +591,14 @@ class _HomeViewState extends State<HomeView> {
|
|||
);
|
||||
}
|
||||
|
||||
Future<void> startOcr(ImageSource imgSrc) async {
|
||||
Future<void> startOcr(SourceType sourceType) async {
|
||||
final availableLanguages = await TessdataApi.getDownloadedData();
|
||||
if (availableLanguages.isEmpty) {
|
||||
if (!mounted) return;
|
||||
await showDialog(
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
title: AppLocalizations.of(context).missingOcr,
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
title: Text(AppLocalizations.of(context).missingOcr),
|
||||
actions: [
|
||||
PlatformButton(
|
||||
text: AppLocalizations.of(context).download,
|
||||
|
@ -628,16 +628,18 @@ class _HomeViewState extends State<HomeView> {
|
|||
List<bool>.filled(availableLanguages.length, false);
|
||||
selectedLanguages[0] = true;
|
||||
|
||||
await showDialog(
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => StatefulBuilder(
|
||||
builder: (ctx, setState) => PlatformDialog(
|
||||
builder: (ctx, setState) => AlertDialog.adaptive(
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
final picker = ImagePicker();
|
||||
final media = await picker.pickImage(source: imgSrc);
|
||||
if (media == null) {
|
||||
final filePath = await FlutterFileDialog.pickFile(
|
||||
params: OpenFileDialogParams(
|
||||
dialogType: OpenFileDialogType.image,
|
||||
sourceType: sourceType));
|
||||
if (filePath == null) {
|
||||
if (mounted) Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
|
@ -652,16 +654,16 @@ class _HomeViewState extends State<HomeView> {
|
|||
logger.i(selected);
|
||||
if (!mounted) return;
|
||||
unawaited(
|
||||
showDialog(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
title: AppLocalizations.of(context).ocrLoading,
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
title: Text(AppLocalizations.of(context).ocrLoading),
|
||||
),
|
||||
barrierDismissible: false,
|
||||
),
|
||||
);
|
||||
final string = await FlutterTesseractOcr.extractText(
|
||||
media.path,
|
||||
filePath,
|
||||
language: selected,
|
||||
args: {
|
||||
"psm": "4",
|
||||
|
@ -723,7 +725,7 @@ class _HomeViewState extends State<HomeView> {
|
|||
child: const Text("Cancel"),
|
||||
),
|
||||
],
|
||||
title: AppLocalizations.of(context).ocrSelect,
|
||||
title: Text(AppLocalizations.of(context).ocrSelect),
|
||||
content: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
|
@ -756,23 +758,4 @@ class _HomeViewState extends State<HomeView> {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> getLostData() async {
|
||||
final picker = ImagePicker();
|
||||
final response = await picker.retrieveLostData();
|
||||
if (response.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final files = response.files;
|
||||
if (files != null) {
|
||||
logger.i("Found lost files");
|
||||
_handleLostFiles(files);
|
||||
} else {
|
||||
logger.e(response.exception);
|
||||
}
|
||||
}
|
||||
|
||||
void _handleLostFiles(List<XFile> files) {
|
||||
// TODO: implement
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'package:prasule/api/recurring_entry.dart';
|
|||
import 'package:prasule/api/wallet.dart';
|
||||
import 'package:prasule/api/wallet_manager.dart';
|
||||
import 'package:prasule/pw/platformbutton.dart';
|
||||
import 'package:prasule/pw/platformdialog.dart';
|
||||
import 'package:prasule/pw/platformroute.dart';
|
||||
import 'package:prasule/util/drawer.dart';
|
||||
import 'package:prasule/util/text_color.dart';
|
||||
|
@ -215,9 +214,10 @@ class _RecurringEntriesViewState extends State<RecurringEntriesView> {
|
|||
onPressed: (c) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (cx) => PlatformDialog(
|
||||
title:
|
||||
AppLocalizations.of(context).sureDialog,
|
||||
builder: (cx) => AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).sureDialog,
|
||||
),
|
||||
content: Text(
|
||||
AppLocalizations.of(context).deleteSure,
|
||||
),
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:prasule/api/wallet.dart';
|
|||
import 'package:prasule/api/wallet_manager.dart';
|
||||
import 'package:prasule/main.dart';
|
||||
import 'package:prasule/pw/platformbutton.dart';
|
||||
import 'package:prasule/pw/platformdialog.dart';
|
||||
import 'package:prasule/pw/platformfield.dart';
|
||||
import 'package:prasule/pw/platformroute.dart';
|
||||
import 'package:prasule/util/text_color.dart';
|
||||
|
@ -147,9 +146,9 @@ class _EditCategoriesViewState extends State<EditCategoriesView> {
|
|||
.getBool("useMaterialYou") ??
|
||||
false;
|
||||
if (!context.mounted) return;
|
||||
await showDialog(
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
actions: [
|
||||
PlatformButton(
|
||||
text: AppLocalizations.of(context).done,
|
||||
|
@ -158,8 +157,8 @@ class _EditCategoriesViewState extends State<EditCategoriesView> {
|
|||
},
|
||||
),
|
||||
],
|
||||
title:
|
||||
AppLocalizations.of(context).pickColor,
|
||||
title: Text(
|
||||
AppLocalizations.of(context).pickColor),
|
||||
content: Column(
|
||||
children: [
|
||||
ColorPicker(
|
||||
|
@ -215,9 +214,9 @@ class _EditCategoriesViewState extends State<EditCategoriesView> {
|
|||
final controller = TextEditingController(
|
||||
text: selectedWallet!.categories[i].name,
|
||||
);
|
||||
showDialog(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () async {
|
||||
|
@ -243,8 +242,8 @@ class _EditCategoriesViewState extends State<EditCategoriesView> {
|
|||
),
|
||||
),
|
||||
],
|
||||
title: AppLocalizations.of(context)
|
||||
.setupCategoriesEditingName,
|
||||
title: Text(AppLocalizations.of(context)
|
||||
.setupCategoriesEditingName),
|
||||
content: SizedBox(
|
||||
width: 400,
|
||||
child:
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:prasule/pw/platformdialog.dart';
|
||||
import 'package:settings_ui/settings_ui.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
|
@ -50,10 +49,10 @@ class _GraphTypeSettingsViewState extends State<GraphTypeSettingsView> {
|
|||
? AppLocalizations.of(context).barChart
|
||||
: AppLocalizations.of(context).lineChart,
|
||||
),
|
||||
onPressed: (c) => showDialog(
|
||||
onPressed: (c) => showAdaptiveDialog(
|
||||
context: c,
|
||||
builder: (ctx) => PlatformDialog(
|
||||
title: AppLocalizations.of(context).selectType,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(AppLocalizations.of(context).selectType),
|
||||
content: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
|
@ -110,8 +109,8 @@ class _GraphTypeSettingsViewState extends State<GraphTypeSettingsView> {
|
|||
),
|
||||
onPressed: (c) => showDialog(
|
||||
context: c,
|
||||
builder: (ctx) => PlatformDialog(
|
||||
title: AppLocalizations.of(context).selectType,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(AppLocalizations.of(context).selectType),
|
||||
content: Column(
|
||||
children: [
|
||||
SizedBox(
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:prasule/api/wallet_manager.dart';
|
||||
import 'package:prasule/main.dart';
|
||||
import 'package:prasule/pw/platformbutton.dart';
|
||||
import 'package:prasule/pw/platformroute.dart';
|
||||
import 'package:prasule/util/show_message.dart';
|
||||
import 'package:prasule/views/settings/edit_categories.dart';
|
||||
import 'package:prasule/views/settings/graph_type.dart';
|
||||
import 'package:prasule/views/settings/tessdata_list.dart';
|
||||
|
@ -103,6 +107,190 @@ class _SettingsViewState extends State<SettingsView> {
|
|||
),
|
||||
],
|
||||
),
|
||||
SettingsSection(
|
||||
title: Text(AppLocalizations.of(context).settingsData),
|
||||
tiles: [
|
||||
SettingsTile.navigation(
|
||||
title: Text(AppLocalizations.of(context).exportSingle),
|
||||
description:
|
||||
Text(AppLocalizations.of(context).exportSingleDesc),
|
||||
onPressed: (ctx) async {
|
||||
final all = await WalletManager.listWallets();
|
||||
if (!ctx.mounted) return;
|
||||
final w = await showAdaptiveDialog<String>(
|
||||
context: ctx,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).selectExportWallet,
|
||||
),
|
||||
actions: [
|
||||
PlatformButton(
|
||||
text: AppLocalizations.of(context).cancel,
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
),
|
||||
],
|
||||
content: SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.7,
|
||||
height: MediaQuery.of(context).size.height * 0.3,
|
||||
child: ListView.builder(
|
||||
itemBuilder: (con, i) => InkWell(
|
||||
onTap: () => Navigator.of(ctx).pop(all[i].name),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: Text(
|
||||
all[i].name,
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
),
|
||||
shrinkWrap: true,
|
||||
itemCount: all.length,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
if (w == null) return;
|
||||
try {
|
||||
await WalletManager.exportWallet(name: w);
|
||||
} catch (e) {
|
||||
if (!context.mounted) return;
|
||||
unawaited(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).exportError,
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Flexible(
|
||||
child: Text(e.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
logger.e(e);
|
||||
return;
|
||||
}
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showMessage(
|
||||
AppLocalizations.of(ctx).exportCompleted,
|
||||
ctx,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
SettingsTile.navigation(
|
||||
title: Text(AppLocalizations.of(context).exportArchive),
|
||||
description:
|
||||
Text(AppLocalizations.of(context).exportArchiveDesc),
|
||||
onPressed: (ctx) async {
|
||||
try {
|
||||
await WalletManager.exportAllWallets();
|
||||
} catch (e) {
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).exportError,
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Flexible(
|
||||
child: Text(e.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
logger.e(e);
|
||||
return;
|
||||
}
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showMessage(
|
||||
AppLocalizations.of(ctx).exportCompleted,
|
||||
context,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
SettingsTile.navigation(
|
||||
title: Text(AppLocalizations.of(context).importSingle),
|
||||
description:
|
||||
Text(AppLocalizations.of(context).importSingleDesc),
|
||||
onPressed: (ctx) async {
|
||||
try {
|
||||
await WalletManager.importWallet();
|
||||
} catch (e) {
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).exportError,
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Flexible(
|
||||
child: Text(e.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
logger.e(e);
|
||||
return;
|
||||
}
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showMessage(
|
||||
AppLocalizations.of(ctx).importCompleted,
|
||||
context,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
SettingsTile.navigation(
|
||||
title: Text(AppLocalizations.of(context).importArchive),
|
||||
description:
|
||||
Text(AppLocalizations.of(context).importArchiveDesc),
|
||||
onPressed: (ctx) async {
|
||||
try {
|
||||
await WalletManager.importArchive();
|
||||
} catch (e) {
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog.adaptive(
|
||||
title: Text(
|
||||
AppLocalizations.of(context).exportError,
|
||||
),
|
||||
content: SingleChildScrollView(
|
||||
child: Flexible(
|
||||
child: Text(e.toString()),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
logger.e(e);
|
||||
return;
|
||||
}
|
||||
if (!ctx.mounted) return;
|
||||
unawaited(
|
||||
showMessage(
|
||||
AppLocalizations.of(ctx).importCompleted,
|
||||
context,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -9,7 +9,6 @@ import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
|
|||
import 'package:prasule/main.dart';
|
||||
import 'package:prasule/network/tessdata.dart';
|
||||
import 'package:prasule/pw/platformbutton.dart';
|
||||
import 'package:prasule/pw/platformdialog.dart';
|
||||
|
||||
/// Used to manage downloaded Tessdata for OCR
|
||||
class TessdataListView extends StatefulWidget {
|
||||
|
@ -62,10 +61,11 @@ class _TessdataListViewState extends State<TessdataListView> {
|
|||
final lang = _tessdata[i].keys.first;
|
||||
if (_tessdata[i][lang]!) {
|
||||
// deleting data
|
||||
await showDialog(
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (context) => PlatformDialog(
|
||||
title: AppLocalizations.of(context).sureDialog,
|
||||
builder: (context) => AlertDialog.adaptive(
|
||||
title:
|
||||
Text(AppLocalizations.of(context).sureDialog),
|
||||
content: Text(
|
||||
AppLocalizations.of(context).deleteOcr(lang),
|
||||
),
|
||||
|
@ -98,11 +98,11 @@ class _TessdataListViewState extends State<TessdataListView> {
|
|||
final progressStream = StreamController<double>();
|
||||
|
||||
unawaited(
|
||||
showDialog(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
title: AppLocalizations.of(context)
|
||||
.langDownloadDialog(lang),
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
title: Text(AppLocalizations.of(context)
|
||||
.langDownloadDialog(lang)),
|
||||
content: StreamBuilder(
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
// ignore_for_file: inference_failure_on_function_invocation
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:currency_picker/currency_picker.dart';
|
||||
import 'package:dynamic_color/dynamic_color.dart';
|
||||
import 'package:flex_color_picker/flex_color_picker.dart';
|
||||
|
@ -12,7 +14,6 @@ import 'package:prasule/api/category.dart';
|
|||
import 'package:prasule/api/wallet.dart';
|
||||
import 'package:prasule/api/wallet_manager.dart';
|
||||
import 'package:prasule/pw/platformbutton.dart';
|
||||
import 'package:prasule/pw/platformdialog.dart';
|
||||
import 'package:prasule/pw/platformfield.dart';
|
||||
import 'package:prasule/pw/platformroute.dart';
|
||||
import 'package:prasule/util/show_message.dart';
|
||||
|
@ -118,11 +119,22 @@ class _SetupViewState extends State<SetupView> {
|
|||
next: Text(AppLocalizations.of(context).next),
|
||||
back: Text(AppLocalizations.of(context).back),
|
||||
done: Text(AppLocalizations.of(context).finish),
|
||||
onDone: () {
|
||||
onDone: () async {
|
||||
if (name.isEmpty) {
|
||||
showMessage(
|
||||
AppLocalizations.of(context).errorEmptyName,
|
||||
context,
|
||||
unawaited(
|
||||
showMessage(
|
||||
AppLocalizations.of(context).errorEmptyName,
|
||||
context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (await WalletManager.exists(name) && context.mounted) {
|
||||
unawaited(
|
||||
showMessage(
|
||||
AppLocalizations.of(context).walletExists,
|
||||
context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -131,25 +143,19 @@ class _SetupViewState extends State<SetupView> {
|
|||
currency: _selectedCurrency,
|
||||
categories: categories,
|
||||
);
|
||||
WalletManager.saveWallet(wallet).then(
|
||||
(value) {
|
||||
if (!value) {
|
||||
showMessage(
|
||||
AppLocalizations.of(context).walletExists,
|
||||
context,
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (widget.newWallet) {
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
Navigator.of(context).pushReplacement(
|
||||
platformRoute(
|
||||
(c) => const HomeView(),
|
||||
),
|
||||
);
|
||||
},
|
||||
await WalletManager.saveWallet(wallet);
|
||||
|
||||
if (widget.newWallet && context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
return;
|
||||
}
|
||||
if (!context.mounted) return;
|
||||
unawaited(
|
||||
Navigator.of(context).pushReplacement(
|
||||
platformRoute(
|
||||
(c) => const HomeView(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
pages: [
|
||||
|
@ -298,9 +304,9 @@ class _SetupViewState extends State<SetupView> {
|
|||
.getBool("useMaterialYou") ??
|
||||
false;
|
||||
if (!context.mounted) return;
|
||||
await showDialog(
|
||||
await showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
actions: [
|
||||
PlatformButton(
|
||||
text: AppLocalizations.of(context)
|
||||
|
@ -310,8 +316,10 @@ class _SetupViewState extends State<SetupView> {
|
|||
},
|
||||
),
|
||||
],
|
||||
title: AppLocalizations.of(context)
|
||||
.pickColor,
|
||||
title: Text(
|
||||
AppLocalizations.of(context)
|
||||
.pickColor,
|
||||
),
|
||||
content: Column(
|
||||
children: [
|
||||
ColorPicker(
|
||||
|
@ -363,9 +371,9 @@ class _SetupViewState extends State<SetupView> {
|
|||
final controller = TextEditingController(
|
||||
text: categories[i].name,
|
||||
);
|
||||
showDialog(
|
||||
showAdaptiveDialog(
|
||||
context: context,
|
||||
builder: (c) => PlatformDialog(
|
||||
builder: (c) => AlertDialog.adaptive(
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
|
@ -390,8 +398,10 @@ class _SetupViewState extends State<SetupView> {
|
|||
),
|
||||
),
|
||||
],
|
||||
title: AppLocalizations.of(context)
|
||||
.setupCategoriesEditingName,
|
||||
title: Text(
|
||||
AppLocalizations.of(context)
|
||||
.setupCategoriesEditingName,
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 400,
|
||||
child: PlatformField(
|
||||
|
|
130
pubspec.lock
130
pubspec.lock
|
@ -18,7 +18,7 @@ packages:
|
|||
source: hosted
|
||||
version: "6.3.0"
|
||||
archive:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: archive
|
||||
sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d"
|
||||
|
@ -177,14 +177,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.7.2"
|
||||
cross_file:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cross_file
|
||||
sha256: fedaadfa3a6996f75211d835aaeb8fede285dae94262485698afd832371b9a5e
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.3+8"
|
||||
crypto:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -273,38 +265,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "7.0.0"
|
||||
file_selector_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_linux
|
||||
sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.2+1"
|
||||
file_selector_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_macos
|
||||
sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+3"
|
||||
file_selector_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_platform_interface
|
||||
sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.6.2"
|
||||
file_selector_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: file_selector_windows
|
||||
sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.9.3+1"
|
||||
fixnum:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -347,6 +307,14 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_file_dialog:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_file_dialog
|
||||
sha256: "9344b8f07be6a1b6f9854b723fb0cf84a8094ba94761af1d213589d3cb087488"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
flutter_iconpicker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -424,14 +392,6 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_plugin_android_lifecycle:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: flutter_plugin_android_lifecycle
|
||||
sha256: b068ffc46f82a55844acfa4fdbb61fad72fa2aef0905548419d97f0f95c456da
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.17"
|
||||
flutter_slidable:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -519,14 +479,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.2"
|
||||
http:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http
|
||||
sha256: a2bbf9d017fcced29139daa8ed2bba4ece450ab222871df93ca9eec6f80c34ba
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
http_multi_server:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -551,70 +503,6 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.4"
|
||||
image_picker:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: image_picker
|
||||
sha256: "26222b01a0c9a2c8fe02fc90b8208bd3325da5ed1f4a2acabf75939031ac0bdd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.7"
|
||||
image_picker_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_android
|
||||
sha256: "39f2bfe497e495450c81abcd44b62f56c2a36a37a175da7d137b4454977b51b1"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.9+3"
|
||||
image_picker_for_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_for_web
|
||||
sha256: e2423c53a68b579a7c37a1eda967b8ae536c3d98518e5db95ca1fe5719a730a3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.2"
|
||||
image_picker_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_ios
|
||||
sha256: fadafce49e8569257a0cad56d24438a6fa1f0cbd7ee0af9b631f7492818a4ca3
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.8.9+1"
|
||||
image_picker_linux:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_linux
|
||||
sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
image_picker_macos:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_macos
|
||||
sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
image_picker_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_platform_interface
|
||||
sha256: fa4e815e6fcada50e35718727d83ba1c92f1edf95c0b4436554cec301b56233b
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.9.3"
|
||||
image_picker_windows:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: image_picker_windows
|
||||
sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
integration_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
|
|
@ -13,6 +13,7 @@ environment:
|
|||
# the latest version available on pub.dev. To see which dependencies have newer
|
||||
# versions available, run `flutter pub outdated`.
|
||||
dependencies:
|
||||
archive: ^3.4.10
|
||||
cupertino_icons: ^1.0.2
|
||||
currency_picker: ^2.0.16
|
||||
dio: ^5.3.0
|
||||
|
@ -21,6 +22,7 @@ dependencies:
|
|||
flex_color_picker: ^3.3.0
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_file_dialog: ^3.0.2
|
||||
flutter_iconpicker: ^3.2.4
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
|
@ -29,7 +31,6 @@ dependencies:
|
|||
flutter_tesseract_ocr: ^0.4.23
|
||||
fluttertoast: ^8.2.4
|
||||
grouped_list: ^5.1.2
|
||||
image_picker: ^1.0.1
|
||||
intl: any
|
||||
introduction_screen: ^3.1.11
|
||||
json_annotation: ^4.8.1
|
||||
|
|
Loading…
Reference in a new issue