From 2038d33a3107f13b5ea06032d97ab07f2e1f5468 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 23 Jun 2024 18:03:46 +0800 Subject: [PATCH] :sparkles: Load more messages --- lib/providers/message/helper.dart | 5 +- lib/screens/channel/channel_chat.dart | 86 ++++++++++++++++++--------- lib/screens/chat.dart | 2 +- 3 files changed, 61 insertions(+), 32 deletions(-) diff --git a/lib/providers/message/helper.dart b/lib/providers/message/helper.dart index 3b3e4dd..d35c904 100644 --- a/lib/providers/message/helper.dart +++ b/lib/providers/message/helper.dart @@ -32,13 +32,14 @@ extension MessageHistoryHelper on MessageHistoryDb { await localMessages.delete(id); } - syncMessages(Channel channel, {String scope = 'global'}) async { + syncMessages(Channel channel, {String scope = 'global', offset = 0}) async { final lastOne = await localMessages.findLastByChannel(channel.id); final data = await _getRemoteMessages( channel, scope, - remainBreath: 5, + remainBreath: 3, + offset: offset, onBrake: (items) { return items.any((x) => x.id == lastOne?.id); }, diff --git a/lib/screens/channel/channel_chat.dart b/lib/screens/channel/channel_chat.dart index 7256cba..c254cc2 100644 --- a/lib/screens/channel/channel_chat.dart +++ b/lib/screens/channel/channel_chat.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:ui'; import 'package:flutter/material.dart'; +import 'package:flutter_animate/flutter_animate.dart'; import 'package:get/get.dart'; import 'package:solian/exts.dart'; import 'package:solian/models/call.dart'; @@ -40,16 +41,20 @@ class ChannelChatScreen extends StatefulWidget { } class _ChannelChatScreenState extends State { + final _chatScrollController = ScrollController(); + bool _isBusy = false; + bool _isLoadingMore = false; int? _accountId; String? _overrideAlias; Channel? _channel; - ChannelMember? _channelProfile; Call? _ongoingCall; + ChannelMember? _channelProfile; StreamSubscription? _subscription; + int _nextHistorySyncOffset = 0; MessageHistoryDb? _db; List _currentHistory = List.empty(); @@ -107,13 +112,19 @@ class _ChannelChatScreenState extends State { } Future getMessages() async { - await _db!.syncMessages(_channel!, scope: widget.realm); + await _db!.syncMessages( + _channel!, + scope: widget.realm, + offset: _nextHistorySyncOffset, + ); await syncHistory(); } Future syncHistory() async { - _currentHistory = await _db!.localMessages.findAllByChannel(_channel!.id); - setState(() {}); + final data = await _db!.localMessages.findAllByChannel(_channel!.id); + setState(() { + _currentHistory = data; + }); } void listenMessages() { @@ -171,6 +182,31 @@ class _ChannelChatScreenState extends State { Message? _messageToReplying; Message? _messageToEditing; + Widget buildHistoryBody(Message item, {bool isMerged = false}) { + if (item.replyTo != null) { + return Column( + children: [ + ChatMessage( + key: Key('m${item.replyTo!.uuid}'), + item: item.replyTo!, + isReply: true, + ).paddingOnly(left: 24, right: 4, bottom: 2), + ChatMessage( + key: Key('m${item.uuid}'), + item: item, + isMerged: isMerged, + ), + ], + ); + } + + return ChatMessage( + key: Key('m${item.uuid}'), + item: item, + isMerged: isMerged, + ); + } + Widget buildHistory(context, index) { bool isMerged = false, hasMerged = false; if (index > 0) { @@ -188,33 +224,9 @@ class _ChannelChatScreenState extends State { final item = _currentHistory[index].data; - Widget content; - if (item.replyTo != null) { - content = Column( - children: [ - ChatMessage( - key: Key('m${item.replyTo!.uuid}'), - item: item.replyTo!, - isReply: true, - ).paddingOnly(left: 24, right: 4, bottom: 2), - ChatMessage( - key: Key('m${item.uuid}'), - item: item, - isMerged: isMerged, - ), - ], - ); - } else { - content = ChatMessage( - key: Key('m${item.uuid}'), - item: item, - isMerged: isMerged, - ); - } - return InkWell( child: Container( - child: content.paddingOnly( + child: buildHistoryBody(item, isMerged: isMerged).paddingOnly( top: !isMerged ? 8 : 0, bottom: !hasMerged ? 8 : 0, ), @@ -241,6 +253,16 @@ class _ChannelChatScreenState extends State { @override void initState() { + _chatScrollController.addListener(() async { + if (_chatScrollController.position.pixels == + _chatScrollController.position.maxScrollExtent) { + setState(() => _isLoadingMore = true); + _nextHistorySyncOffset = _currentHistory.length; + await getMessages(); + setState(() => _isLoadingMore = false); + } + }); + createHistoryDb().then((db) async { _db = db; @@ -330,8 +352,14 @@ class _ChannelChatScreenState extends State { children: [ Column( children: [ + if (_isLoadingMore) + const LinearProgressIndicator() + .paddingOnly(bottom: 4) + .animate() + .slideY(), Expanded( child: ListView.builder( + controller: _chatScrollController, itemCount: _currentHistory.length, clipBehavior: Clip.none, reverse: true, diff --git a/lib/screens/chat.dart b/lib/screens/chat.dart index 5cabea1..526dadf 100644 --- a/lib/screens/chat.dart +++ b/lib/screens/chat.dart @@ -101,7 +101,7 @@ class _ChatScreenState extends State { context), sliver: SliverAppBar( title: AppBarTitle('chat'.tr), - centerTitle: true, + centerTitle: false, floating: true, titleSpacing: SolianTheme.titleSpacing(context), toolbarHeight: SolianTheme.toolbarHeight(context),