diff --git a/lib/domain/repository/chat.dart b/lib/domain/repository/chat.dart index 503dafb29a7..f2432fcda2b 100644 --- a/lib/domain/repository/chat.dart +++ b/lib/domain/repository/chat.dart @@ -286,9 +286,6 @@ abstract class RxChat implements Comparable { /// [MyUser] in this [chat]. Rx? get firstUnread; - /// Returns the last [ChatItem] of this [RxChat]. - ChatItem? get lastItem; - /// Listens to the updates of this [RxChat] while the returned [Stream] is /// listened to. Stream get updates; diff --git a/lib/store/chat.dart b/lib/store/chat.dart index 15ed3138570..aec64fdb32d 100644 --- a/lib/store/chat.dart +++ b/lib/store/chat.dart @@ -431,6 +431,7 @@ class ChatRepository extends DisposableInterface rxChat = await ensureRemoteDialog(chatId); } catch (_) { local?.status.value = SendingStatus.error; + return; } } @@ -1483,6 +1484,14 @@ class ChatRepository extends DisposableInterface // [Chat.firstItem] is maintained locally only for [Pagination] reasons. chat.value.firstItem ??= saved?.chat.value.firstItem; + // [Chat.lastItem] and [Chat.updatedAt] are manipulated in [HiveRxChat] by + // its items local state, to account local [ChatItem]s being posted. + if (saved != null && + saved.chat.value.updatedAt.isAfter(chat.value.updatedAt)) { + chat.value.updatedAt = saved.chat.value.updatedAt; + chat.value.lastItem = saved.chat.value.lastItem; + } + // Check the versions first, if [ignoreVersion] is `false`. if (saved != null && !ignoreVersion) { if (saved.ver != null && saved.ver! >= chat.ver) { diff --git a/lib/store/chat_rx.dart b/lib/store/chat_rx.dart index f0f95cdaed8..043a20f6b57 100644 --- a/lib/store/chat_rx.dart +++ b/lib/store/chat_rx.dart @@ -147,6 +147,9 @@ class HiveRxChat extends RxChat { /// [Timer] unmuting the muted [chat] when its [MuteDuration.until] expires. Timer? _muteTimer; + /// [ChatItemHiveProvider.boxEvents] subscription. + StreamIterator? _localSubscription; + /// [ChatRepository.chatEvents] subscription. /// /// May be uninitialized since connection establishment may fail. @@ -254,19 +257,6 @@ class HiveRxChat extends RxChat { return null; } - @override - ChatItem? get lastItem { - ChatItem? item = chat.value.lastItem; - if (messages.isNotEmpty) { - final ChatItem last = messages.last.value; - if (item?.at.isBefore(last.at) == true) { - item = last; - } - } - - return item; - } - @override Stream get updates => _controller.stream; @@ -397,6 +387,8 @@ class HiveRxChat extends RxChat { await _local.init(userId: me); + _initLocalSubscription(); + HiveChatItem? item; if (chat.value.lastReadItem != null) { item = await get(chat.value.lastReadItem!); @@ -419,6 +411,7 @@ class HiveRxChat extends RxChat { _aroundToken.cancel(); _muteTimer?.cancel(); _readTimer?.cancel(); + _localSubscription?.cancel(); _remoteSubscription?.close(immediate: true); _remoteSubscription = null; _paginationSubscription?.cancel(); @@ -1081,6 +1074,46 @@ class HiveRxChat extends RxChat { } } + /// Initializes [ChatItemHiveProvider.boxEvents] subscription. + Future _initLocalSubscription() async { + _localSubscription = StreamIterator(_local.boxEvents); + while (await _localSubscription!.moveNext()) { + final BoxEvent event = _localSubscription!.current; + final ChatItemKey key = ChatItemKey.fromString(event.key); + + if (event.deleted) { + if (chat.value.lastItem?.key == key) { + final HiveChat? chatEntity = await _chatLocal.get(id); + + if (chatEntity != null) { + if (_local.keys.isNotEmpty) { + final HiveChatItem? item = await _local.get(_local.keys.last); + if (item != null) { + chatEntity.value.lastItem = item.value; + chatEntity.value.updatedAt = item.value.at; + } + } else { + chatEntity.value.lastItem = null; + } + + await _chatRepository.put(chatEntity, ignoreVersion: true); + } + } + } else { + final HiveChatItem item = event.value; + if (item.value.at.isAfter(chat.value.updatedAt)) { + final HiveChat? chatEntity = await _chatLocal.get(id); + + if (chatEntity != null) { + chatEntity.value.updatedAt = item.value.at; + chatEntity.value.lastItem = item.value; + await _chatRepository.put(chatEntity, ignoreVersion: true); + } + } + } + } + } + /// Initializes [ChatRepository.chatEvents] subscription. Future _initRemoteSubscription() async { if (_disposed) { diff --git a/lib/store/pagination/hive.dart b/lib/store/pagination/hive.dart index ddcff3572cb..c6293386caa 100644 --- a/lib/store/pagination/hive.dart +++ b/lib/store/pagination/hive.dart @@ -250,13 +250,14 @@ class HivePageProvider final T? firstItem = items.firstOrNull; if (firstItem != null && isFirst != null) { - hasPrevious = - !isFirst!.call(firstItem) || getKey(firstItem) != ordered.first; + hasPrevious = items.none((e) => isFirst!.call(e)) || + getKey(firstItem) != ordered.first; } final T? lastItem = items.lastOrNull; if (lastItem != null && isLast != null) { - hasNext = !isLast!.call(lastItem) || getKey(lastItem) != ordered.last; + hasNext = items.none((e) => isLast!.call(e)) || + getKey(lastItem) != ordered.last; } final Page page = Page( diff --git a/lib/ui/page/home/page/chat/controller.dart b/lib/ui/page/home/page/chat/controller.dart index 95d4cc002bf..c5f9ee73f46 100644 --- a/lib/ui/page/home/page/chat/controller.dart +++ b/lib/ui/page/home/page/chat/controller.dart @@ -438,6 +438,8 @@ class ChatController extends GetxController { if (!PlatformUtils.isMobile) { Future.delayed(Duration.zero, send.field.focus.requestFocus); + } else { + send.field.focus.requestFocus(); } } } diff --git a/lib/ui/page/home/tab/chats/widget/recent_chat.dart b/lib/ui/page/home/tab/chats/widget/recent_chat.dart index 65e6985625b..c0a3a86a1a1 100644 --- a/lib/ui/page/home/tab/chats/widget/recent_chat.dart +++ b/lib/ui/page/home/tab/chats/widget/recent_chat.dart @@ -326,7 +326,7 @@ class RecentChatTile extends StatelessWidget { final List subtitle; final Chat chat = rxChat.chat.value; - final ChatItem? item = rxChat.lastItem; + final ChatItem? item = rxChat.chat.value.lastItem; final ChatMessage? draft = rxChat.draft.value; final Iterable typings = rxChat.typingUsers @@ -834,7 +834,7 @@ class RecentChatTile extends StatelessWidget { return Obx(() { final Chat chat = rxChat.chat.value; - final ChatItem? item = rxChat.lastItem; + final ChatItem? item = rxChat.chat.value.lastItem; if (item != null && item.author.id == me && !chat.isMonolog) { final bool isSent = item.status.value == SendingStatus.sent; diff --git a/lib/ui/page/style/page/widgets/common/dummy_chat.dart b/lib/ui/page/style/page/widgets/common/dummy_chat.dart index 08c6eeb29ec..cdb65ab0cc6 100644 --- a/lib/ui/page/style/page/widgets/common/dummy_chat.dart +++ b/lib/ui/page/style/page/widgets/common/dummy_chat.dart @@ -54,9 +54,6 @@ class DummyRxChat extends RxChat { @override RxBool get hasPrevious => RxBool(false); - @override - ChatItem? get lastItem => null; - @override UserId? get me => null;