Ordering and show the last message in channel

This commit is contained in:
LittleSheep 2024-12-04 00:17:11 +08:00
parent 468b7f2c2e
commit c5a40702b9
2 changed files with 54 additions and 6 deletions

View File

@ -1,7 +1,9 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:surface/controllers/chat_message_controller.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/user_directory.dart';
import 'package:surface/types/chat.dart'; import 'package:surface/types/chat.dart';
import 'package:surface/types/realm.dart'; import 'package:surface/types/realm.dart';
@ -9,11 +11,13 @@ class ChatChannelProvider extends ChangeNotifier {
static const kChatChannelBoxName = 'nex_chat_channels'; static const kChatChannelBoxName = 'nex_chat_channels';
late final SnNetworkProvider _sn; late final SnNetworkProvider _sn;
late final UserDirectoryProvider _ud;
Box<SnChannel>? get _channelBox => Hive.box<SnChannel>(kChatChannelBoxName); Box<SnChannel>? get _channelBox => Hive.box<SnChannel>(kChatChannelBoxName);
ChatChannelProvider(BuildContext context) { ChatChannelProvider(BuildContext context) {
_sn = context.read<SnNetworkProvider>(); _sn = context.read<SnNetworkProvider>();
_ud = context.read<UserDirectoryProvider>();
_initializeLocalData(); _initializeLocalData();
} }
@ -113,6 +117,25 @@ class ChatChannelProvider extends ChangeNotifier {
yield result; yield result;
} }
Future<List<SnChatMessage>> getLastMessages(
Iterable<SnChannel> channels,
) async {
final result = List<SnChatMessage>.empty(growable: true);
for (final channel in channels) {
final channelBox = await Hive.openBox<SnChatMessage>(
'${ChatMessageController.kChatMessageBoxPrefix}${channel.id}',
);
final lastMessage = channelBox.isNotEmpty
? channelBox.values
.reduce((a, b) => a.createdAt.isAfter(b.createdAt) ? a : b)
: null;
if (lastMessage != null) result.add(lastMessage);
channelBox.close();
}
await _ud.listAccount(result.map((ele) => ele.sender.accountId).toSet());
return result;
}
@override @override
void dispose() { void dispose() {
_channelBox?.close(); _channelBox?.close();

View File

@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
import 'package:material_symbols_icons/symbols.dart'; import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:surface/providers/channel.dart'; import 'package:surface/providers/channel.dart';
import 'package:surface/providers/user_directory.dart';
import 'package:surface/types/chat.dart'; import 'package:surface/types/chat.dart';
import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/dialog.dart';
@ -20,10 +21,25 @@ class _ChatScreenState extends State<ChatScreen> {
bool _isBusy = true; bool _isBusy = true;
List<SnChannel>? _channels; List<SnChannel>? _channels;
Map<int, SnChatMessage>? _lastMessages;
void _refreshChannels() { void _refreshChannels() {
final chan = context.read<ChatChannelProvider>(); final chan = context.read<ChatChannelProvider>();
chan.fetchChannels().listen((channels) { chan.fetchChannels().listen((channels) async {
final lastMessages = await chan.getLastMessages(channels);
_lastMessages = {for (final val in lastMessages) val.channelId: val};
channels.sort((a, b) {
if (_lastMessages!.containsKey(a.id) &&
_lastMessages!.containsKey(b.id)) {
return _lastMessages![b.id]!
.createdAt
.compareTo(_lastMessages![a.id]!.createdAt);
}
if (_lastMessages!.containsKey(a.id)) return -1;
if (_lastMessages!.containsKey(b.id)) return 1;
return 0;
});
if (mounted) setState(() => _channels = channels); if (mounted) setState(() => _channels = channels);
}) })
..onError((err) { ..onError((err) {
@ -45,6 +61,8 @@ class _ChatScreenState extends State<ChatScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ud = context.read<UserDirectoryProvider>();
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text('screenChat').tr(), title: Text('screenChat').tr(),
@ -67,9 +85,16 @@ class _ChatScreenState extends State<ChatScreen> {
itemCount: _channels?.length ?? 0, itemCount: _channels?.length ?? 0,
itemBuilder: (context, idx) { itemBuilder: (context, idx) {
final channel = _channels![idx]; final channel = _channels![idx];
final lastMessage = _lastMessages?[channel.id];
return ListTile( return ListTile(
title: Text(channel.name), title: Text(channel.name),
subtitle: Text( subtitle: lastMessage != null
? Text(
'${ud.getAccountFromCache(lastMessage.sender.accountId)?.nick}: ${lastMessage.body['text'] ?? 'Unable preview'}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
)
: Text(
channel.description, channel.description,
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,