♻️ 使用 SQLITE 来存储本地消息记录 #1
| @@ -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); | ||||
|       }, | ||||
|   | ||||
| @@ -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<ChannelChatScreen> { | ||||
|   final _chatScrollController = ScrollController(); | ||||
|  | ||||
|   bool _isBusy = false; | ||||
|   bool _isLoadingMore = false; | ||||
|   int? _accountId; | ||||
|  | ||||
|   String? _overrideAlias; | ||||
|  | ||||
|   Channel? _channel; | ||||
|   ChannelMember? _channelProfile; | ||||
|   Call? _ongoingCall; | ||||
|   ChannelMember? _channelProfile; | ||||
|   StreamSubscription<NetworkPackage>? _subscription; | ||||
|  | ||||
|   int _nextHistorySyncOffset = 0; | ||||
|   MessageHistoryDb? _db; | ||||
|   List<LocalMessage> _currentHistory = List.empty(); | ||||
|  | ||||
| @@ -107,13 +112,19 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> { | ||||
|   } | ||||
|  | ||||
|   Future<void> getMessages() async { | ||||
|     await _db!.syncMessages(_channel!, scope: widget.realm); | ||||
|     await _db!.syncMessages( | ||||
|       _channel!, | ||||
|       scope: widget.realm, | ||||
|       offset: _nextHistorySyncOffset, | ||||
|     ); | ||||
|     await syncHistory(); | ||||
|   } | ||||
|  | ||||
|   Future<void> 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<ChannelChatScreen> { | ||||
|   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<ChannelChatScreen> { | ||||
|  | ||||
|     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<ChannelChatScreen> { | ||||
|  | ||||
|   @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<ChannelChatScreen> { | ||||
|         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, | ||||
|   | ||||
| @@ -101,7 +101,7 @@ class _ChatScreenState extends State<ChatScreen> { | ||||
|                         context), | ||||
|                     sliver: SliverAppBar( | ||||
|                       title: AppBarTitle('chat'.tr), | ||||
|                       centerTitle: true, | ||||
|                       centerTitle: false, | ||||
|                       floating: true, | ||||
|                       titleSpacing: SolianTheme.titleSpacing(context), | ||||
|                       toolbarHeight: SolianTheme.toolbarHeight(context), | ||||
|   | ||||
		Reference in New Issue
	
	Block a user