Compare commits
3 commits
5ce09b1930
...
9f95581b96
Author | SHA1 | Date | |
---|---|---|---|
|
9f95581b96 | ||
|
943bf15aab | ||
|
2226d37f8f |
7 changed files with 160 additions and 77 deletions
|
@ -4,6 +4,9 @@
|
||||||
- Placeholder text is now inserted into the field in setup, instead of showing as label
|
- Placeholder text is now inserted into the field in setup, instead of showing as label
|
||||||
- Show version text in about dialog
|
- Show version text in about dialog
|
||||||
- Added tessdata license text into about dialog
|
- Added tessdata license text into about dialog
|
||||||
|
- Added sorting by oldest
|
||||||
|
- Moved search into three-dot menu
|
||||||
|
- Make search case-insensitive
|
||||||
# 1.0.0-alpha+5
|
# 1.0.0-alpha+5
|
||||||
- Add tests
|
- Add tests
|
||||||
- Add searching through entries to homepage
|
- Add searching through entries to homepage
|
||||||
|
|
|
@ -106,5 +106,9 @@
|
||||||
"exportCompleted":"Export dokončen",
|
"exportCompleted":"Export dokončen",
|
||||||
"importCompleted":"Import dokončen",
|
"importCompleted":"Import dokončen",
|
||||||
"setup":"Prvotní nastavení",
|
"setup":"Prvotní nastavení",
|
||||||
"sourceCode":"Zdrojový kód"
|
"sourceCode":"Zdrojový kód",
|
||||||
|
"sortNewest":"Nejnovější první",
|
||||||
|
"sortOldest":"Nejstarší první",
|
||||||
|
"sort":"Seřadit",
|
||||||
|
"search":"Prohledat"
|
||||||
}
|
}
|
|
@ -222,5 +222,9 @@
|
||||||
"exportCompleted":"Export completed",
|
"exportCompleted":"Export completed",
|
||||||
"importCompleted":"Import completed",
|
"importCompleted":"Import completed",
|
||||||
"setup":"Setup",
|
"setup":"Setup",
|
||||||
"sourceCode":"Source code"
|
"sourceCode":"Source code",
|
||||||
|
"sortNewest":"Newest first",
|
||||||
|
"sortOldest":"Oldest first",
|
||||||
|
"sort":"Sort",
|
||||||
|
"search":"Search"
|
||||||
}
|
}
|
1
lib/l10n/app_sk.arb
Normal file
1
lib/l10n/app_sk.arb
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
58
lib/util/sorting.dart
Normal file
58
lib/util/sorting.dart
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import 'package:grouped_list/grouped_list.dart';
|
||||||
|
import 'package:intl/intl.dart';
|
||||||
|
|
||||||
|
/// Sorts [GroupedListView]'s group by newest group
|
||||||
|
int groupSortNewest(String a, String b, String locale) {
|
||||||
|
// TODO: better sorting algorithm lol
|
||||||
|
final yearA = RegExp(r'\d+').firstMatch(a);
|
||||||
|
if (yearA == null) return 0;
|
||||||
|
final yearB = RegExp(r'\d+').firstMatch(b);
|
||||||
|
if (yearB == null) return 0;
|
||||||
|
final compareYears = int.parse(yearB.group(0)!).compareTo(
|
||||||
|
int.parse(yearA.group(0)!),
|
||||||
|
);
|
||||||
|
if (compareYears != 0) {
|
||||||
|
return compareYears;
|
||||||
|
}
|
||||||
|
final months = List<String>.generate(
|
||||||
|
12,
|
||||||
|
(index) => DateFormat.MMMM(locale).format(
|
||||||
|
DateTime(2023, index + 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final monthA = RegExp('[^0-9 ]+').firstMatch(a);
|
||||||
|
if (monthA == null) return 0;
|
||||||
|
final monthB = RegExp('[^0-9 ]+').firstMatch(b);
|
||||||
|
if (monthB == null) return 0;
|
||||||
|
return months.indexOf(monthB.group(0)!).compareTo(
|
||||||
|
months.indexOf(monthA.group(0)!),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sorts [GroupedListView]'s group by oldest group
|
||||||
|
int groupSortOldest(String a, String b, String locale) {
|
||||||
|
// TODO: better sorting algorithm lol
|
||||||
|
final yearA = RegExp(r'\d+').firstMatch(a);
|
||||||
|
if (yearA == null) return 0;
|
||||||
|
final yearB = RegExp(r'\d+').firstMatch(b);
|
||||||
|
if (yearB == null) return 0;
|
||||||
|
final compareYears = int.parse(yearA.group(0)!).compareTo(
|
||||||
|
int.parse(yearB.group(0)!),
|
||||||
|
);
|
||||||
|
if (compareYears != 0) {
|
||||||
|
return compareYears;
|
||||||
|
}
|
||||||
|
final months = List<String>.generate(
|
||||||
|
12,
|
||||||
|
(index) => DateFormat.MMMM(locale).format(
|
||||||
|
DateTime(2023, index + 1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
final monthA = RegExp('[^0-9 ]+').firstMatch(a);
|
||||||
|
if (monthA == null) return 0;
|
||||||
|
final monthB = RegExp('[^0-9 ]+').firstMatch(b);
|
||||||
|
if (monthB == null) return 0;
|
||||||
|
return months.indexOf(monthA.group(0)!).compareTo(
|
||||||
|
months.indexOf(monthB.group(0)!),
|
||||||
|
);
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import 'package:prasule/pw/platformbutton.dart';
|
||||||
import 'package:prasule/pw/platformfield.dart';
|
import 'package:prasule/pw/platformfield.dart';
|
||||||
import 'package:prasule/pw/platformroute.dart';
|
import 'package:prasule/pw/platformroute.dart';
|
||||||
import 'package:prasule/util/drawer.dart';
|
import 'package:prasule/util/drawer.dart';
|
||||||
|
import 'package:prasule/util/sorting.dart';
|
||||||
import 'package:prasule/util/text_color.dart';
|
import 'package:prasule/util/text_color.dart';
|
||||||
import 'package:prasule/util/utils.dart';
|
import 'package:prasule/util/utils.dart';
|
||||||
import 'package:prasule/views/create_entry.dart';
|
import 'package:prasule/views/create_entry.dart';
|
||||||
|
@ -41,13 +42,15 @@ class HomeView extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeViewState extends State<HomeView> {
|
class _HomeViewState extends State<HomeView> {
|
||||||
Wallet? selectedWallet;
|
Wallet? selectedWallet; // current wallet
|
||||||
List<Wallet> wallets = [];
|
List<Wallet> wallets = []; // all available wallets
|
||||||
DateTime? prevDate;
|
DateTime? prevDate;
|
||||||
late String locale;
|
late String locale; // user's locale
|
||||||
var _searchActive = false;
|
var _searchActive = false; // whether search field is shown
|
||||||
var _filter = "";
|
var _filter = ""; // search filter
|
||||||
final searchFocus = FocusNode();
|
final searchFocus = FocusNode();
|
||||||
|
var sort = SortType.newest;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
|
@ -191,40 +194,67 @@ class _HomeViewState extends State<HomeView> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: _searchActive
|
||||||
if (!_searchActive)
|
? []
|
||||||
IconButton(
|
: [
|
||||||
onPressed: () {
|
PopupMenuButton(
|
||||||
_searchActive = true;
|
tooltip: AppLocalizations.of(context).sort,
|
||||||
setState(() {});
|
icon: const Icon(Icons.sort_rounded),
|
||||||
},
|
itemBuilder: (context) => [
|
||||||
icon: const Icon(Icons.search),
|
AppLocalizations.of(context).sortNewest,
|
||||||
),
|
AppLocalizations.of(context).sortOldest,
|
||||||
if (!_searchActive)
|
]
|
||||||
PopupMenuButton(
|
.map(
|
||||||
itemBuilder: (context) => [
|
(e) => PopupMenuItem(
|
||||||
AppLocalizations.of(context).settings,
|
value: e,
|
||||||
AppLocalizations.of(context).about,
|
child: Text(e),
|
||||||
].map((e) => PopupMenuItem(value: e, child: Text(e))).toList(),
|
),
|
||||||
onSelected: (value) {
|
)
|
||||||
if (value == AppLocalizations.of(context).settings) {
|
.toList(),
|
||||||
Navigator.of(context)
|
onSelected: (value) {
|
||||||
.push(
|
if (value == AppLocalizations.of(context).sortNewest) {
|
||||||
platformRoute(
|
sort = SortType.newest;
|
||||||
(context) => const SettingsView(),
|
setState(() {});
|
||||||
),
|
} else if (value ==
|
||||||
)
|
AppLocalizations.of(context).sortOldest) {
|
||||||
.then((value) async {
|
sort = SortType.oldest;
|
||||||
wallets = await WalletManager.listWallets();
|
setState(() {});
|
||||||
selectedWallet =
|
}
|
||||||
await WalletManager.loadWallet(selectedWallet!.name);
|
},
|
||||||
});
|
),
|
||||||
} else if (value == AppLocalizations.of(context).about) {
|
PopupMenuButton(
|
||||||
showAbout(context);
|
itemBuilder: (context) => [
|
||||||
}
|
AppLocalizations.of(context).settings,
|
||||||
},
|
AppLocalizations.of(context).search,
|
||||||
),
|
AppLocalizations.of(context).about,
|
||||||
],
|
]
|
||||||
|
.map((e) => PopupMenuItem(value: e, child: Text(e)))
|
||||||
|
.toList(),
|
||||||
|
onSelected: (value) {
|
||||||
|
if (value == AppLocalizations.of(context).settings) {
|
||||||
|
Navigator.of(context)
|
||||||
|
.push(
|
||||||
|
platformRoute(
|
||||||
|
(context) => const SettingsView(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.then((value) async {
|
||||||
|
wallets = await WalletManager.listWallets();
|
||||||
|
selectedWallet = await WalletManager.loadWallet(
|
||||||
|
selectedWallet!.name);
|
||||||
|
});
|
||||||
|
} else if (value == AppLocalizations.of(context).about) {
|
||||||
|
showAbout(context);
|
||||||
|
} else if (value == AppLocalizations.of(context).search) {
|
||||||
|
_searchActive = !_searchActive;
|
||||||
|
if (!_searchActive) {
|
||||||
|
_filter = "";
|
||||||
|
}
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
body: Center(
|
body: Center(
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
|
@ -354,47 +384,20 @@ class _HomeViewState extends State<HomeView> {
|
||||||
elements: selectedWallet!.entries
|
elements: selectedWallet!.entries
|
||||||
.where(
|
.where(
|
||||||
(element) => element.data.name
|
(element) => element.data.name
|
||||||
.contains(_filter),
|
.toLowerCase()
|
||||||
|
.contains(_filter.toLowerCase()),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
itemComparator: (a, b) =>
|
itemComparator: (a, b) =>
|
||||||
b.date.compareTo(a.date),
|
(sort == SortType.newest)
|
||||||
|
? b.date.compareTo(a.date)
|
||||||
|
: a.date.compareTo(b.date),
|
||||||
groupBy: (e) =>
|
groupBy: (e) =>
|
||||||
DateFormat.yMMMM(locale).format(e.date),
|
DateFormat.yMMMM(locale).format(e.date),
|
||||||
groupComparator: (a, b) {
|
groupComparator: (a, b) =>
|
||||||
// TODO: better sorting algorithm lol
|
(sort == SortType.newest)
|
||||||
final yearA =
|
? groupSortNewest(a, b, locale)
|
||||||
RegExp(r'\d+').firstMatch(a);
|
: groupSortOldest(a, b, locale),
|
||||||
if (yearA == null) return 0;
|
|
||||||
final yearB =
|
|
||||||
RegExp(r'\d+').firstMatch(b);
|
|
||||||
if (yearB == null) return 0;
|
|
||||||
final compareYears =
|
|
||||||
int.parse(yearB.group(0)!).compareTo(
|
|
||||||
int.parse(yearA.group(0)!),
|
|
||||||
);
|
|
||||||
if (compareYears != 0) {
|
|
||||||
return compareYears;
|
|
||||||
}
|
|
||||||
final months = List<String>.generate(
|
|
||||||
12,
|
|
||||||
(index) =>
|
|
||||||
DateFormat.MMMM(locale).format(
|
|
||||||
DateTime(2023, index + 1),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
final monthA =
|
|
||||||
RegExp('[^0-9 ]+').firstMatch(a);
|
|
||||||
if (monthA == null) return 0;
|
|
||||||
final monthB =
|
|
||||||
RegExp('[^0-9 ]+').firstMatch(b);
|
|
||||||
if (monthB == null) return 0;
|
|
||||||
return months
|
|
||||||
.indexOf(monthB.group(0)!)
|
|
||||||
.compareTo(
|
|
||||||
months.indexOf(monthA.group(0)!),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemBuilder: (context, element) => Slidable(
|
itemBuilder: (context, element) => Slidable(
|
||||||
endActionPane: ActionPane(
|
endActionPane: ActionPane(
|
||||||
motion: const ScrollMotion(),
|
motion: const ScrollMotion(),
|
||||||
|
@ -760,3 +763,12 @@ class _HomeViewState extends State<HomeView> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents entry sorting type
|
||||||
|
enum SortType {
|
||||||
|
/// Sort newest first
|
||||||
|
newest,
|
||||||
|
|
||||||
|
/// Sort oldest first
|
||||||
|
oldest
|
||||||
|
}
|
||||||
|
|
|
@ -57,6 +57,7 @@ class _SetupViewState extends State<SetupView> {
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
if (categories.isEmpty) {
|
if (categories.isEmpty) {
|
||||||
|
name = AppLocalizations.of(context).setupNamePlaceholder;
|
||||||
categories = [
|
categories = [
|
||||||
WalletCategory(
|
WalletCategory(
|
||||||
name: AppLocalizations.of(context).noCategory,
|
name: AppLocalizations.of(context).noCategory,
|
||||||
|
|
Loading…
Reference in a new issue