diff --git a/lib/apis/user_api.dart b/lib/apis/user_api.dart index 3363b34..eab4c97 100644 --- a/lib/apis/user_api.dart +++ b/lib/apis/user_api.dart @@ -28,6 +28,11 @@ class UserApi { final data = jsonDecode(response.body); return UserStatus.fromMap(data); } + + static Future notifyOnlineInstance(ApiClient client) async { + final response = await client.post("/stats/instanceOnline/${client.authenticationData.secretMachineId.hashCode}"); + ApiClient.checkResponse(response); + } static Future setStatus(ApiClient client, {required UserStatus status}) async { final pkginfo = await PackageInfo.fromPlatform(); diff --git a/lib/clients/api_client.dart b/lib/clients/api_client.dart index c1240f0..e9e54ab 100644 --- a/lib/clients/api_client.dart +++ b/lib/clients/api_client.dart @@ -1,8 +1,5 @@ import 'dart:async'; import 'dart:convert'; -import 'package:contacts_plus_plus/clients/messaging_client.dart'; -import 'package:contacts_plus_plus/clients/notification_client.dart'; -import 'package:contacts_plus_plus/clients/settings_client.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_phoenix/flutter_phoenix.dart'; diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index 7da4cdc..f5030b2 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -1,9 +1,9 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'package:collection/collection.dart'; import 'package:contacts_plus_plus/apis/friend_api.dart'; import 'package:contacts_plus_plus/apis/message_api.dart'; +import 'package:contacts_plus_plus/apis/user_api.dart'; import 'package:contacts_plus_plus/clients/notification_client.dart'; import 'package:contacts_plus_plus/models/authentication_data.dart'; import 'package:contacts_plus_plus/models/friend.dart'; @@ -57,6 +57,7 @@ class MessagingClient extends ChangeNotifier { final Workmanager _workmanager = Workmanager(); final NotificationClient _notificationClient; Friend? selectedFriend; + Timer? _notifyOnlineTimer; Timer? _autoRefresh; Timer? _refreshTimeout; int _attempts = 0; @@ -66,16 +67,24 @@ class MessagingClient extends ChangeNotifier { String? get initStatus => _initStatus; + bool get websocketConnected => _wsChannel != null; + MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient}) : _apiClient = apiClient, _notificationClient = notificationClient { refreshFriendsListWithErrorHandler(); - start(); + startWebsocket(); + _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. + UserApi.setStatus(apiClient, status: await UserApi.getUserStatus(apiClient, userId: apiClient.userId)); + }); } @override void dispose() { _autoRefresh?.cancel(); _refreshTimeout?.cancel(); + _notifyOnlineTimer?.cancel(); _wsChannel?.close(); super.dispose(); } @@ -116,16 +125,21 @@ class MessagingClient extends ChangeNotifier { _friendsCache[friend.id] = friend; } _sortedFriendsCache.clear(); - _sortedFriendsCache.addAll(friends.sorted((a, b) { + _sortedFriendsCache.addAll(friends); + _sortFriendsCache(); + _initStatus = ""; + notifyListeners(); + } + + void _sortFriendsCache() { + _sortedFriendsCache.sort((a, b) { var aVal = friendHasUnreads(a) ? -3 : 0; var bVal = friendHasUnreads(b) ? -3 : 0; aVal -= a.userStatus.lastStatusChange.compareTo(b.userStatus.lastStatusChange); aVal += a.userStatus.onlineStatus.compareTo(b.userStatus.onlineStatus) * 2; return aVal.compareTo(bVal); - })); - _initStatus = ""; - notifyListeners(); + }); } void updateAllUnreads(List messages) { @@ -151,6 +165,7 @@ class MessagingClient extends ChangeNotifier { messages.add(message); } messages.sort(); + _sortFriendsCache(); _notificationClient.showUnreadMessagesNotification(messages.reversed); notifyListeners(); } @@ -205,11 +220,12 @@ class MessagingClient extends ChangeNotifier { } void _onDisconnected(error) async { + _wsChannel = null; _logger.warning("Neos Hub connection died with error '$error', reconnecting..."); - await start(); + await startWebsocket(); } - Future start() async { + Future startWebsocket() async { if (!_apiClient.isAuthenticated) { _logger.info("Tried to connect to Neos Hub without authentication, this is probably fine for now."); return; @@ -352,9 +368,4 @@ class MessagingClient extends ChangeNotifier { }; _sendData(data); } -} - - -class MessagesProvider extends ChangeNotifier { - } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 26c863c..c995552 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -72,7 +72,9 @@ class _ContactsPlusPlusState extends State { ChangeNotifierProvider( // This doesn't need to be a proxy provider since the arguments should never change during it's lifetime. create: (context) => MessagingClient( - apiClient: clientHolder.apiClient, notificationClient: clientHolder.notificationClient), + apiClient: clientHolder.apiClient, + notificationClient: clientHolder.notificationClient, + ), child: const FriendsList(), ) : LoginScreen( diff --git a/lib/widgets/friends_list.dart b/lib/widgets/friends_list.dart index 30d7f15..b579eec 100644 --- a/lib/widgets/friends_list.dart +++ b/lib/widgets/friends_list.dart @@ -4,7 +4,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/friend.dart'; -import 'package:contacts_plus_plus/models/message.dart'; import 'package:contacts_plus_plus/models/personal_profile.dart'; import 'package:contacts_plus_plus/widgets/default_error_widget.dart'; import 'package:contacts_plus_plus/widgets/expanding_input_fab.dart';