diff --git a/lib/controllers/chat_message_controller.dart b/lib/controllers/chat_message_controller.dart index 7d3931d..46197ff 100644 --- a/lib/controllers/chat_message_controller.dart +++ b/lib/controllers/chat_message_controller.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:surface/database/database.dart'; import 'package:surface/logger.dart'; +import 'package:surface/providers/channel.dart'; import 'package:surface/providers/database.dart'; import 'package:surface/providers/keypair.dart'; import 'package:surface/providers/sn_attachment.dart'; @@ -26,6 +27,7 @@ class ChatMessageController extends ChangeNotifier { late final WebSocketProvider _ws; late final SnAttachmentProvider _attach; late final DatabaseProvider _dt; + late final ChatChannelProvider _ct; late final KeyPairProvider _kp; StreamSubscription? _wsSubscription; @@ -35,6 +37,7 @@ class ChatMessageController extends ChangeNotifier { _ud = context.read(); _ws = context.read(); _attach = context.read(); + _ct = context.read(); _dt = context.read(); _kp = context.read(); } @@ -65,10 +68,7 @@ class ChatMessageController extends ChangeNotifier { channel = chan; // Fetch channel profile - final resp = await _sn.client.get( - '/cgi/im/channels/${chan.keyPath}/me', - ); - profile = SnChannelMember.fromJson(resp.data); + profile = await _ct.getChannelProfile(channel!); _wsSubscription = _ws.pk.stream.listen((event) { switch (event.method) { diff --git a/lib/providers/channel.dart b/lib/providers/channel.dart index 94d2cd1..98cfcc3 100644 --- a/lib/providers/channel.dart +++ b/lib/providers/channel.dart @@ -8,6 +8,7 @@ import 'package:surface/providers/database.dart'; import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_realm.dart'; import 'package:surface/providers/user_directory.dart'; +import 'package:surface/providers/userinfo.dart'; import 'package:surface/types/chat.dart'; class ChatChannelProvider extends ChangeNotifier { @@ -15,12 +16,14 @@ class ChatChannelProvider extends ChangeNotifier { late final SnNetworkProvider _sn; late final UserDirectoryProvider _ud; + late final UserProvider _ua; late final DatabaseProvider _dt; late final SnRealmProvider _rels; ChatChannelProvider(BuildContext context) { _sn = context.read(); _ud = context.read(); + _ua = context.read(); _dt = context.read(); _rels = context.read(); } @@ -149,4 +152,60 @@ class ChatChannelProvider extends ChangeNotifier { await _ud.listAccount(out.map((ele) => ele.sender.accountId).toSet()); return out; } + + Future _saveMemberToLocal(Iterable members) async { + final queries = members.map((ele) { + return _dt.db.snLocalChannelMember.insertOne( + SnLocalChannelMemberCompanion.insert( + id: Value(ele.id), + channelId: ele.channelId, + accountId: ele.accountId, + content: ele, + cacheExpiredAt: DateTime.now().add(const Duration(days: 7)), + ), + onConflict: DoUpdate( + (_) => SnLocalChannelMemberCompanion.custom( + content: Constant(jsonEncode(ele.toJson())), + cacheExpiredAt: + Constant(DateTime.now().add(const Duration(days: 7))), + ), + ), + ); + }); + await Future.wait(queries); + } + + Future removeLocalChannel(SnChannel channel) async { + await _dt.db.transaction(() async { + await (_dt.db.snLocalChannelMember.delete() + ..where((e) => e.channelId.equals(channel.id))) + .go(); + await (_dt.db.snLocalChatChannel.delete() + ..where((e) => e.id.equals(channel.id))) + .go(); + await (_dt.db.snLocalChatMessage.delete() + ..where((e) => e.channelId.equals(channel.id))) + .go(); + }); + } + + Future updateChannelProfile(SnChannelMember member) { + return _saveMemberToLocal([member]); + } + + Future getChannelProfile(SnChannel channel) async { + if (_ua.user == null) throw Exception('User not logged in'); + final local = await (_dt.db.snLocalChannelMember.select() + ..where((e) => e.channelId.equals(channel.id)) + ..where((e) => e.accountId.equals(_ua.user!.id))) + .getSingleOrNull(); + if (local != null) { + return local.content; + } + + final resp = await _sn.client.get('/cgi/im/channels/${channel.keyPath}/me'); + final out = SnChannelMember.fromJson(resp.data); + _saveMemberToLocal([out]); + return out; + } } diff --git a/lib/screens/chat/channel_detail.dart b/lib/screens/chat/channel_detail.dart index fe2f794..40cea51 100644 --- a/lib/screens/chat/channel_detail.dart +++ b/lib/screens/chat/channel_detail.dart @@ -57,11 +57,9 @@ class _ChannelDetailScreenState extends State { setState(() => _isBusy = true); try { - final sn = context.read(); - final resp = - await sn.client.get('/cgi/im/channels/${_channel!.keyPath}/me'); - _profile = SnChannelMember.fromJson(resp.data); - _notifyLevel = _profile!.notify; + final ct = context.read(); + final resp = await ct.getChannelProfile(_channel!); + _notifyLevel = resp.notify; if (!mounted) return; final ud = context.read(); await ud.getAccount(_profile!.accountId); @@ -103,10 +101,12 @@ class _ChannelDetailScreenState extends State { if (!mounted) return; try { + final ct = context.read(); final sn = context.read(); await sn.client.delete( '/cgi/im/channels/${_channel!.realm?.alias ?? 'global'}/${_channel!.alias}/me', ); + await ct.removeLocalChannel(_channel!); if (!mounted) return; Navigator.pop(context, false); } catch (err) { @@ -130,12 +130,14 @@ class _ChannelDetailScreenState extends State { setState(() => _isUpdatingNotifyLevel = true); try { + final ct = context.read(); final sn = context.read(); await sn.client.put( '/cgi/im/channels/${_channel!.keyPath}/members/me/notify', data: {'notify_level': value}, ); _notifyLevel = value; + await ct.updateChannelProfile(_profile!); if (!mounted) return; context.showSnackbar('channelNotifyLevelApplied'.tr()); } catch (err) {