⚡ User channel profile cache
This commit is contained in:
		@@ -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<UserDirectoryProvider>();
 | 
			
		||||
    _ws = context.read<WebSocketProvider>();
 | 
			
		||||
    _attach = context.read<SnAttachmentProvider>();
 | 
			
		||||
    _ct = context.read<ChatChannelProvider>();
 | 
			
		||||
    _dt = context.read<DatabaseProvider>();
 | 
			
		||||
    _kp = context.read<KeyPairProvider>();
 | 
			
		||||
  }
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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<SnNetworkProvider>();
 | 
			
		||||
    _ud = context.read<UserDirectoryProvider>();
 | 
			
		||||
    _ua = context.read<UserProvider>();
 | 
			
		||||
    _dt = context.read<DatabaseProvider>();
 | 
			
		||||
    _rels = context.read<SnRealmProvider>();
 | 
			
		||||
  }
 | 
			
		||||
@@ -149,4 +152,60 @@ class ChatChannelProvider extends ChangeNotifier {
 | 
			
		||||
    await _ud.listAccount(out.map((ele) => ele.sender.accountId).toSet());
 | 
			
		||||
    return out;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<void> _saveMemberToLocal(Iterable<SnChannelMember> 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<void> 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<void> updateChannelProfile(SnChannelMember member) {
 | 
			
		||||
    return _saveMemberToLocal([member]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Future<SnChannelMember> 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;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -57,11 +57,9 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
 | 
			
		||||
    setState(() => _isBusy = true);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      final sn = context.read<SnNetworkProvider>();
 | 
			
		||||
      final resp =
 | 
			
		||||
          await sn.client.get('/cgi/im/channels/${_channel!.keyPath}/me');
 | 
			
		||||
      _profile = SnChannelMember.fromJson(resp.data);
 | 
			
		||||
      _notifyLevel = _profile!.notify;
 | 
			
		||||
      final ct = context.read<ChatChannelProvider>();
 | 
			
		||||
      final resp = await ct.getChannelProfile(_channel!);
 | 
			
		||||
      _notifyLevel = resp.notify;
 | 
			
		||||
      if (!mounted) return;
 | 
			
		||||
      final ud = context.read<UserDirectoryProvider>();
 | 
			
		||||
      await ud.getAccount(_profile!.accountId);
 | 
			
		||||
@@ -103,10 +101,12 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
 | 
			
		||||
    if (!mounted) return;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      final ct = context.read<ChatChannelProvider>();
 | 
			
		||||
      final sn = context.read<SnNetworkProvider>();
 | 
			
		||||
      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<ChannelDetailScreen> {
 | 
			
		||||
    setState(() => _isUpdatingNotifyLevel = true);
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      final ct = context.read<ChatChannelProvider>();
 | 
			
		||||
      final sn = context.read<SnNetworkProvider>();
 | 
			
		||||
      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) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user