✨ Ordering and show the last message in channel
This commit is contained in:
parent
468b7f2c2e
commit
c5a40702b9
@ -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();
|
||||||
|
@ -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,13 +85,20 @@ 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
|
||||||
channel.description,
|
? Text(
|
||||||
maxLines: 1,
|
'${ud.getAccountFromCache(lastMessage.sender.accountId)?.nick}: ${lastMessage.body['text'] ?? 'Unable preview'}',
|
||||||
overflow: TextOverflow.ellipsis,
|
maxLines: 1,
|
||||||
),
|
overflow: TextOverflow.ellipsis,
|
||||||
|
)
|
||||||
|
: Text(
|
||||||
|
channel.description,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
contentPadding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
leading: AccountImage(
|
leading: AccountImage(
|
||||||
content: null,
|
content: null,
|
||||||
|
Loading…
Reference in New Issue
Block a user