diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index e0cd167..f9c464f 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'package:contacts_plus_plus/hub_manager.dart'; +import 'package:contacts_plus_plus/models/users/online_status.dart'; import 'package:contacts_plus_plus/models/users/user_status.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; @@ -57,12 +58,15 @@ class MessagingClient extends ChangeNotifier { final Logger _logger = Logger("Messaging"); final NotificationClient _notificationClient; final HubManager _hubManager = HubManager(); - Friend? selectedFriend; + Timer? _notifyOnlineTimer; Timer? _autoRefresh; Timer? _unreadSafeguard; String? _initStatus; + UserStatus _userStatus = UserStatus.empty().copyWith(onlineStatus: OnlineStatus.online); + + UserStatus get userStatus => _userStatus; MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient}) : _apiClient = apiClient, @@ -72,11 +76,6 @@ class MessagingClient extends ChangeNotifier { box.delete(_lastUpdateKey); }); _setupHub(); - _notifyOnlineTimer = Timer.periodic(const Duration(seconds: 60), (timer) async { - // We should probably let the MessagingClient handle the entire state of USerStatus instead of mirroring like this - // but I don't feel like implementing that right now. - setUserStatus(await UserApi.getUserStatus(apiClient, userId: apiClient.userId)); - }); } @override @@ -146,18 +145,23 @@ class MessagingClient extends ChangeNotifier { Future setUserStatus(UserStatus status) async { final pkginfo = await PackageInfo.fromPlatform(); - status = status.copyWith( + _userStatus = status.copyWith( appVersion: "${pkginfo.version} of ${pkginfo.appName}", isMobile: true, + lastStatusChange: DateTime.now(), ); _hubManager.send("BroadcastStatus", arguments: [ - status.toMap(), + _userStatus.toMap(), { "group": 0, "targetIds": [], } ]); + + final self = getAsFriend(_apiClient.userId); + await _updateContact(self!.copyWith(userStatus: _userStatus)); + notifyListeners(); } void addUnread(Message message) { diff --git a/lib/main.dart b/lib/main.dart index 9c825db..1f27300 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,6 +14,7 @@ import 'package:contacts_plus_plus/widgets/update_notifier.dart'; import 'package:dynamic_color/dynamic_color.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_downloader/flutter_downloader.dart'; import 'package:flutter_phoenix/flutter_phoenix.dart'; import 'package:hive_flutter/hive_flutter.dart'; @@ -132,14 +133,12 @@ class _ContactsPlusPlusState extends State { theme: ThemeData( useMaterial3: true, textTheme: _typography.black, - canvasColor: lightDynamic?.surfaceVariant, colorScheme: lightDynamic ?? ColorScheme.fromSeed(seedColor: Colors.purple, brightness: Brightness.light), ), darkTheme: ThemeData( useMaterial3: true, textTheme: _typography.white, - canvasColor: darkDynamic?.surfaceVariant, colorScheme: darkDynamic ?? ColorScheme.fromSeed(seedColor: Colors.purple, brightness: Brightness.dark), ), themeMode: ThemeMode.values[widget.settingsClient.currentSettings.themeMode.valueOrDefault], diff --git a/lib/widgets/friends/friends_list_app_bar.dart b/lib/widgets/friends/friends_list_app_bar.dart index ef60632..524c77e 100644 --- a/lib/widgets/friends/friends_list_app_bar.dart +++ b/lib/widgets/friends/friends_list_app_bar.dart @@ -1,8 +1,6 @@ -import 'package:contacts_plus_plus/apis/user_api.dart'; import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/clients/messaging_client.dart'; import 'package:contacts_plus_plus/models/users/online_status.dart'; -import 'package:contacts_plus_plus/models/users/user_status.dart'; import 'package:contacts_plus_plus/widgets/friends/user_search.dart'; import 'package:contacts_plus_plus/widgets/my_profile_dialog.dart'; import 'package:flutter/material.dart'; @@ -18,33 +16,6 @@ class FriendsListAppBar extends StatefulWidget { } class _FriendsListAppBarState extends State with AutomaticKeepAliveClientMixin { - Future? _userStatusFuture; - ClientHolder? _clientHolder; - - @override - void didChangeDependencies() async { - super.didChangeDependencies(); - final clientHolder = ClientHolder.of(context); - if (_clientHolder != clientHolder) { - _clientHolder = clientHolder; - _refreshUserStatus(); - } - } - - void _refreshUserStatus() { - final apiClient = _clientHolder!.apiClient; - final messagingClient = Provider.of(context, listen: false); - _userStatusFuture ??= UserApi.getUserStatus(apiClient, userId: apiClient.userId).then((value) async { - if (value.onlineStatus == OnlineStatus.offline) { - final newStatus = value.copyWith( - onlineStatus: - OnlineStatus.values[_clientHolder!.settingsClient.currentSettings.lastOnlineStatus.valueOrDefault]); - await messagingClient.setUserStatus(newStatus); - return newStatus; - } - return value; - }); - } @override Widget build(BuildContext context) { @@ -52,106 +23,63 @@ class _FriendsListAppBarState extends State with AutomaticKee return AppBar( title: const Text("Contacts++"), systemOverlayStyle: SystemUiOverlayStyle( - systemNavigationBarColor: Theme.of(context).colorScheme.surfaceVariant, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, ), actions: [ - FutureBuilder( - future: _userStatusFuture, - builder: (context, snapshot) { - if (snapshot.hasData) { - final userStatus = snapshot.data as UserStatus; - return PopupMenuButton( - child: Row( - children: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Icon( + Consumer(builder: (context, client, _) { + return PopupMenuButton( + child: Row( + children: [ + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Icon( + Icons.circle, + size: 16, + color: client.userStatus.onlineStatus.color(context), + ), + ), + Text(toBeginningOfSentenceCase(client.userStatus.onlineStatus.name) ?? "Unknown"), + ], + ), + onSelected: (OnlineStatus onlineStatus) async { + final newStatus = client.userStatus.copyWith(onlineStatus: onlineStatus); + final settingsClient = ClientHolder.of(context).settingsClient; + try { + await client.setUserStatus(newStatus); + await settingsClient + .changeSettings(settingsClient.currentSettings.copyWith(lastOnlineStatus: onlineStatus.index)); + } catch (e, s) { + FlutterError.reportError(FlutterErrorDetails(exception: e, stack: s)); + if (context.mounted) { + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar(content: Text("Failed to set online-status."))); + } + } + }, + itemBuilder: (BuildContext context) => OnlineStatus.values + .where((element) => element == OnlineStatus.online || element == OnlineStatus.invisible) + .map( + (item) => PopupMenuItem( + value: item, + child: Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Icon( Icons.circle, size: 16, - color: userStatus.onlineStatus.color(context), + color: item.color(context), ), - ), - Text(toBeginningOfSentenceCase(userStatus.onlineStatus.name) ?? "Unknown"), - ], - ), - onSelected: (OnlineStatus onlineStatus) async { - try { - final messagingClient = Provider.of(context, listen: false); - final newStatus = userStatus.copyWith(onlineStatus: onlineStatus); - setState(() { - _userStatusFuture = Future.value(newStatus.copyWith(lastStatusChange: DateTime.now())); - }); - final settingsClient = _clientHolder!.settingsClient; - await messagingClient.setUserStatus(newStatus); - await settingsClient.changeSettings( - settingsClient.currentSettings.copyWith(lastOnlineStatus: onlineStatus.index)); - } catch (e, s) { - FlutterError.reportError(FlutterErrorDetails(exception: e, stack: s)); - if (context.mounted) { - ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar(content: Text("Failed to set online-status."))); - } - setState(() { - _userStatusFuture = Future.value(userStatus); - }); - } - }, - itemBuilder: (BuildContext context) => OnlineStatus.values - .where((element) => element == OnlineStatus.online || element == OnlineStatus.invisible) - .map( - (item) => PopupMenuItem( - value: item, - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Icon( - Icons.circle, - size: 16, - color: item.color(context), - ), - const SizedBox( - width: 8, - ), - Text(toBeginningOfSentenceCase(item.name)!), - ], - ), + const SizedBox( + width: 8, + ), + Text(toBeginningOfSentenceCase(item.name)!), + ], ), - ) - .toList()); - } else if (snapshot.hasError) { - return TextButton.icon( - style: TextButton.styleFrom( - foregroundColor: Theme.of(context).colorScheme.onSurface, - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 2)), - onPressed: () { - setState(() { - _userStatusFuture = - UserApi.getUserStatus(_clientHolder!.apiClient, userId: _clientHolder!.apiClient.userId); - }); - }, - icon: const Icon(Icons.warning), - label: const Text("Retry"), - ); - } else { - return TextButton.icon( - style: TextButton.styleFrom( - disabledForegroundColor: Theme.of(context).colorScheme.onSurface, - ), - onPressed: null, - icon: Container( - width: 16, - height: 16, - margin: const EdgeInsets.only(right: 4), - child: CircularProgressIndicator( - strokeWidth: 2, - color: Theme.of(context).colorScheme.onSurface, ), - ), - label: const Text("Loading"), - ); - } - }, - ), + ) + .toList(), + ); + }), Padding( padding: const EdgeInsets.only(left: 4, right: 4), child: PopupMenuButton( @@ -190,16 +118,16 @@ class _FriendsListAppBarState extends State with AutomaticKee ] .map( (item) => PopupMenuItem( - value: item, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(item.name), - Icon(item.icon), - ], - ), - ), - ) + value: item, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(item.name), + Icon(item.icon), + ], + ), + ), + ) .toList(), ), ) diff --git a/lib/widgets/homepage.dart b/lib/widgets/homepage.dart index f919807..334d96d 100644 --- a/lib/widgets/homepage.dart +++ b/lib/widgets/homepage.dart @@ -47,13 +47,9 @@ class _HomeState extends State { SettingsPage(), ], ), - bottomNavigationBar: BottomNavigationBar( - backgroundColor: Theme.of(context).colorScheme.surfaceVariant, - type: BottomNavigationBarType.fixed, - unselectedItemColor: Theme.of(context).colorScheme.onBackground, - selectedItemColor: Theme.of(context).colorScheme.primary, - currentIndex: _selectedPage, - onTap: (index) { + bottomNavigationBar: NavigationBar( + selectedIndex: _selectedPage, + onDestinationSelected: (index) { _pageController.animateToPage( index, duration: const Duration(milliseconds: 200), @@ -63,20 +59,20 @@ class _HomeState extends State { _selectedPage = index; }); }, - items: const [ - BottomNavigationBarItem( + destinations: const [ + NavigationDestination( icon: Icon(Icons.message), label: "Chat", ), - BottomNavigationBarItem( + NavigationDestination( icon: Icon(Icons.public), label: "Sessions", ), - BottomNavigationBarItem( + NavigationDestination( icon: Icon(Icons.inventory), label: "Inventory", ), - BottomNavigationBarItem( + NavigationDestination( icon: Icon(Icons.settings), label: "Settings", ), diff --git a/lib/widgets/inventory/inventory_browser_app_bar.dart b/lib/widgets/inventory/inventory_browser_app_bar.dart index bc051d4..a026d7a 100644 --- a/lib/widgets/inventory/inventory_browser_app_bar.dart +++ b/lib/widgets/inventory/inventory_browser_app_bar.dart @@ -62,14 +62,14 @@ class _InventoryBrowserAppBarState extends State { key: const ValueKey("default-appbar"), title: const Text("Inventory"), systemOverlayStyle: SystemUiOverlayStyle( - systemNavigationBarColor: Theme.of(context).colorScheme.surfaceVariant, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, ), ) : AppBar( key: const ValueKey("selection-appbar"), title: Text("${iClient.selectedRecordCount} Selected"), systemOverlayStyle: SystemUiOverlayStyle( - systemNavigationBarColor: Theme.of(context).colorScheme.surfaceVariant, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, ), leading: IconButton( onPressed: () { diff --git a/lib/widgets/sessions/session_list_app_bar.dart b/lib/widgets/sessions/session_list_app_bar.dart index 1fb80c6..acdd5b5 100644 --- a/lib/widgets/sessions/session_list_app_bar.dart +++ b/lib/widgets/sessions/session_list_app_bar.dart @@ -17,7 +17,7 @@ class _SessionListAppBarState extends State { return AppBar( title: const Text("Sessions"), systemOverlayStyle: SystemUiOverlayStyle( - systemNavigationBarColor: Theme.of(context).colorScheme.surfaceVariant, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, ), actions: [ Padding( diff --git a/lib/widgets/settings_app_bar.dart b/lib/widgets/settings_app_bar.dart index b810071..3a33243 100644 --- a/lib/widgets/settings_app_bar.dart +++ b/lib/widgets/settings_app_bar.dart @@ -9,7 +9,7 @@ class SettingsAppBar extends StatelessWidget { return AppBar( title: const Text("Settings"), systemOverlayStyle: SystemUiOverlayStyle( - systemNavigationBarColor: Theme.of(context).colorScheme.surfaceVariant, + systemNavigationBarColor: Theme.of(context).navigationBarTheme.backgroundColor, ), ); }