From 9f08e6ce621466a04d48ab9b1ab3baca93559e57 Mon Sep 17 00:00:00 2001 From: Nutcake Date: Sat, 21 Oct 2023 12:39:09 +0200 Subject: [PATCH 1/2] Fix online status not being restored properly Closes #11 --- lib/clients/messaging_client.dart | 11 ++++++++--- lib/main.dart | 1 + pubspec.yaml | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index fc53a8d..fc54cdb 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -6,6 +6,7 @@ import 'package:recon/apis/session_api.dart'; import 'package:recon/apis/user_api.dart'; import 'package:recon/clients/api_client.dart'; import 'package:recon/clients/notification_client.dart'; +import 'package:recon/clients/settings_client.dart'; import 'package:recon/crypto_helper.dart'; import 'package:recon/hub_manager.dart'; import 'package:recon/models/hub_events.dart'; @@ -37,6 +38,7 @@ class MessagingClient extends ChangeNotifier { final HubManager _hubManager = HubManager(); final Map _sessionMap = {}; final Set _knownSessionKeys = {}; + final SettingsClient _settingsClient; Friend? selectedFriend; Timer? _statusHeartbeat; @@ -47,9 +49,11 @@ class MessagingClient extends ChangeNotifier { UserStatus get userStatus => _userStatus; - MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient}) + MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient, required SettingsClient settingsClient}) : _apiClient = apiClient, - _notificationClient = notificationClient { + _notificationClient = notificationClient, + _settingsClient = settingsClient + { debugPrint("mClient created: $hashCode"); Hive.openBox(_messageBoxKey).then((box) async { await box.delete(_lastUpdateKey); @@ -276,7 +280,8 @@ class MessagingClient extends ChangeNotifier { await _refreshUnreads(); _unreadSafeguard = Timer.periodic(_unreadSafeguardDuration, (timer) => _refreshUnreads()); _hubManager.send("RequestStatus", arguments: [null, false]); - await setOnlineStatus(OnlineStatus.online); + final lastOnline = OnlineStatus.values.elementAtOrNull(_settingsClient.currentSettings.lastOnlineStatus.valueOrDefault); + await setOnlineStatus(lastOnline ?? OnlineStatus.online); _statusHeartbeat = Timer.periodic(_statusHeartbeatDuration, (timer) { setOnlineStatus(_userStatus.onlineStatus); }); diff --git a/lib/main.dart b/lib/main.dart index ddf6bee..c940b2e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -164,6 +164,7 @@ class _ReConState extends State { ChangeNotifierProvider( create: (context) => MessagingClient( apiClient: clientHolder.apiClient, + settingsClient: clientHolder.settingsClient, notificationClient: clientHolder.notificationClient, ), ), diff --git a/pubspec.yaml b/pubspec.yaml index 0da794f..014ffa9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.9.2-beta+1 +version: 0.9.3-beta+1 environment: sdk: '>=3.0.1' From 2d785d6cb422ecfda66d7d8305d0eddbed48fa28 Mon Sep 17 00:00:00 2001 From: Nutcake Date: Sat, 21 Oct 2023 14:02:28 +0200 Subject: [PATCH 2/2] Add inventory sorting functions --- lib/clients/inventory_client.dart | 61 ++++++++++- lib/widgets/inventory/inventory_browser.dart | 5 +- .../inventory/inventory_browser_app_bar.dart | 100 +++++++++++++++++- pubspec.yaml | 2 +- 4 files changed, 159 insertions(+), 9 deletions(-) diff --git a/lib/clients/inventory_client.dart b/lib/clients/inventory_client.dart index 7d24c7c..eede68e 100644 --- a/lib/clients/inventory_client.dart +++ b/lib/clients/inventory_client.dart @@ -1,24 +1,74 @@ import 'dart:async'; +import 'package:flutter/material.dart'; import 'package:recon/apis/record_api.dart'; import 'package:recon/clients/api_client.dart'; import 'package:recon/models/inventory/resonite_directory.dart'; import 'package:recon/models/records/record.dart'; -import 'package:flutter/material.dart'; + +enum SortMode { + name, + date; + + int sortFunction(Record a, Record b, {bool reverse = false}) { + final func = switch (this) { + SortMode.name => (Record x, Record y) => + x.formattedName.toString().toLowerCase().compareTo(y.formattedName.toString().toLowerCase()), + SortMode.date => (Record x, Record y) => x.creationTime.compareTo(y.creationTime), + }; + if (reverse) { + return func(b, a); + } + return func(a, b); + } + + static const Map _iconsMap = { + SortMode.name: Icons.sort_by_alpha, + SortMode.date: Icons.access_time_outlined + }; + + IconData get icon => _iconsMap[this] ?? Icons.question_mark; +} class InventoryClient extends ChangeNotifier { final ApiClient apiClient; + final Map _selectedRecords = {}; Future? _currentDirectory; - - Future? get directoryFuture => _currentDirectory; + SortMode _sortMode = SortMode.name; + bool _sortReverse = false; InventoryClient({required this.apiClient}); - final Map _selectedRecords = {}; + SortMode get sortMode => _sortMode; + + bool get sortReverse => _sortReverse; + + set sortMode(SortMode mode) { + if (_sortMode != mode) { + _sortMode = mode; + notifyListeners(); + } + } + + set sortReverse(bool reverse) { + if (_sortReverse != reverse) { + _sortReverse = reverse; + notifyListeners(); + } + } List get selectedRecords => _selectedRecords.values.toList(); + Future? get directoryFuture => _currentDirectory?.then( + (ResoniteDirectory value) { + value.children.sort( + (ResoniteDirectory a, ResoniteDirectory b) => _sortMode.sortFunction(a.record, b.record, reverse: _sortReverse), + ); + return value; + }, + ); + bool get isAnyRecordSelected => _selectedRecords.isNotEmpty; bool isRecordSelected(Record record) => _selectedRecords.containsKey(record.id); @@ -142,7 +192,8 @@ class InventoryClient extends ChangeNotifier { _currentDirectory = _getDirectory(record).then( (records) { childDir.children.clear(); - childDir.children.addAll(records.map((record) => ResoniteDirectory.fromRecord(record: record, parent: childDir))); + childDir.children + .addAll(records.map((record) => ResoniteDirectory.fromRecord(record: record, parent: childDir))); return childDir; }, ).onError((error, stackTrace) { diff --git a/lib/widgets/inventory/inventory_browser.dart b/lib/widgets/inventory/inventory_browser.dart index 5303924..b567519 100644 --- a/lib/widgets/inventory/inventory_browser.dart +++ b/lib/widgets/inventory/inventory_browser.dart @@ -77,8 +77,9 @@ class _InventoryBrowserState extends State with AutomaticKeepA } final directory = snapshot.data; final records = directory?.records ?? []; - - records.sort((a, b) => a.name.compareTo(b.name)); + records.sort( + (Record a, Record b) => iClient.sortMode.sortFunction(a, b, reverse: iClient.sortReverse), + ); final paths = records .where((element) => element.recordType == RecordType.link || element.recordType == RecordType.directory) diff --git a/lib/widgets/inventory/inventory_browser_app_bar.dart b/lib/widgets/inventory/inventory_browser_app_bar.dart index a84bd23..3421e7a 100644 --- a/lib/widgets/inventory/inventory_browser_app_bar.dart +++ b/lib/widgets/inventory/inventory_browser_app_bar.dart @@ -4,6 +4,7 @@ import 'dart:ui'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; +import 'package:intl/intl.dart'; import 'package:path/path.dart'; import 'package:provider/provider.dart'; import 'package:recon/auxiliary.dart'; @@ -50,7 +51,7 @@ class _InventoryBrowserAppBarState extends State { @override Widget build(BuildContext context) { return Consumer( - builder: (BuildContext context, InventoryClient iClient, Widget? child) { + builder: (BuildContext context, InventoryClient iClient, Widget? _) { return AnimatedSwitcher( duration: const Duration(milliseconds: 350), transitionBuilder: (child, animation) => FadeTransition( @@ -61,6 +62,103 @@ class _InventoryBrowserAppBarState extends State { ? AppBar( key: const ValueKey("default-appbar"), title: const Text("Inventory"), + actions: [ + PopupMenuButton( + icon: const Icon(Icons.swap_vert), + onSelected: (value) { + iClient.sortReverse = value; + }, + itemBuilder: (context) { + return [ + PopupMenuItem( + value: false, + child: Row( + children: [ + Icon( + Icons.arrow_upward, + color: iClient.sortReverse == false + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + ), + const SizedBox( + width: 8, + ), + Text( + "Ascending", + style: TextStyle( + color: iClient.sortReverse == false + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + ), + ), + ], + ), + ), + PopupMenuItem( + value: true, + child: Row( + children: [ + Icon(Icons.arrow_downward, + color: iClient.sortReverse == true + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface), + const SizedBox( + width: 8, + ), + Text( + "Descending", + style: TextStyle( + color: iClient.sortReverse == true + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + ), + ), + ], + ), + ) + ]; + }, + ), + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: PopupMenuButton( + icon: const Icon(Icons.sort), + onSelected: (value) { + iClient.sortMode = value; + }, + itemBuilder: (context) { + return SortMode.values + .map( + (e) => PopupMenuItem( + value: e, + child: Row( + children: [ + Icon( + e.icon, + color: iClient.sortMode == e + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + ), + const SizedBox( + width: 8, + ), + Text( + toBeginningOfSentenceCase(e.name) ?? e.name, + style: TextStyle( + color: iClient.sortMode == e + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onSurface, + ), + ) + ], + ), + ), + ) + .toList(); + }, + ), + ), + ], ) : AppBar( key: const ValueKey("selection-appbar"), diff --git a/pubspec.yaml b/pubspec.yaml index 014ffa9..d412c22 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 0.9.3-beta+1 +version: 0.10.0-beta+1 environment: sdk: '>=3.0.1'