♻️ Use sqlite to replace hive #5
@@ -683,5 +683,9 @@
 | 
				
			|||||||
  "postChannelRealm": "Realms",
 | 
					  "postChannelRealm": "Realms",
 | 
				
			||||||
  "postFilterReset": "Reset Filter",
 | 
					  "postFilterReset": "Reset Filter",
 | 
				
			||||||
  "postFilterResetDescription": "Clear filter and show all posts.",
 | 
					  "postFilterResetDescription": "Clear filter and show all posts.",
 | 
				
			||||||
  "postFilterWithCategory": "Viewing posts in {}"
 | 
					  "postFilterWithCategory": "Viewing posts in {}",
 | 
				
			||||||
 | 
					  "databaseSize": "Database Size",
 | 
				
			||||||
 | 
					  "databaseDelete": "Delete Database",
 | 
				
			||||||
 | 
					  "databaseDeleteDescription": "Remove the database on your local disk, the content will be fetched from server again.",
 | 
				
			||||||
 | 
					  "databaseDeleted": "The local database has been deleted."
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -681,5 +681,9 @@
 | 
				
			|||||||
  "postChannelRealm": "领域",
 | 
					  "postChannelRealm": "领域",
 | 
				
			||||||
  "postFilterReset": "重置过滤器",
 | 
					  "postFilterReset": "重置过滤器",
 | 
				
			||||||
  "postFilterResetDescription": "清除过滤器并显示所有帖子。",
 | 
					  "postFilterResetDescription": "清除过滤器并显示所有帖子。",
 | 
				
			||||||
  "postFilterWithCategory": "查看{}区中的帖子"
 | 
					  "postFilterWithCategory": "查看{}区中的帖子",
 | 
				
			||||||
 | 
					  "databaseSize": "数据库大小",
 | 
				
			||||||
 | 
					  "databaseDelete": "删除数据库",
 | 
				
			||||||
 | 
					  "databaseDeleteDescription": "删除本地数据库,内容将从服务器重新获取。",
 | 
				
			||||||
 | 
					  "databaseDeleted": "本地数据库已被删除。"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -681,5 +681,9 @@
 | 
				
			|||||||
  "postChannelRealm": "領域",
 | 
					  "postChannelRealm": "領域",
 | 
				
			||||||
  "postFilterReset": "重置過濾器",
 | 
					  "postFilterReset": "重置過濾器",
 | 
				
			||||||
  "postFilterResetDescription": "清除過濾器並顯示所有帖子。",
 | 
					  "postFilterResetDescription": "清除過濾器並顯示所有帖子。",
 | 
				
			||||||
  "postFilterWithCategory": "查看{}區中的帖子"
 | 
					  "postFilterWithCategory": "查看{}區中的帖子",
 | 
				
			||||||
 | 
					  "databaseSize": "數據庫大小",
 | 
				
			||||||
 | 
					  "databaseDelete": "刪除數據庫",
 | 
				
			||||||
 | 
					  "databaseDeleteDescription": "刪除本地數據庫,內容將從服務器重新獲取。",
 | 
				
			||||||
 | 
					  "databaseDeleted": "本地數據庫已被刪除。"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -681,5 +681,9 @@
 | 
				
			|||||||
  "postChannelRealm": "領域",
 | 
					  "postChannelRealm": "領域",
 | 
				
			||||||
  "postFilterReset": "重置過濾器",
 | 
					  "postFilterReset": "重置過濾器",
 | 
				
			||||||
  "postFilterResetDescription": "清除過濾器並顯示所有帖子。",
 | 
					  "postFilterResetDescription": "清除過濾器並顯示所有帖子。",
 | 
				
			||||||
  "postFilterWithCategory": "查看{}區中的帖子"
 | 
					  "postFilterWithCategory": "查看{}區中的帖子",
 | 
				
			||||||
 | 
					  "databaseSize": "數據庫大小",
 | 
				
			||||||
 | 
					  "databaseDelete": "刪除數據庫",
 | 
				
			||||||
 | 
					  "databaseDeleteDescription": "刪除本地數據庫,內容將從服務器重新獲取。",
 | 
				
			||||||
 | 
					  "databaseDeleted": "本地數據庫已被刪除。"
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -221,6 +221,25 @@ PODS:
 | 
				
			|||||||
  - sqflite_darwin (0.0.4):
 | 
					  - sqflite_darwin (0.0.4):
 | 
				
			||||||
    - Flutter
 | 
					    - Flutter
 | 
				
			||||||
    - FlutterMacOS
 | 
					    - FlutterMacOS
 | 
				
			||||||
 | 
					  - sqlite3 (3.49.0):
 | 
				
			||||||
 | 
					    - sqlite3/common (= 3.49.0)
 | 
				
			||||||
 | 
					  - sqlite3/common (3.49.0)
 | 
				
			||||||
 | 
					  - sqlite3/dbstatvtab (3.49.0):
 | 
				
			||||||
 | 
					    - sqlite3/common
 | 
				
			||||||
 | 
					  - sqlite3/fts5 (3.49.0):
 | 
				
			||||||
 | 
					    - sqlite3/common
 | 
				
			||||||
 | 
					  - sqlite3/perf-threadsafe (3.49.0):
 | 
				
			||||||
 | 
					    - sqlite3/common
 | 
				
			||||||
 | 
					  - sqlite3/rtree (3.49.0):
 | 
				
			||||||
 | 
					    - sqlite3/common
 | 
				
			||||||
 | 
					  - sqlite3_flutter_libs (0.0.1):
 | 
				
			||||||
 | 
					    - Flutter
 | 
				
			||||||
 | 
					    - FlutterMacOS
 | 
				
			||||||
 | 
					    - sqlite3 (~> 3.49.0)
 | 
				
			||||||
 | 
					    - sqlite3/dbstatvtab
 | 
				
			||||||
 | 
					    - sqlite3/fts5
 | 
				
			||||||
 | 
					    - sqlite3/perf-threadsafe
 | 
				
			||||||
 | 
					    - sqlite3/rtree
 | 
				
			||||||
  - SwiftyGif (5.4.5)
 | 
					  - SwiftyGif (5.4.5)
 | 
				
			||||||
  - url_launcher_ios (0.0.1):
 | 
					  - url_launcher_ios (0.0.1):
 | 
				
			||||||
    - Flutter
 | 
					    - Flutter
 | 
				
			||||||
@@ -268,6 +287,7 @@ DEPENDENCIES:
 | 
				
			|||||||
  - share_plus (from `.symlinks/plugins/share_plus/ios`)
 | 
					  - share_plus (from `.symlinks/plugins/share_plus/ios`)
 | 
				
			||||||
  - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
 | 
					  - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
 | 
				
			||||||
  - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
 | 
					  - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
 | 
				
			||||||
 | 
					  - sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/darwin`)
 | 
				
			||||||
  - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
 | 
					  - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
 | 
				
			||||||
  - video_compress (from `.symlinks/plugins/video_compress/ios`)
 | 
					  - video_compress (from `.symlinks/plugins/video_compress/ios`)
 | 
				
			||||||
  - volume_controller (from `.symlinks/plugins/volume_controller/ios`)
 | 
					  - volume_controller (from `.symlinks/plugins/volume_controller/ios`)
 | 
				
			||||||
@@ -294,6 +314,7 @@ SPEC REPOS:
 | 
				
			|||||||
    - PromisesObjC
 | 
					    - PromisesObjC
 | 
				
			||||||
    - SAMKeychain
 | 
					    - SAMKeychain
 | 
				
			||||||
    - SDWebImage
 | 
					    - SDWebImage
 | 
				
			||||||
 | 
					    - sqlite3
 | 
				
			||||||
    - SwiftyGif
 | 
					    - SwiftyGif
 | 
				
			||||||
    - WebRTC-SDK
 | 
					    - WebRTC-SDK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -360,6 +381,8 @@ EXTERNAL SOURCES:
 | 
				
			|||||||
    :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
 | 
					    :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
 | 
				
			||||||
  sqflite_darwin:
 | 
					  sqflite_darwin:
 | 
				
			||||||
    :path: ".symlinks/plugins/sqflite_darwin/darwin"
 | 
					    :path: ".symlinks/plugins/sqflite_darwin/darwin"
 | 
				
			||||||
 | 
					  sqlite3_flutter_libs:
 | 
				
			||||||
 | 
					    :path: ".symlinks/plugins/sqlite3_flutter_libs/darwin"
 | 
				
			||||||
  url_launcher_ios:
 | 
					  url_launcher_ios:
 | 
				
			||||||
    :path: ".symlinks/plugins/url_launcher_ios/ios"
 | 
					    :path: ".symlinks/plugins/url_launcher_ios/ios"
 | 
				
			||||||
  video_compress:
 | 
					  video_compress:
 | 
				
			||||||
@@ -421,6 +444,8 @@ SPEC CHECKSUMS:
 | 
				
			|||||||
  share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
 | 
					  share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
 | 
				
			||||||
  shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
 | 
					  shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
 | 
				
			||||||
  sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
 | 
					  sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
 | 
				
			||||||
 | 
					  sqlite3: 4922312598b67e1825c6a6c821296dcbf6783046
 | 
				
			||||||
 | 
					  sqlite3_flutter_libs: 069c435986dd4b63461aecd68f4b30be4a9e9daa
 | 
				
			||||||
  SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
 | 
					  SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
 | 
				
			||||||
  url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
 | 
					  url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
 | 
				
			||||||
  video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe
 | 
					  video_compress: fce97e4fb1dfd88175aa07d2ffc8a2f297f87fbe
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,11 +2,12 @@ import 'dart:async';
 | 
				
			|||||||
import 'dart:convert';
 | 
					import 'dart:convert';
 | 
				
			||||||
import 'dart:math' as math;
 | 
					import 'dart:math' as math;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import 'package:collection/collection.dart';
 | 
					 | 
				
			||||||
import 'package:dio/dio.dart';
 | 
					import 'package:dio/dio.dart';
 | 
				
			||||||
 | 
					import 'package:drift/drift.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:hive/hive.dart';
 | 
					 | 
				
			||||||
import 'package:provider/provider.dart';
 | 
					import 'package:provider/provider.dart';
 | 
				
			||||||
 | 
					import 'package:surface/database/database.dart';
 | 
				
			||||||
 | 
					import 'package:surface/providers/database.dart';
 | 
				
			||||||
import 'package:surface/providers/sn_attachment.dart';
 | 
					import 'package:surface/providers/sn_attachment.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/providers/user_directory.dart';
 | 
				
			||||||
@@ -16,13 +17,13 @@ import 'package:surface/types/websocket.dart';
 | 
				
			|||||||
import 'package:uuid/uuid.dart';
 | 
					import 'package:uuid/uuid.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ChatMessageController extends ChangeNotifier {
 | 
					class ChatMessageController extends ChangeNotifier {
 | 
				
			||||||
  static const kChatMessageBoxPrefix = 'nex_chat_messages_';
 | 
					 | 
				
			||||||
  static const kSingleBatchLoadLimit = 100;
 | 
					  static const kSingleBatchLoadLimit = 100;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  late final SnNetworkProvider _sn;
 | 
					  late final SnNetworkProvider _sn;
 | 
				
			||||||
  late final UserDirectoryProvider _ud;
 | 
					  late final UserDirectoryProvider _ud;
 | 
				
			||||||
  late final WebSocketProvider _ws;
 | 
					  late final WebSocketProvider _ws;
 | 
				
			||||||
  late final SnAttachmentProvider _attach;
 | 
					  late final SnAttachmentProvider _attach;
 | 
				
			||||||
 | 
					  late final DatabaseProvider _dt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  StreamSubscription? _wsSubscription;
 | 
					  StreamSubscription? _wsSubscription;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -31,6 +32,7 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    _ud = context.read<UserDirectoryProvider>();
 | 
					    _ud = context.read<UserDirectoryProvider>();
 | 
				
			||||||
    _ws = context.read<WebSocketProvider>();
 | 
					    _ws = context.read<WebSocketProvider>();
 | 
				
			||||||
    _attach = context.read<SnAttachmentProvider>();
 | 
					    _attach = context.read<SnAttachmentProvider>();
 | 
				
			||||||
 | 
					    _dt = context.read<DatabaseProvider>();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool isPending = true;
 | 
					  bool isPending = true;
 | 
				
			||||||
@@ -38,9 +40,9 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  int? messageTotal;
 | 
					  int? messageTotal;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  bool get isAllLoaded => messageTotal != null && messages.length >= messageTotal!;
 | 
					  bool get isAllLoaded =>
 | 
				
			||||||
 | 
					      messageTotal != null && messages.length >= messageTotal!;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  String? _boxKey;
 | 
					 | 
				
			||||||
  SnChannel? channel;
 | 
					  SnChannel? channel;
 | 
				
			||||||
  SnChannelMember? profile;
 | 
					  SnChannelMember? profile;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -51,25 +53,17 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
  /// Stored as a list of nonce to provide the loading state
 | 
					  /// Stored as a list of nonce to provide the loading state
 | 
				
			||||||
  final List<String> unconfirmedMessages = List.empty(growable: true);
 | 
					  final List<String> unconfirmedMessages = List.empty(growable: true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Box<SnChatMessage>? get _box => (_boxKey == null || isPending) ? null : Hive.box<SnChatMessage>(_boxKey!);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  final List<SnChannelMember> typingMembers = List.empty(growable: true);
 | 
					  final List<SnChannelMember> typingMembers = List.empty(growable: true);
 | 
				
			||||||
  final Map<int, Timer> typingInactiveTimer = {};
 | 
					  final Map<int, Timer> typingInactiveTimer = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> initialize(SnChannel chan) async {
 | 
					  Future<void> initialize(SnChannel chan) async {
 | 
				
			||||||
    channel = chan;
 | 
					    channel = chan;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Initialize local data
 | 
					 | 
				
			||||||
    _boxKey = '$kChatMessageBoxPrefix${chan.id}';
 | 
					 | 
				
			||||||
    await Hive.openBox<SnChatMessage>(_boxKey!);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Fetch channel profile
 | 
					    // Fetch channel profile
 | 
				
			||||||
    final resp = await _sn.client.get(
 | 
					    final resp = await _sn.client.get(
 | 
				
			||||||
      '/cgi/im/channels/${chan.keyPath}/me',
 | 
					      '/cgi/im/channels/${chan.keyPath}/me',
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    profile = SnChannelMember.fromJson(
 | 
					    profile = SnChannelMember.fromJson(resp.data);
 | 
				
			||||||
      resp.data as Map<String, dynamic>,
 | 
					 | 
				
			||||||
    );
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _wsSubscription = _ws.pk.stream.listen((event) {
 | 
					    _wsSubscription = _ws.pk.stream.listen((event) {
 | 
				
			||||||
      switch (event.method) {
 | 
					      switch (event.method) {
 | 
				
			||||||
@@ -87,7 +81,8 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
            notifyListeners();
 | 
					            notifyListeners();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          typingInactiveTimer[member.id]?.cancel();
 | 
					          typingInactiveTimer[member.id]?.cancel();
 | 
				
			||||||
          typingInactiveTimer[member.id] = Timer(const Duration(seconds: 3), () {
 | 
					          typingInactiveTimer[member.id] =
 | 
				
			||||||
 | 
					              Timer(const Duration(seconds: 3), () {
 | 
				
			||||||
            typingMembers.removeWhere((x) => x.id == member.id);
 | 
					            typingMembers.removeWhere((x) => x.id == member.id);
 | 
				
			||||||
            typingInactiveTimer.remove(member.id);
 | 
					            typingInactiveTimer.remove(member.id);
 | 
				
			||||||
            notifyListeners();
 | 
					            notifyListeners();
 | 
				
			||||||
@@ -129,10 +124,16 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _saveMessageToLocal(Iterable<SnChatMessage> messages) async {
 | 
					  Future<void> _saveMessageToLocal(Iterable<SnChatMessage> messages) async {
 | 
				
			||||||
    if (_box == null) return;
 | 
					    await _dt.db.snLocalChatMessage.insertAll(
 | 
				
			||||||
    await _box!.putAll({
 | 
					        messages.map(
 | 
				
			||||||
      for (final message in messages) message.id: message,
 | 
					          (ele) => SnLocalChatMessageCompanion.insert(
 | 
				
			||||||
    });
 | 
					            id: Value(ele.id),
 | 
				
			||||||
 | 
					            content: ele,
 | 
				
			||||||
 | 
					            channelId: channel!.id,
 | 
				
			||||||
 | 
					            createdAt: Value(ele.createdAt),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        onConflict: DoNothing());
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _addUnconfirmedMessage(SnChatMessage message) async {
 | 
					  Future<void> _addUnconfirmedMessage(SnChatMessage message) async {
 | 
				
			||||||
@@ -184,8 +185,21 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    await _applyMessage(message);
 | 
					    await _applyMessage(message);
 | 
				
			||||||
    notifyListeners();
 | 
					    notifyListeners();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (_box == null) return;
 | 
					    if (isCheckedUpdate) {
 | 
				
			||||||
    await _box!.put(message.id, message);
 | 
					      await _dt.db.snLocalChatMessage.insertOne(
 | 
				
			||||||
 | 
					        SnLocalChatMessageCompanion.insert(
 | 
				
			||||||
 | 
					          id: Value(message.id),
 | 
				
			||||||
 | 
					          content: message,
 | 
				
			||||||
 | 
					          channelId: channel!.id,
 | 
				
			||||||
 | 
					          createdAt: Value(message.createdAt),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					        onConflict: DoUpdate((_) => SnLocalChatMessageCompanion.custom(
 | 
				
			||||||
 | 
					              content: Constant(jsonEncode(message.toJson())),
 | 
				
			||||||
 | 
					            )),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      incomeStrandedQueue.add(message);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _applyMessage(SnChatMessage message) async {
 | 
					  Future<void> _applyMessage(SnChatMessage message) async {
 | 
				
			||||||
@@ -194,7 +208,8 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    switch (message.type) {
 | 
					    switch (message.type) {
 | 
				
			||||||
      case 'messages.edit':
 | 
					      case 'messages.edit':
 | 
				
			||||||
        if (message.relatedEventId != null) {
 | 
					        if (message.relatedEventId != null) {
 | 
				
			||||||
          final idx = messages.indexWhere((x) => x.id == message.relatedEventId);
 | 
					          final idx =
 | 
				
			||||||
 | 
					              messages.indexWhere((x) => x.id == message.relatedEventId);
 | 
				
			||||||
          if (idx != -1) {
 | 
					          if (idx != -1) {
 | 
				
			||||||
            final newBody = message.body;
 | 
					            final newBody = message.body;
 | 
				
			||||||
            newBody.remove('related_event');
 | 
					            newBody.remove('related_event');
 | 
				
			||||||
@@ -202,16 +217,24 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
              body: newBody,
 | 
					              body: newBody,
 | 
				
			||||||
              updatedAt: message.updatedAt,
 | 
					              updatedAt: message.updatedAt,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            if (_box!.containsKey(message.relatedEventId)) {
 | 
					            if (message.relatedEventId != null) {
 | 
				
			||||||
              await _box!.put(message.relatedEventId, messages[idx]);
 | 
					              await (_dt.db.snLocalChatMessage.update()
 | 
				
			||||||
 | 
					                    ..where((e) => e.id.equals(message.relatedEventId!)))
 | 
				
			||||||
 | 
					                  .write(
 | 
				
			||||||
 | 
					                SnLocalChatMessageCompanion.custom(
 | 
				
			||||||
 | 
					                  content: Constant(jsonEncode(messages[idx].toJson())),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					              );
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      case 'messages.delete':
 | 
					      case 'messages.delete':
 | 
				
			||||||
        if (message.relatedEventId != null) {
 | 
					        if (message.relatedEventId != null) {
 | 
				
			||||||
          messages.removeWhere((x) => x.id == message.relatedEventId);
 | 
					          messages.removeWhere((x) => x.id == message.relatedEventId);
 | 
				
			||||||
          if (_box!.containsKey(message.relatedEventId)) {
 | 
					          if (message.relatedEventId != null) {
 | 
				
			||||||
            await _box!.delete(message.relatedEventId);
 | 
					            await (_dt.db.snLocalChatMessage.delete()
 | 
				
			||||||
 | 
					                  ..where((e) => e.id.equals(message.relatedEventId!)))
 | 
				
			||||||
 | 
					                .go();
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -233,7 +256,8 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
      'algorithm': 'plain',
 | 
					      'algorithm': 'plain',
 | 
				
			||||||
      if (quoteId != null) 'quote_event': quoteId,
 | 
					      if (quoteId != null) 'quote_event': quoteId,
 | 
				
			||||||
      if (relatedId != null) 'related_event': relatedId,
 | 
					      if (relatedId != null) 'related_event': relatedId,
 | 
				
			||||||
      if (attachments != null && attachments.isNotEmpty) 'attachments': attachments,
 | 
					      if (attachments != null && attachments.isNotEmpty)
 | 
				
			||||||
 | 
					        'attachments': attachments,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Mock the message locally
 | 
					    // Mock the message locally
 | 
				
			||||||
@@ -287,20 +311,34 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  bool isCheckedUpdate = false;
 | 
				
			||||||
 | 
					  List<SnChatMessage> incomeStrandedQueue = List.empty(growable: true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Check the local storage is up to date with the server.
 | 
					  /// Check the local storage is up to date with the server.
 | 
				
			||||||
  /// If the local storage is not up to date, it will be updated.
 | 
					  /// If the local storage is not up to date, it will be updated.
 | 
				
			||||||
  Future<void> checkUpdate() async {
 | 
					  Future<void> checkUpdate() async {
 | 
				
			||||||
    if (_box == null) return;
 | 
					 | 
				
			||||||
    if (_box!.isEmpty) return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    isLoading = true;
 | 
					    isLoading = true;
 | 
				
			||||||
    notifyListeners();
 | 
					    notifyListeners();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    final mostRecentMessage = await (_dt.db.snLocalChatMessage.select()
 | 
				
			||||||
 | 
					          ..limit(1)
 | 
				
			||||||
 | 
					          ..orderBy([
 | 
				
			||||||
 | 
					            (e) =>
 | 
				
			||||||
 | 
					                OrderingTerm(expression: e.createdAt, mode: OrderingMode.desc)
 | 
				
			||||||
 | 
					          ]))
 | 
				
			||||||
 | 
					        .getSingleOrNull();
 | 
				
			||||||
 | 
					    if (mostRecentMessage == null) {
 | 
				
			||||||
 | 
					      // Initial load
 | 
				
			||||||
 | 
					      await loadMessages(take: 20);
 | 
				
			||||||
 | 
					      isCheckedUpdate = true;
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      final resp = await _sn.client.get(
 | 
					      final resp = await _sn.client.get(
 | 
				
			||||||
        '/cgi/im/channels/${channel!.keyPath}/events/update',
 | 
					        '/cgi/im/channels/${channel!.keyPath}/events/update',
 | 
				
			||||||
        queryParameters: {
 | 
					        queryParameters: {
 | 
				
			||||||
          'pivot': _box!.values.last.id,
 | 
					          'pivot': mostRecentMessage.content.id,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      if (resp.data['up_to_date'] == true) return;
 | 
					      if (resp.data['up_to_date'] == true) return;
 | 
				
			||||||
@@ -316,6 +354,12 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    } finally {
 | 
					    } finally {
 | 
				
			||||||
      await loadMessages();
 | 
					      await loadMessages();
 | 
				
			||||||
      isLoading = false;
 | 
					      isLoading = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      isCheckedUpdate = true;
 | 
				
			||||||
 | 
					      _saveMessageToLocal(incomeStrandedQueue).then((_) {
 | 
				
			||||||
 | 
					        incomeStrandedQueue.clear();
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      notifyListeners();
 | 
					      notifyListeners();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -324,13 +368,18 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
  /// If it was not found in local storage we will look it up in remote
 | 
					  /// If it was not found in local storage we will look it up in remote
 | 
				
			||||||
  Future<SnChatMessage?> getMessage(int id) async {
 | 
					  Future<SnChatMessage?> getMessage(int id) async {
 | 
				
			||||||
    SnChatMessage? out;
 | 
					    SnChatMessage? out;
 | 
				
			||||||
    if (_box != null && _box!.containsKey(id)) {
 | 
					    final local = await (_dt.db.snLocalChatMessage.select()
 | 
				
			||||||
      out = _box!.get(id);
 | 
					          ..limit(1)
 | 
				
			||||||
 | 
					          ..where((e) => e.id.equals(id)))
 | 
				
			||||||
 | 
					        .getSingleOrNull();
 | 
				
			||||||
 | 
					    if (local != null) {
 | 
				
			||||||
 | 
					      out = local.content;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (out == null) {
 | 
					    if (out == null) {
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        final resp = await _sn.client.get('/cgi/im/channels/${channel!.keyPath}/events/$id');
 | 
					        final resp = await _sn.client
 | 
				
			||||||
 | 
					            .get('/cgi/im/channels/${channel!.keyPath}/events/$id');
 | 
				
			||||||
        out = SnChatMessage.fromJson(resp.data);
 | 
					        out = SnChatMessage.fromJson(resp.data);
 | 
				
			||||||
        _saveMessageToLocal([out]);
 | 
					        _saveMessageToLocal([out]);
 | 
				
			||||||
      } catch (_) {
 | 
					      } catch (_) {
 | 
				
			||||||
@@ -364,16 +413,21 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    bool forceLocal = false,
 | 
					    bool forceLocal = false,
 | 
				
			||||||
    bool forceRemote = false,
 | 
					    bool forceRemote = false,
 | 
				
			||||||
  }) async {
 | 
					  }) async {
 | 
				
			||||||
 | 
					    final localTotal = await _dt.db.snLocalChatMessage
 | 
				
			||||||
 | 
					        .count(where: (e) => e.channelId.equals(channel!.id))
 | 
				
			||||||
 | 
					        .getSingle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    late List<SnChatMessage> out;
 | 
					    late List<SnChatMessage> out;
 | 
				
			||||||
    if (_box != null && (_box!.length >= take + offset || forceLocal) && !forceRemote) {
 | 
					    if ((localTotal >= take + offset || forceLocal) && !forceRemote) {
 | 
				
			||||||
      out = _box!.keys
 | 
					      final result = await (_dt.db.snLocalChatMessage.select()
 | 
				
			||||||
          .toList()
 | 
					            ..where((e) => e.channelId.equals(channel!.id))
 | 
				
			||||||
          .cast<int>()
 | 
					            ..orderBy([
 | 
				
			||||||
          .sorted((a, b) => b.compareTo(a))
 | 
					              (e) =>
 | 
				
			||||||
          .skip(offset)
 | 
					                  OrderingTerm(expression: e.createdAt, mode: OrderingMode.desc)
 | 
				
			||||||
          .take(take)
 | 
					            ])
 | 
				
			||||||
          .map((key) => _box!.get(key)!)
 | 
					            ..limit(take, offset: offset))
 | 
				
			||||||
          .toList();
 | 
					          .get();
 | 
				
			||||||
 | 
					      out = result.map((e) => e.content).toList();
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
      final resp = await _sn.client.get(
 | 
					      final resp = await _sn.client.get(
 | 
				
			||||||
        '/cgi/im/channels/${channel!.keyPath}/events',
 | 
					        '/cgi/im/channels/${channel!.keyPath}/events',
 | 
				
			||||||
@@ -408,7 +462,8 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
          quoteEvent: quoteEvent,
 | 
					          quoteEvent: quoteEvent,
 | 
				
			||||||
          attachments: attachments
 | 
					          attachments: attachments
 | 
				
			||||||
              .where(
 | 
					              .where(
 | 
				
			||||||
                (ele) => out[i].body['attachments']?.contains(ele?.rid) ?? false,
 | 
					                (ele) =>
 | 
				
			||||||
 | 
					                    out[i].body['attachments']?.contains(ele?.rid) ?? false,
 | 
				
			||||||
              )
 | 
					              )
 | 
				
			||||||
              .toList(),
 | 
					              .toList(),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
@@ -416,7 +471,10 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Preload sender accounts
 | 
					    // Preload sender accounts
 | 
				
			||||||
    final accountId = out.where((ele) => ele.sender.accountId >= 0).map((ele) => ele.sender.accountId).toSet();
 | 
					    final accountId = out
 | 
				
			||||||
 | 
					        .where((ele) => ele.sender.accountId >= 0)
 | 
				
			||||||
 | 
					        .map((ele) => ele.sender.accountId)
 | 
				
			||||||
 | 
					        .toSet();
 | 
				
			||||||
    await _ud.listAccount(accountId);
 | 
					    await _ud.listAccount(accountId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return out;
 | 
					    return out;
 | 
				
			||||||
@@ -443,7 +501,6 @@ class ChatMessageController extends ChangeNotifier {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  void dispose() {
 | 
					  void dispose() {
 | 
				
			||||||
    _box?.close();
 | 
					 | 
				
			||||||
    _wsSubscription?.cancel();
 | 
					    _wsSubscription?.cancel();
 | 
				
			||||||
    super.dispose();
 | 
					    super.dispose();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										74
									
								
								lib/database/chat.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								lib/database/chat.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:drift/drift.dart';
 | 
				
			||||||
 | 
					import 'package:surface/types/chat.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnChannelConverter extends TypeConverter<SnChannel, String>
 | 
				
			||||||
 | 
					    with JsonTypeConverter2<SnChannel, String, Map<String, Object?>> {
 | 
				
			||||||
 | 
					  const SnChannelConverter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  SnChannel fromSql(String fromDb) {
 | 
				
			||||||
 | 
					    return fromJson(jsonDecode(fromDb) as Map<String, dynamic>);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toSql(SnChannel value) {
 | 
				
			||||||
 | 
					    return jsonEncode(toJson(value));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  SnChannel fromJson(Map<String, Object?> json) {
 | 
				
			||||||
 | 
					    return SnChannel.fromJson(json);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, Object?> toJson(SnChannel value) {
 | 
				
			||||||
 | 
					    return value.toJson();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnLocalChatChannel extends Table {
 | 
				
			||||||
 | 
					  IntColumn get id => integer().autoIncrement()();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  TextColumn get alias => text()();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  TextColumn get content => text().map(const SnChannelConverter())();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnMessageConverter extends TypeConverter<SnChatMessage, String>
 | 
				
			||||||
 | 
					    with JsonTypeConverter2<SnChatMessage, String, Map<String, Object?>> {
 | 
				
			||||||
 | 
					  const SnMessageConverter();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  SnChatMessage fromSql(String fromDb) {
 | 
				
			||||||
 | 
					    return fromJson(jsonDecode(fromDb) as Map<String, dynamic>);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toSql(SnChatMessage value) {
 | 
				
			||||||
 | 
					    return jsonEncode(toJson(value));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  SnChatMessage fromJson(Map<String, Object?> json) {
 | 
				
			||||||
 | 
					    return SnChatMessage.fromJson(json);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, Object?> toJson(SnChatMessage value) {
 | 
				
			||||||
 | 
					    return value.toJson();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnLocalChatMessage extends Table {
 | 
				
			||||||
 | 
					  IntColumn get id => integer().autoIncrement()();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  IntColumn get channelId => integer()();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  TextColumn get content => text().map(const SnMessageConverter())();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DateTimeColumn get createdAt => dateTime().withDefault(currentDateAndTime)();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										28
									
								
								lib/database/database.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								lib/database/database.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					import 'package:drift/drift.dart';
 | 
				
			||||||
 | 
					import 'package:drift_flutter/drift_flutter.dart';
 | 
				
			||||||
 | 
					import 'package:path_provider/path_provider.dart';
 | 
				
			||||||
 | 
					import 'package:surface/database/chat.dart';
 | 
				
			||||||
 | 
					import 'package:surface/types/chat.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					part 'database.g.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@DriftDatabase(tables: [SnLocalChatChannel, SnLocalChatMessage])
 | 
				
			||||||
 | 
					class AppDatabase extends _$AppDatabase {
 | 
				
			||||||
 | 
					  AppDatabase() : super(_openConnection());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get schemaVersion => 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static QueryExecutor _openConnection() {
 | 
				
			||||||
 | 
					    return driftDatabase(
 | 
				
			||||||
 | 
					      name: 'solar_network_data',
 | 
				
			||||||
 | 
					      native: const DriftNativeOptions(
 | 
				
			||||||
 | 
					        databaseDirectory: getApplicationSupportDirectory,
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					      web: DriftWebOptions(
 | 
				
			||||||
 | 
					        sqlite3Wasm: Uri.parse('sqlite3.wasm'),
 | 
				
			||||||
 | 
					        driftWorker: Uri.parse('drift_worker.dart.js'),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										880
									
								
								lib/database/database.g.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										880
									
								
								lib/database/database.g.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,880 @@
 | 
				
			|||||||
 | 
					// GENERATED CODE - DO NOT MODIFY BY HAND
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					part of 'database.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ignore_for_file: type=lint
 | 
				
			||||||
 | 
					class $SnLocalChatChannelTable extends SnLocalChatChannel
 | 
				
			||||||
 | 
					    with TableInfo<$SnLocalChatChannelTable, SnLocalChatChannelData> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  final GeneratedDatabase attachedDatabase;
 | 
				
			||||||
 | 
					  final String? _alias;
 | 
				
			||||||
 | 
					  $SnLocalChatChannelTable(this.attachedDatabase, [this._alias]);
 | 
				
			||||||
 | 
					  static const VerificationMeta _idMeta = const VerificationMeta('id');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumn<int> id = GeneratedColumn<int>(
 | 
				
			||||||
 | 
					      'id', aliasedName, false,
 | 
				
			||||||
 | 
					      hasAutoIncrement: true,
 | 
				
			||||||
 | 
					      type: DriftSqlType.int,
 | 
				
			||||||
 | 
					      requiredDuringInsert: false,
 | 
				
			||||||
 | 
					      defaultConstraints:
 | 
				
			||||||
 | 
					          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
 | 
				
			||||||
 | 
					  static const VerificationMeta _aliasMeta = const VerificationMeta('alias');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumn<String> alias = GeneratedColumn<String>(
 | 
				
			||||||
 | 
					      'alias', aliasedName, false,
 | 
				
			||||||
 | 
					      type: DriftSqlType.string, requiredDuringInsert: true);
 | 
				
			||||||
 | 
					  static const VerificationMeta _contentMeta =
 | 
				
			||||||
 | 
					      const VerificationMeta('content');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumnWithTypeConverter<SnChannel, String> content =
 | 
				
			||||||
 | 
					      GeneratedColumn<String>('content', aliasedName, false,
 | 
				
			||||||
 | 
					              type: DriftSqlType.string, requiredDuringInsert: true)
 | 
				
			||||||
 | 
					          .withConverter<SnChannel>($SnLocalChatChannelTable.$convertercontent);
 | 
				
			||||||
 | 
					  static const VerificationMeta _createdAtMeta =
 | 
				
			||||||
 | 
					      const VerificationMeta('createdAt');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
 | 
				
			||||||
 | 
					      'created_at', aliasedName, false,
 | 
				
			||||||
 | 
					      type: DriftSqlType.dateTime,
 | 
				
			||||||
 | 
					      requiredDuringInsert: false,
 | 
				
			||||||
 | 
					      defaultValue: currentDateAndTime);
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  List<GeneratedColumn> get $columns => [id, alias, content, createdAt];
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String get aliasedName => _alias ?? actualTableName;
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String get actualTableName => $name;
 | 
				
			||||||
 | 
					  static const String $name = 'sn_local_chat_channel';
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  VerificationContext validateIntegrity(
 | 
				
			||||||
 | 
					      Insertable<SnLocalChatChannelData> instance,
 | 
				
			||||||
 | 
					      {bool isInserting = false}) {
 | 
				
			||||||
 | 
					    final context = VerificationContext();
 | 
				
			||||||
 | 
					    final data = instance.toColumns(true);
 | 
				
			||||||
 | 
					    if (data.containsKey('id')) {
 | 
				
			||||||
 | 
					      context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (data.containsKey('alias')) {
 | 
				
			||||||
 | 
					      context.handle(
 | 
				
			||||||
 | 
					          _aliasMeta, alias.isAcceptableOrUnknown(data['alias']!, _aliasMeta));
 | 
				
			||||||
 | 
					    } else if (isInserting) {
 | 
				
			||||||
 | 
					      context.missing(_aliasMeta);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    context.handle(_contentMeta, const VerificationResult.success());
 | 
				
			||||||
 | 
					    if (data.containsKey('created_at')) {
 | 
				
			||||||
 | 
					      context.handle(_createdAtMeta,
 | 
				
			||||||
 | 
					          createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return context;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Set<GeneratedColumn> get $primaryKey => {id};
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  SnLocalChatChannelData map(Map<String, dynamic> data, {String? tablePrefix}) {
 | 
				
			||||||
 | 
					    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
 | 
				
			||||||
 | 
					    return SnLocalChatChannelData(
 | 
				
			||||||
 | 
					      id: attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
 | 
				
			||||||
 | 
					      alias: attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					          .read(DriftSqlType.string, data['${effectivePrefix}alias'])!,
 | 
				
			||||||
 | 
					      content: $SnLocalChatChannelTable.$convertercontent.fromSql(
 | 
				
			||||||
 | 
					          attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					              .read(DriftSqlType.string, data['${effectivePrefix}content'])!),
 | 
				
			||||||
 | 
					      createdAt: attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  $SnLocalChatChannelTable createAlias(String alias) {
 | 
				
			||||||
 | 
					    return $SnLocalChatChannelTable(attachedDatabase, alias);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static JsonTypeConverter2<SnChannel, String, Map<String, Object?>>
 | 
				
			||||||
 | 
					      $convertercontent = const SnChannelConverter();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnLocalChatChannelData extends DataClass
 | 
				
			||||||
 | 
					    implements Insertable<SnLocalChatChannelData> {
 | 
				
			||||||
 | 
					  final int id;
 | 
				
			||||||
 | 
					  final String alias;
 | 
				
			||||||
 | 
					  final SnChannel content;
 | 
				
			||||||
 | 
					  final DateTime createdAt;
 | 
				
			||||||
 | 
					  const SnLocalChatChannelData(
 | 
				
			||||||
 | 
					      {required this.id,
 | 
				
			||||||
 | 
					      required this.alias,
 | 
				
			||||||
 | 
					      required this.content,
 | 
				
			||||||
 | 
					      required this.createdAt});
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, Expression> toColumns(bool nullToAbsent) {
 | 
				
			||||||
 | 
					    final map = <String, Expression>{};
 | 
				
			||||||
 | 
					    map['id'] = Variable<int>(id);
 | 
				
			||||||
 | 
					    map['alias'] = Variable<String>(alias);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      map['content'] = Variable<String>(
 | 
				
			||||||
 | 
					          $SnLocalChatChannelTable.$convertercontent.toSql(content));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    map['created_at'] = Variable<DateTime>(createdAt);
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SnLocalChatChannelCompanion toCompanion(bool nullToAbsent) {
 | 
				
			||||||
 | 
					    return SnLocalChatChannelCompanion(
 | 
				
			||||||
 | 
					      id: Value(id),
 | 
				
			||||||
 | 
					      alias: Value(alias),
 | 
				
			||||||
 | 
					      content: Value(content),
 | 
				
			||||||
 | 
					      createdAt: Value(createdAt),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory SnLocalChatChannelData.fromJson(Map<String, dynamic> json,
 | 
				
			||||||
 | 
					      {ValueSerializer? serializer}) {
 | 
				
			||||||
 | 
					    serializer ??= driftRuntimeOptions.defaultSerializer;
 | 
				
			||||||
 | 
					    return SnLocalChatChannelData(
 | 
				
			||||||
 | 
					      id: serializer.fromJson<int>(json['id']),
 | 
				
			||||||
 | 
					      alias: serializer.fromJson<String>(json['alias']),
 | 
				
			||||||
 | 
					      content: $SnLocalChatChannelTable.$convertercontent
 | 
				
			||||||
 | 
					          .fromJson(serializer.fromJson<Map<String, Object?>>(json['content'])),
 | 
				
			||||||
 | 
					      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
 | 
				
			||||||
 | 
					    serializer ??= driftRuntimeOptions.defaultSerializer;
 | 
				
			||||||
 | 
					    return <String, dynamic>{
 | 
				
			||||||
 | 
					      'id': serializer.toJson<int>(id),
 | 
				
			||||||
 | 
					      'alias': serializer.toJson<String>(alias),
 | 
				
			||||||
 | 
					      'content': serializer.toJson<Map<String, Object?>>(
 | 
				
			||||||
 | 
					          $SnLocalChatChannelTable.$convertercontent.toJson(content)),
 | 
				
			||||||
 | 
					      'createdAt': serializer.toJson<DateTime>(createdAt),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SnLocalChatChannelData copyWith(
 | 
				
			||||||
 | 
					          {int? id, String? alias, SnChannel? content, DateTime? createdAt}) =>
 | 
				
			||||||
 | 
					      SnLocalChatChannelData(
 | 
				
			||||||
 | 
					        id: id ?? this.id,
 | 
				
			||||||
 | 
					        alias: alias ?? this.alias,
 | 
				
			||||||
 | 
					        content: content ?? this.content,
 | 
				
			||||||
 | 
					        createdAt: createdAt ?? this.createdAt,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  SnLocalChatChannelData copyWithCompanion(SnLocalChatChannelCompanion data) {
 | 
				
			||||||
 | 
					    return SnLocalChatChannelData(
 | 
				
			||||||
 | 
					      id: data.id.present ? data.id.value : this.id,
 | 
				
			||||||
 | 
					      alias: data.alias.present ? data.alias.value : this.alias,
 | 
				
			||||||
 | 
					      content: data.content.present ? data.content.value : this.content,
 | 
				
			||||||
 | 
					      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return (StringBuffer('SnLocalChatChannelData(')
 | 
				
			||||||
 | 
					          ..write('id: $id, ')
 | 
				
			||||||
 | 
					          ..write('alias: $alias, ')
 | 
				
			||||||
 | 
					          ..write('content: $content, ')
 | 
				
			||||||
 | 
					          ..write('createdAt: $createdAt')
 | 
				
			||||||
 | 
					          ..write(')'))
 | 
				
			||||||
 | 
					        .toString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get hashCode => Object.hash(id, alias, content, createdAt);
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool operator ==(Object other) =>
 | 
				
			||||||
 | 
					      identical(this, other) ||
 | 
				
			||||||
 | 
					      (other is SnLocalChatChannelData &&
 | 
				
			||||||
 | 
					          other.id == this.id &&
 | 
				
			||||||
 | 
					          other.alias == this.alias &&
 | 
				
			||||||
 | 
					          other.content == this.content &&
 | 
				
			||||||
 | 
					          other.createdAt == this.createdAt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnLocalChatChannelCompanion
 | 
				
			||||||
 | 
					    extends UpdateCompanion<SnLocalChatChannelData> {
 | 
				
			||||||
 | 
					  final Value<int> id;
 | 
				
			||||||
 | 
					  final Value<String> alias;
 | 
				
			||||||
 | 
					  final Value<SnChannel> content;
 | 
				
			||||||
 | 
					  final Value<DateTime> createdAt;
 | 
				
			||||||
 | 
					  const SnLocalChatChannelCompanion({
 | 
				
			||||||
 | 
					    this.id = const Value.absent(),
 | 
				
			||||||
 | 
					    this.alias = const Value.absent(),
 | 
				
			||||||
 | 
					    this.content = const Value.absent(),
 | 
				
			||||||
 | 
					    this.createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  SnLocalChatChannelCompanion.insert({
 | 
				
			||||||
 | 
					    this.id = const Value.absent(),
 | 
				
			||||||
 | 
					    required String alias,
 | 
				
			||||||
 | 
					    required SnChannel content,
 | 
				
			||||||
 | 
					    this.createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					  })  : alias = Value(alias),
 | 
				
			||||||
 | 
					        content = Value(content);
 | 
				
			||||||
 | 
					  static Insertable<SnLocalChatChannelData> custom({
 | 
				
			||||||
 | 
					    Expression<int>? id,
 | 
				
			||||||
 | 
					    Expression<String>? alias,
 | 
				
			||||||
 | 
					    Expression<String>? content,
 | 
				
			||||||
 | 
					    Expression<DateTime>? createdAt,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    return RawValuesInsertable({
 | 
				
			||||||
 | 
					      if (id != null) 'id': id,
 | 
				
			||||||
 | 
					      if (alias != null) 'alias': alias,
 | 
				
			||||||
 | 
					      if (content != null) 'content': content,
 | 
				
			||||||
 | 
					      if (createdAt != null) 'created_at': createdAt,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SnLocalChatChannelCompanion copyWith(
 | 
				
			||||||
 | 
					      {Value<int>? id,
 | 
				
			||||||
 | 
					      Value<String>? alias,
 | 
				
			||||||
 | 
					      Value<SnChannel>? content,
 | 
				
			||||||
 | 
					      Value<DateTime>? createdAt}) {
 | 
				
			||||||
 | 
					    return SnLocalChatChannelCompanion(
 | 
				
			||||||
 | 
					      id: id ?? this.id,
 | 
				
			||||||
 | 
					      alias: alias ?? this.alias,
 | 
				
			||||||
 | 
					      content: content ?? this.content,
 | 
				
			||||||
 | 
					      createdAt: createdAt ?? this.createdAt,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, Expression> toColumns(bool nullToAbsent) {
 | 
				
			||||||
 | 
					    final map = <String, Expression>{};
 | 
				
			||||||
 | 
					    if (id.present) {
 | 
				
			||||||
 | 
					      map['id'] = Variable<int>(id.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (alias.present) {
 | 
				
			||||||
 | 
					      map['alias'] = Variable<String>(alias.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (content.present) {
 | 
				
			||||||
 | 
					      map['content'] = Variable<String>(
 | 
				
			||||||
 | 
					          $SnLocalChatChannelTable.$convertercontent.toSql(content.value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (createdAt.present) {
 | 
				
			||||||
 | 
					      map['created_at'] = Variable<DateTime>(createdAt.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return (StringBuffer('SnLocalChatChannelCompanion(')
 | 
				
			||||||
 | 
					          ..write('id: $id, ')
 | 
				
			||||||
 | 
					          ..write('alias: $alias, ')
 | 
				
			||||||
 | 
					          ..write('content: $content, ')
 | 
				
			||||||
 | 
					          ..write('createdAt: $createdAt')
 | 
				
			||||||
 | 
					          ..write(')'))
 | 
				
			||||||
 | 
					        .toString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $SnLocalChatMessageTable extends SnLocalChatMessage
 | 
				
			||||||
 | 
					    with TableInfo<$SnLocalChatMessageTable, SnLocalChatMessageData> {
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  final GeneratedDatabase attachedDatabase;
 | 
				
			||||||
 | 
					  final String? _alias;
 | 
				
			||||||
 | 
					  $SnLocalChatMessageTable(this.attachedDatabase, [this._alias]);
 | 
				
			||||||
 | 
					  static const VerificationMeta _idMeta = const VerificationMeta('id');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumn<int> id = GeneratedColumn<int>(
 | 
				
			||||||
 | 
					      'id', aliasedName, false,
 | 
				
			||||||
 | 
					      hasAutoIncrement: true,
 | 
				
			||||||
 | 
					      type: DriftSqlType.int,
 | 
				
			||||||
 | 
					      requiredDuringInsert: false,
 | 
				
			||||||
 | 
					      defaultConstraints:
 | 
				
			||||||
 | 
					          GeneratedColumn.constraintIsAlways('PRIMARY KEY AUTOINCREMENT'));
 | 
				
			||||||
 | 
					  static const VerificationMeta _channelIdMeta =
 | 
				
			||||||
 | 
					      const VerificationMeta('channelId');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumn<int> channelId = GeneratedColumn<int>(
 | 
				
			||||||
 | 
					      'channel_id', aliasedName, false,
 | 
				
			||||||
 | 
					      type: DriftSqlType.int, requiredDuringInsert: true);
 | 
				
			||||||
 | 
					  static const VerificationMeta _contentMeta =
 | 
				
			||||||
 | 
					      const VerificationMeta('content');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumnWithTypeConverter<SnChatMessage, String> content =
 | 
				
			||||||
 | 
					      GeneratedColumn<String>('content', aliasedName, false,
 | 
				
			||||||
 | 
					              type: DriftSqlType.string, requiredDuringInsert: true)
 | 
				
			||||||
 | 
					          .withConverter<SnChatMessage>(
 | 
				
			||||||
 | 
					              $SnLocalChatMessageTable.$convertercontent);
 | 
				
			||||||
 | 
					  static const VerificationMeta _createdAtMeta =
 | 
				
			||||||
 | 
					      const VerificationMeta('createdAt');
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  late final GeneratedColumn<DateTime> createdAt = GeneratedColumn<DateTime>(
 | 
				
			||||||
 | 
					      'created_at', aliasedName, false,
 | 
				
			||||||
 | 
					      type: DriftSqlType.dateTime,
 | 
				
			||||||
 | 
					      requiredDuringInsert: false,
 | 
				
			||||||
 | 
					      defaultValue: currentDateAndTime);
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  List<GeneratedColumn> get $columns => [id, channelId, content, createdAt];
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String get aliasedName => _alias ?? actualTableName;
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String get actualTableName => $name;
 | 
				
			||||||
 | 
					  static const String $name = 'sn_local_chat_message';
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  VerificationContext validateIntegrity(
 | 
				
			||||||
 | 
					      Insertable<SnLocalChatMessageData> instance,
 | 
				
			||||||
 | 
					      {bool isInserting = false}) {
 | 
				
			||||||
 | 
					    final context = VerificationContext();
 | 
				
			||||||
 | 
					    final data = instance.toColumns(true);
 | 
				
			||||||
 | 
					    if (data.containsKey('id')) {
 | 
				
			||||||
 | 
					      context.handle(_idMeta, id.isAcceptableOrUnknown(data['id']!, _idMeta));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (data.containsKey('channel_id')) {
 | 
				
			||||||
 | 
					      context.handle(_channelIdMeta,
 | 
				
			||||||
 | 
					          channelId.isAcceptableOrUnknown(data['channel_id']!, _channelIdMeta));
 | 
				
			||||||
 | 
					    } else if (isInserting) {
 | 
				
			||||||
 | 
					      context.missing(_channelIdMeta);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    context.handle(_contentMeta, const VerificationResult.success());
 | 
				
			||||||
 | 
					    if (data.containsKey('created_at')) {
 | 
				
			||||||
 | 
					      context.handle(_createdAtMeta,
 | 
				
			||||||
 | 
					          createdAt.isAcceptableOrUnknown(data['created_at']!, _createdAtMeta));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return context;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Set<GeneratedColumn> get $primaryKey => {id};
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  SnLocalChatMessageData map(Map<String, dynamic> data, {String? tablePrefix}) {
 | 
				
			||||||
 | 
					    final effectivePrefix = tablePrefix != null ? '$tablePrefix.' : '';
 | 
				
			||||||
 | 
					    return SnLocalChatMessageData(
 | 
				
			||||||
 | 
					      id: attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					          .read(DriftSqlType.int, data['${effectivePrefix}id'])!,
 | 
				
			||||||
 | 
					      channelId: attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					          .read(DriftSqlType.int, data['${effectivePrefix}channel_id'])!,
 | 
				
			||||||
 | 
					      content: $SnLocalChatMessageTable.$convertercontent.fromSql(
 | 
				
			||||||
 | 
					          attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					              .read(DriftSqlType.string, data['${effectivePrefix}content'])!),
 | 
				
			||||||
 | 
					      createdAt: attachedDatabase.typeMapping
 | 
				
			||||||
 | 
					          .read(DriftSqlType.dateTime, data['${effectivePrefix}created_at'])!,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  $SnLocalChatMessageTable createAlias(String alias) {
 | 
				
			||||||
 | 
					    return $SnLocalChatMessageTable(attachedDatabase, alias);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  static JsonTypeConverter2<SnChatMessage, String, Map<String, Object?>>
 | 
				
			||||||
 | 
					      $convertercontent = const SnMessageConverter();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnLocalChatMessageData extends DataClass
 | 
				
			||||||
 | 
					    implements Insertable<SnLocalChatMessageData> {
 | 
				
			||||||
 | 
					  final int id;
 | 
				
			||||||
 | 
					  final int channelId;
 | 
				
			||||||
 | 
					  final SnChatMessage content;
 | 
				
			||||||
 | 
					  final DateTime createdAt;
 | 
				
			||||||
 | 
					  const SnLocalChatMessageData(
 | 
				
			||||||
 | 
					      {required this.id,
 | 
				
			||||||
 | 
					      required this.channelId,
 | 
				
			||||||
 | 
					      required this.content,
 | 
				
			||||||
 | 
					      required this.createdAt});
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, Expression> toColumns(bool nullToAbsent) {
 | 
				
			||||||
 | 
					    final map = <String, Expression>{};
 | 
				
			||||||
 | 
					    map['id'] = Variable<int>(id);
 | 
				
			||||||
 | 
					    map['channel_id'] = Variable<int>(channelId);
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      map['content'] = Variable<String>(
 | 
				
			||||||
 | 
					          $SnLocalChatMessageTable.$convertercontent.toSql(content));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    map['created_at'] = Variable<DateTime>(createdAt);
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SnLocalChatMessageCompanion toCompanion(bool nullToAbsent) {
 | 
				
			||||||
 | 
					    return SnLocalChatMessageCompanion(
 | 
				
			||||||
 | 
					      id: Value(id),
 | 
				
			||||||
 | 
					      channelId: Value(channelId),
 | 
				
			||||||
 | 
					      content: Value(content),
 | 
				
			||||||
 | 
					      createdAt: Value(createdAt),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  factory SnLocalChatMessageData.fromJson(Map<String, dynamic> json,
 | 
				
			||||||
 | 
					      {ValueSerializer? serializer}) {
 | 
				
			||||||
 | 
					    serializer ??= driftRuntimeOptions.defaultSerializer;
 | 
				
			||||||
 | 
					    return SnLocalChatMessageData(
 | 
				
			||||||
 | 
					      id: serializer.fromJson<int>(json['id']),
 | 
				
			||||||
 | 
					      channelId: serializer.fromJson<int>(json['channelId']),
 | 
				
			||||||
 | 
					      content: $SnLocalChatMessageTable.$convertercontent
 | 
				
			||||||
 | 
					          .fromJson(serializer.fromJson<Map<String, Object?>>(json['content'])),
 | 
				
			||||||
 | 
					      createdAt: serializer.fromJson<DateTime>(json['createdAt']),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, dynamic> toJson({ValueSerializer? serializer}) {
 | 
				
			||||||
 | 
					    serializer ??= driftRuntimeOptions.defaultSerializer;
 | 
				
			||||||
 | 
					    return <String, dynamic>{
 | 
				
			||||||
 | 
					      'id': serializer.toJson<int>(id),
 | 
				
			||||||
 | 
					      'channelId': serializer.toJson<int>(channelId),
 | 
				
			||||||
 | 
					      'content': serializer.toJson<Map<String, Object?>>(
 | 
				
			||||||
 | 
					          $SnLocalChatMessageTable.$convertercontent.toJson(content)),
 | 
				
			||||||
 | 
					      'createdAt': serializer.toJson<DateTime>(createdAt),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SnLocalChatMessageData copyWith(
 | 
				
			||||||
 | 
					          {int? id,
 | 
				
			||||||
 | 
					          int? channelId,
 | 
				
			||||||
 | 
					          SnChatMessage? content,
 | 
				
			||||||
 | 
					          DateTime? createdAt}) =>
 | 
				
			||||||
 | 
					      SnLocalChatMessageData(
 | 
				
			||||||
 | 
					        id: id ?? this.id,
 | 
				
			||||||
 | 
					        channelId: channelId ?? this.channelId,
 | 
				
			||||||
 | 
					        content: content ?? this.content,
 | 
				
			||||||
 | 
					        createdAt: createdAt ?? this.createdAt,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					  SnLocalChatMessageData copyWithCompanion(SnLocalChatMessageCompanion data) {
 | 
				
			||||||
 | 
					    return SnLocalChatMessageData(
 | 
				
			||||||
 | 
					      id: data.id.present ? data.id.value : this.id,
 | 
				
			||||||
 | 
					      channelId: data.channelId.present ? data.channelId.value : this.channelId,
 | 
				
			||||||
 | 
					      content: data.content.present ? data.content.value : this.content,
 | 
				
			||||||
 | 
					      createdAt: data.createdAt.present ? data.createdAt.value : this.createdAt,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return (StringBuffer('SnLocalChatMessageData(')
 | 
				
			||||||
 | 
					          ..write('id: $id, ')
 | 
				
			||||||
 | 
					          ..write('channelId: $channelId, ')
 | 
				
			||||||
 | 
					          ..write('content: $content, ')
 | 
				
			||||||
 | 
					          ..write('createdAt: $createdAt')
 | 
				
			||||||
 | 
					          ..write(')'))
 | 
				
			||||||
 | 
					        .toString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  int get hashCode => Object.hash(id, channelId, content, createdAt);
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  bool operator ==(Object other) =>
 | 
				
			||||||
 | 
					      identical(this, other) ||
 | 
				
			||||||
 | 
					      (other is SnLocalChatMessageData &&
 | 
				
			||||||
 | 
					          other.id == this.id &&
 | 
				
			||||||
 | 
					          other.channelId == this.channelId &&
 | 
				
			||||||
 | 
					          other.content == this.content &&
 | 
				
			||||||
 | 
					          other.createdAt == this.createdAt);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SnLocalChatMessageCompanion
 | 
				
			||||||
 | 
					    extends UpdateCompanion<SnLocalChatMessageData> {
 | 
				
			||||||
 | 
					  final Value<int> id;
 | 
				
			||||||
 | 
					  final Value<int> channelId;
 | 
				
			||||||
 | 
					  final Value<SnChatMessage> content;
 | 
				
			||||||
 | 
					  final Value<DateTime> createdAt;
 | 
				
			||||||
 | 
					  const SnLocalChatMessageCompanion({
 | 
				
			||||||
 | 
					    this.id = const Value.absent(),
 | 
				
			||||||
 | 
					    this.channelId = const Value.absent(),
 | 
				
			||||||
 | 
					    this.content = const Value.absent(),
 | 
				
			||||||
 | 
					    this.createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  SnLocalChatMessageCompanion.insert({
 | 
				
			||||||
 | 
					    this.id = const Value.absent(),
 | 
				
			||||||
 | 
					    required int channelId,
 | 
				
			||||||
 | 
					    required SnChatMessage content,
 | 
				
			||||||
 | 
					    this.createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					  })  : channelId = Value(channelId),
 | 
				
			||||||
 | 
					        content = Value(content);
 | 
				
			||||||
 | 
					  static Insertable<SnLocalChatMessageData> custom({
 | 
				
			||||||
 | 
					    Expression<int>? id,
 | 
				
			||||||
 | 
					    Expression<int>? channelId,
 | 
				
			||||||
 | 
					    Expression<String>? content,
 | 
				
			||||||
 | 
					    Expression<DateTime>? createdAt,
 | 
				
			||||||
 | 
					  }) {
 | 
				
			||||||
 | 
					    return RawValuesInsertable({
 | 
				
			||||||
 | 
					      if (id != null) 'id': id,
 | 
				
			||||||
 | 
					      if (channelId != null) 'channel_id': channelId,
 | 
				
			||||||
 | 
					      if (content != null) 'content': content,
 | 
				
			||||||
 | 
					      if (createdAt != null) 'created_at': createdAt,
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  SnLocalChatMessageCompanion copyWith(
 | 
				
			||||||
 | 
					      {Value<int>? id,
 | 
				
			||||||
 | 
					      Value<int>? channelId,
 | 
				
			||||||
 | 
					      Value<SnChatMessage>? content,
 | 
				
			||||||
 | 
					      Value<DateTime>? createdAt}) {
 | 
				
			||||||
 | 
					    return SnLocalChatMessageCompanion(
 | 
				
			||||||
 | 
					      id: id ?? this.id,
 | 
				
			||||||
 | 
					      channelId: channelId ?? this.channelId,
 | 
				
			||||||
 | 
					      content: content ?? this.content,
 | 
				
			||||||
 | 
					      createdAt: createdAt ?? this.createdAt,
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Map<String, Expression> toColumns(bool nullToAbsent) {
 | 
				
			||||||
 | 
					    final map = <String, Expression>{};
 | 
				
			||||||
 | 
					    if (id.present) {
 | 
				
			||||||
 | 
					      map['id'] = Variable<int>(id.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (channelId.present) {
 | 
				
			||||||
 | 
					      map['channel_id'] = Variable<int>(channelId.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (content.present) {
 | 
				
			||||||
 | 
					      map['content'] = Variable<String>(
 | 
				
			||||||
 | 
					          $SnLocalChatMessageTable.$convertercontent.toSql(content.value));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (createdAt.present) {
 | 
				
			||||||
 | 
					      map['created_at'] = Variable<DateTime>(createdAt.value);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return map;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  String toString() {
 | 
				
			||||||
 | 
					    return (StringBuffer('SnLocalChatMessageCompanion(')
 | 
				
			||||||
 | 
					          ..write('id: $id, ')
 | 
				
			||||||
 | 
					          ..write('channelId: $channelId, ')
 | 
				
			||||||
 | 
					          ..write('content: $content, ')
 | 
				
			||||||
 | 
					          ..write('createdAt: $createdAt')
 | 
				
			||||||
 | 
					          ..write(')'))
 | 
				
			||||||
 | 
					        .toString();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					abstract class _$AppDatabase extends GeneratedDatabase {
 | 
				
			||||||
 | 
					  _$AppDatabase(QueryExecutor e) : super(e);
 | 
				
			||||||
 | 
					  $AppDatabaseManager get managers => $AppDatabaseManager(this);
 | 
				
			||||||
 | 
					  late final $SnLocalChatChannelTable snLocalChatChannel =
 | 
				
			||||||
 | 
					      $SnLocalChatChannelTable(this);
 | 
				
			||||||
 | 
					  late final $SnLocalChatMessageTable snLocalChatMessage =
 | 
				
			||||||
 | 
					      $SnLocalChatMessageTable(this);
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  Iterable<TableInfo<Table, Object?>> get allTables =>
 | 
				
			||||||
 | 
					      allSchemaEntities.whereType<TableInfo<Table, Object?>>();
 | 
				
			||||||
 | 
					  @override
 | 
				
			||||||
 | 
					  List<DatabaseSchemaEntity> get allSchemaEntities =>
 | 
				
			||||||
 | 
					      [snLocalChatChannel, snLocalChatMessage];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef $$SnLocalChatChannelTableCreateCompanionBuilder
 | 
				
			||||||
 | 
					    = SnLocalChatChannelCompanion Function({
 | 
				
			||||||
 | 
					  Value<int> id,
 | 
				
			||||||
 | 
					  required String alias,
 | 
				
			||||||
 | 
					  required SnChannel content,
 | 
				
			||||||
 | 
					  Value<DateTime> createdAt,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					typedef $$SnLocalChatChannelTableUpdateCompanionBuilder
 | 
				
			||||||
 | 
					    = SnLocalChatChannelCompanion Function({
 | 
				
			||||||
 | 
					  Value<int> id,
 | 
				
			||||||
 | 
					  Value<String> alias,
 | 
				
			||||||
 | 
					  Value<SnChannel> content,
 | 
				
			||||||
 | 
					  Value<DateTime> createdAt,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatChannelTableFilterComposer
 | 
				
			||||||
 | 
					    extends Composer<_$AppDatabase, $SnLocalChatChannelTable> {
 | 
				
			||||||
 | 
					  $$SnLocalChatChannelTableFilterComposer({
 | 
				
			||||||
 | 
					    required super.$db,
 | 
				
			||||||
 | 
					    required super.$table,
 | 
				
			||||||
 | 
					    super.joinBuilder,
 | 
				
			||||||
 | 
					    super.$addJoinBuilderToRootComposer,
 | 
				
			||||||
 | 
					    super.$removeJoinBuilderFromRootComposer,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  ColumnFilters<int> get id => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.id, builder: (column) => ColumnFilters(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnFilters<String> get alias => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.alias, builder: (column) => ColumnFilters(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnWithTypeConverterFilters<SnChannel, SnChannel, String> get content =>
 | 
				
			||||||
 | 
					      $composableBuilder(
 | 
				
			||||||
 | 
					          column: $table.content,
 | 
				
			||||||
 | 
					          builder: (column) => ColumnWithTypeConverterFilters(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnFilters<DateTime> get createdAt => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.createdAt, builder: (column) => ColumnFilters(column));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatChannelTableOrderingComposer
 | 
				
			||||||
 | 
					    extends Composer<_$AppDatabase, $SnLocalChatChannelTable> {
 | 
				
			||||||
 | 
					  $$SnLocalChatChannelTableOrderingComposer({
 | 
				
			||||||
 | 
					    required super.$db,
 | 
				
			||||||
 | 
					    required super.$table,
 | 
				
			||||||
 | 
					    super.joinBuilder,
 | 
				
			||||||
 | 
					    super.$addJoinBuilderToRootComposer,
 | 
				
			||||||
 | 
					    super.$removeJoinBuilderFromRootComposer,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  ColumnOrderings<int> get id => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.id, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnOrderings<String> get alias => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.alias, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnOrderings<String> get content => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.content, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnOrderings<DateTime> get createdAt => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.createdAt, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatChannelTableAnnotationComposer
 | 
				
			||||||
 | 
					    extends Composer<_$AppDatabase, $SnLocalChatChannelTable> {
 | 
				
			||||||
 | 
					  $$SnLocalChatChannelTableAnnotationComposer({
 | 
				
			||||||
 | 
					    required super.$db,
 | 
				
			||||||
 | 
					    required super.$table,
 | 
				
			||||||
 | 
					    super.joinBuilder,
 | 
				
			||||||
 | 
					    super.$addJoinBuilderToRootComposer,
 | 
				
			||||||
 | 
					    super.$removeJoinBuilderFromRootComposer,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  GeneratedColumn<int> get id =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.id, builder: (column) => column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GeneratedColumn<String> get alias =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.alias, builder: (column) => column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GeneratedColumnWithTypeConverter<SnChannel, String> get content =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.content, builder: (column) => column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GeneratedColumn<DateTime> get createdAt =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.createdAt, builder: (column) => column);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatChannelTableTableManager extends RootTableManager<
 | 
				
			||||||
 | 
					    _$AppDatabase,
 | 
				
			||||||
 | 
					    $SnLocalChatChannelTable,
 | 
				
			||||||
 | 
					    SnLocalChatChannelData,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableFilterComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableOrderingComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableAnnotationComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableCreateCompanionBuilder,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableUpdateCompanionBuilder,
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					      SnLocalChatChannelData,
 | 
				
			||||||
 | 
					      BaseReferences<_$AppDatabase, $SnLocalChatChannelTable,
 | 
				
			||||||
 | 
					          SnLocalChatChannelData>
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    SnLocalChatChannelData,
 | 
				
			||||||
 | 
					    PrefetchHooks Function()> {
 | 
				
			||||||
 | 
					  $$SnLocalChatChannelTableTableManager(
 | 
				
			||||||
 | 
					      _$AppDatabase db, $SnLocalChatChannelTable table)
 | 
				
			||||||
 | 
					      : super(TableManagerState(
 | 
				
			||||||
 | 
					          db: db,
 | 
				
			||||||
 | 
					          table: table,
 | 
				
			||||||
 | 
					          createFilteringComposer: () =>
 | 
				
			||||||
 | 
					              $$SnLocalChatChannelTableFilterComposer($db: db, $table: table),
 | 
				
			||||||
 | 
					          createOrderingComposer: () =>
 | 
				
			||||||
 | 
					              $$SnLocalChatChannelTableOrderingComposer($db: db, $table: table),
 | 
				
			||||||
 | 
					          createComputedFieldComposer: () =>
 | 
				
			||||||
 | 
					              $$SnLocalChatChannelTableAnnotationComposer(
 | 
				
			||||||
 | 
					                  $db: db, $table: table),
 | 
				
			||||||
 | 
					          updateCompanionCallback: ({
 | 
				
			||||||
 | 
					            Value<int> id = const Value.absent(),
 | 
				
			||||||
 | 
					            Value<String> alias = const Value.absent(),
 | 
				
			||||||
 | 
					            Value<SnChannel> content = const Value.absent(),
 | 
				
			||||||
 | 
					            Value<DateTime> createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					          }) =>
 | 
				
			||||||
 | 
					              SnLocalChatChannelCompanion(
 | 
				
			||||||
 | 
					            id: id,
 | 
				
			||||||
 | 
					            alias: alias,
 | 
				
			||||||
 | 
					            content: content,
 | 
				
			||||||
 | 
					            createdAt: createdAt,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          createCompanionCallback: ({
 | 
				
			||||||
 | 
					            Value<int> id = const Value.absent(),
 | 
				
			||||||
 | 
					            required String alias,
 | 
				
			||||||
 | 
					            required SnChannel content,
 | 
				
			||||||
 | 
					            Value<DateTime> createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					          }) =>
 | 
				
			||||||
 | 
					              SnLocalChatChannelCompanion.insert(
 | 
				
			||||||
 | 
					            id: id,
 | 
				
			||||||
 | 
					            alias: alias,
 | 
				
			||||||
 | 
					            content: content,
 | 
				
			||||||
 | 
					            createdAt: createdAt,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          withReferenceMapper: (p0) => p0
 | 
				
			||||||
 | 
					              .map((e) => (e.readTable(table), BaseReferences(db, table, e)))
 | 
				
			||||||
 | 
					              .toList(),
 | 
				
			||||||
 | 
					          prefetchHooksCallback: null,
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef $$SnLocalChatChannelTableProcessedTableManager = ProcessedTableManager<
 | 
				
			||||||
 | 
					    _$AppDatabase,
 | 
				
			||||||
 | 
					    $SnLocalChatChannelTable,
 | 
				
			||||||
 | 
					    SnLocalChatChannelData,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableFilterComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableOrderingComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableAnnotationComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableCreateCompanionBuilder,
 | 
				
			||||||
 | 
					    $$SnLocalChatChannelTableUpdateCompanionBuilder,
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					      SnLocalChatChannelData,
 | 
				
			||||||
 | 
					      BaseReferences<_$AppDatabase, $SnLocalChatChannelTable,
 | 
				
			||||||
 | 
					          SnLocalChatChannelData>
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    SnLocalChatChannelData,
 | 
				
			||||||
 | 
					    PrefetchHooks Function()>;
 | 
				
			||||||
 | 
					typedef $$SnLocalChatMessageTableCreateCompanionBuilder
 | 
				
			||||||
 | 
					    = SnLocalChatMessageCompanion Function({
 | 
				
			||||||
 | 
					  Value<int> id,
 | 
				
			||||||
 | 
					  required int channelId,
 | 
				
			||||||
 | 
					  required SnChatMessage content,
 | 
				
			||||||
 | 
					  Value<DateTime> createdAt,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					typedef $$SnLocalChatMessageTableUpdateCompanionBuilder
 | 
				
			||||||
 | 
					    = SnLocalChatMessageCompanion Function({
 | 
				
			||||||
 | 
					  Value<int> id,
 | 
				
			||||||
 | 
					  Value<int> channelId,
 | 
				
			||||||
 | 
					  Value<SnChatMessage> content,
 | 
				
			||||||
 | 
					  Value<DateTime> createdAt,
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatMessageTableFilterComposer
 | 
				
			||||||
 | 
					    extends Composer<_$AppDatabase, $SnLocalChatMessageTable> {
 | 
				
			||||||
 | 
					  $$SnLocalChatMessageTableFilterComposer({
 | 
				
			||||||
 | 
					    required super.$db,
 | 
				
			||||||
 | 
					    required super.$table,
 | 
				
			||||||
 | 
					    super.joinBuilder,
 | 
				
			||||||
 | 
					    super.$addJoinBuilderToRootComposer,
 | 
				
			||||||
 | 
					    super.$removeJoinBuilderFromRootComposer,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  ColumnFilters<int> get id => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.id, builder: (column) => ColumnFilters(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnFilters<int> get channelId => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.channelId, builder: (column) => ColumnFilters(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnWithTypeConverterFilters<SnChatMessage, SnChatMessage, String>
 | 
				
			||||||
 | 
					      get content => $composableBuilder(
 | 
				
			||||||
 | 
					          column: $table.content,
 | 
				
			||||||
 | 
					          builder: (column) => ColumnWithTypeConverterFilters(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnFilters<DateTime> get createdAt => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.createdAt, builder: (column) => ColumnFilters(column));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatMessageTableOrderingComposer
 | 
				
			||||||
 | 
					    extends Composer<_$AppDatabase, $SnLocalChatMessageTable> {
 | 
				
			||||||
 | 
					  $$SnLocalChatMessageTableOrderingComposer({
 | 
				
			||||||
 | 
					    required super.$db,
 | 
				
			||||||
 | 
					    required super.$table,
 | 
				
			||||||
 | 
					    super.joinBuilder,
 | 
				
			||||||
 | 
					    super.$addJoinBuilderToRootComposer,
 | 
				
			||||||
 | 
					    super.$removeJoinBuilderFromRootComposer,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  ColumnOrderings<int> get id => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.id, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnOrderings<int> get channelId => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.channelId, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnOrderings<String> get content => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.content, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ColumnOrderings<DateTime> get createdAt => $composableBuilder(
 | 
				
			||||||
 | 
					      column: $table.createdAt, builder: (column) => ColumnOrderings(column));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatMessageTableAnnotationComposer
 | 
				
			||||||
 | 
					    extends Composer<_$AppDatabase, $SnLocalChatMessageTable> {
 | 
				
			||||||
 | 
					  $$SnLocalChatMessageTableAnnotationComposer({
 | 
				
			||||||
 | 
					    required super.$db,
 | 
				
			||||||
 | 
					    required super.$table,
 | 
				
			||||||
 | 
					    super.joinBuilder,
 | 
				
			||||||
 | 
					    super.$addJoinBuilderToRootComposer,
 | 
				
			||||||
 | 
					    super.$removeJoinBuilderFromRootComposer,
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					  GeneratedColumn<int> get id =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.id, builder: (column) => column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GeneratedColumn<int> get channelId =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.channelId, builder: (column) => column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GeneratedColumnWithTypeConverter<SnChatMessage, String> get content =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.content, builder: (column) => column);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  GeneratedColumn<DateTime> get createdAt =>
 | 
				
			||||||
 | 
					      $composableBuilder(column: $table.createdAt, builder: (column) => column);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $$SnLocalChatMessageTableTableManager extends RootTableManager<
 | 
				
			||||||
 | 
					    _$AppDatabase,
 | 
				
			||||||
 | 
					    $SnLocalChatMessageTable,
 | 
				
			||||||
 | 
					    SnLocalChatMessageData,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableFilterComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableOrderingComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableAnnotationComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableCreateCompanionBuilder,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableUpdateCompanionBuilder,
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					      SnLocalChatMessageData,
 | 
				
			||||||
 | 
					      BaseReferences<_$AppDatabase, $SnLocalChatMessageTable,
 | 
				
			||||||
 | 
					          SnLocalChatMessageData>
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    SnLocalChatMessageData,
 | 
				
			||||||
 | 
					    PrefetchHooks Function()> {
 | 
				
			||||||
 | 
					  $$SnLocalChatMessageTableTableManager(
 | 
				
			||||||
 | 
					      _$AppDatabase db, $SnLocalChatMessageTable table)
 | 
				
			||||||
 | 
					      : super(TableManagerState(
 | 
				
			||||||
 | 
					          db: db,
 | 
				
			||||||
 | 
					          table: table,
 | 
				
			||||||
 | 
					          createFilteringComposer: () =>
 | 
				
			||||||
 | 
					              $$SnLocalChatMessageTableFilterComposer($db: db, $table: table),
 | 
				
			||||||
 | 
					          createOrderingComposer: () =>
 | 
				
			||||||
 | 
					              $$SnLocalChatMessageTableOrderingComposer($db: db, $table: table),
 | 
				
			||||||
 | 
					          createComputedFieldComposer: () =>
 | 
				
			||||||
 | 
					              $$SnLocalChatMessageTableAnnotationComposer(
 | 
				
			||||||
 | 
					                  $db: db, $table: table),
 | 
				
			||||||
 | 
					          updateCompanionCallback: ({
 | 
				
			||||||
 | 
					            Value<int> id = const Value.absent(),
 | 
				
			||||||
 | 
					            Value<int> channelId = const Value.absent(),
 | 
				
			||||||
 | 
					            Value<SnChatMessage> content = const Value.absent(),
 | 
				
			||||||
 | 
					            Value<DateTime> createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					          }) =>
 | 
				
			||||||
 | 
					              SnLocalChatMessageCompanion(
 | 
				
			||||||
 | 
					            id: id,
 | 
				
			||||||
 | 
					            channelId: channelId,
 | 
				
			||||||
 | 
					            content: content,
 | 
				
			||||||
 | 
					            createdAt: createdAt,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          createCompanionCallback: ({
 | 
				
			||||||
 | 
					            Value<int> id = const Value.absent(),
 | 
				
			||||||
 | 
					            required int channelId,
 | 
				
			||||||
 | 
					            required SnChatMessage content,
 | 
				
			||||||
 | 
					            Value<DateTime> createdAt = const Value.absent(),
 | 
				
			||||||
 | 
					          }) =>
 | 
				
			||||||
 | 
					              SnLocalChatMessageCompanion.insert(
 | 
				
			||||||
 | 
					            id: id,
 | 
				
			||||||
 | 
					            channelId: channelId,
 | 
				
			||||||
 | 
					            content: content,
 | 
				
			||||||
 | 
					            createdAt: createdAt,
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          withReferenceMapper: (p0) => p0
 | 
				
			||||||
 | 
					              .map((e) => (e.readTable(table), BaseReferences(db, table, e)))
 | 
				
			||||||
 | 
					              .toList(),
 | 
				
			||||||
 | 
					          prefetchHooksCallback: null,
 | 
				
			||||||
 | 
					        ));
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef $$SnLocalChatMessageTableProcessedTableManager = ProcessedTableManager<
 | 
				
			||||||
 | 
					    _$AppDatabase,
 | 
				
			||||||
 | 
					    $SnLocalChatMessageTable,
 | 
				
			||||||
 | 
					    SnLocalChatMessageData,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableFilterComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableOrderingComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableAnnotationComposer,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableCreateCompanionBuilder,
 | 
				
			||||||
 | 
					    $$SnLocalChatMessageTableUpdateCompanionBuilder,
 | 
				
			||||||
 | 
					    (
 | 
				
			||||||
 | 
					      SnLocalChatMessageData,
 | 
				
			||||||
 | 
					      BaseReferences<_$AppDatabase, $SnLocalChatMessageTable,
 | 
				
			||||||
 | 
					          SnLocalChatMessageData>
 | 
				
			||||||
 | 
					    ),
 | 
				
			||||||
 | 
					    SnLocalChatMessageData,
 | 
				
			||||||
 | 
					    PrefetchHooks Function()>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class $AppDatabaseManager {
 | 
				
			||||||
 | 
					  final _$AppDatabase _db;
 | 
				
			||||||
 | 
					  $AppDatabaseManager(this._db);
 | 
				
			||||||
 | 
					  $$SnLocalChatChannelTableTableManager get snLocalChatChannel =>
 | 
				
			||||||
 | 
					      $$SnLocalChatChannelTableTableManager(_db, _db.snLocalChatChannel);
 | 
				
			||||||
 | 
					  $$SnLocalChatMessageTableTableManager get snLocalChatMessage =>
 | 
				
			||||||
 | 
					      $$SnLocalChatMessageTableTableManager(_db, _db.snLocalChatMessage);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										8
									
								
								lib/database/drift_worker.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								lib/database/drift_worker.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					import 'package:drift/wasm.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Use `dart compile js -O4 ./drift_worker.dart` to compile this file.
 | 
				
			||||||
 | 
					// And place it in the web/ directory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// When compiled with dart2js, this file defines a dedicated or shared web
 | 
				
			||||||
 | 
					// worker used by drift.
 | 
				
			||||||
 | 
					void main() => WasmDatabase.workerMainForOpen();
 | 
				
			||||||
@@ -13,7 +13,6 @@ import 'package:flutter/foundation.dart';
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:flutter/services.dart';
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:go_router/go_router.dart';
 | 
					import 'package:go_router/go_router.dart';
 | 
				
			||||||
import 'package:hive_flutter/hive_flutter.dart';
 | 
					 | 
				
			||||||
import 'package:hotkey_manager/hotkey_manager.dart';
 | 
					import 'package:hotkey_manager/hotkey_manager.dart';
 | 
				
			||||||
import 'package:package_info_plus/package_info_plus.dart';
 | 
					import 'package:package_info_plus/package_info_plus.dart';
 | 
				
			||||||
import 'package:provider/provider.dart';
 | 
					import 'package:provider/provider.dart';
 | 
				
			||||||
@@ -24,6 +23,7 @@ import 'package:surface/firebase_options.dart';
 | 
				
			|||||||
import 'package:surface/providers/channel.dart';
 | 
					import 'package:surface/providers/channel.dart';
 | 
				
			||||||
import 'package:surface/providers/chat_call.dart';
 | 
					import 'package:surface/providers/chat_call.dart';
 | 
				
			||||||
import 'package:surface/providers/config.dart';
 | 
					import 'package:surface/providers/config.dart';
 | 
				
			||||||
 | 
					import 'package:surface/providers/database.dart';
 | 
				
			||||||
import 'package:surface/providers/link_preview.dart';
 | 
					import 'package:surface/providers/link_preview.dart';
 | 
				
			||||||
import 'package:surface/providers/navigation.dart';
 | 
					import 'package:surface/providers/navigation.dart';
 | 
				
			||||||
import 'package:surface/providers/notification.dart';
 | 
					import 'package:surface/providers/notification.dart';
 | 
				
			||||||
@@ -40,8 +40,6 @@ import 'package:surface/providers/userinfo.dart';
 | 
				
			|||||||
import 'package:surface/providers/websocket.dart';
 | 
					import 'package:surface/providers/websocket.dart';
 | 
				
			||||||
import 'package:surface/providers/widget.dart';
 | 
					import 'package:surface/providers/widget.dart';
 | 
				
			||||||
import 'package:surface/router.dart';
 | 
					import 'package:surface/router.dart';
 | 
				
			||||||
import 'package:surface/types/chat.dart';
 | 
					 | 
				
			||||||
import 'package:surface/types/realm.dart';
 | 
					 | 
				
			||||||
import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
 | 
					import 'package:flutter_web_plugins/url_strategy.dart' show usePathUrlStrategy;
 | 
				
			||||||
import 'package:surface/widgets/dialog.dart';
 | 
					import 'package:surface/widgets/dialog.dart';
 | 
				
			||||||
import 'package:tray_manager/tray_manager.dart';
 | 
					import 'package:tray_manager/tray_manager.dart';
 | 
				
			||||||
@@ -82,12 +80,6 @@ void main() async {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  await EasyLocalization.ensureInitialized();
 | 
					  await EasyLocalization.ensureInitialized();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  await Hive.initFlutter();
 | 
					 | 
				
			||||||
  Hive.registerAdapter(SnChannelImplAdapter());
 | 
					 | 
				
			||||||
  Hive.registerAdapter(SnRealmImplAdapter());
 | 
					 | 
				
			||||||
  Hive.registerAdapter(SnChannelMemberImplAdapter());
 | 
					 | 
				
			||||||
  Hive.registerAdapter(SnChatMessageImplAdapter());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  if (!kIsWeb && !Platform.isLinux) {
 | 
					  if (!kIsWeb && !Platform.isLinux) {
 | 
				
			||||||
    await Firebase.initializeApp(
 | 
					    await Firebase.initializeApp(
 | 
				
			||||||
      options: DefaultFirebaseOptions.currentPlatform,
 | 
					      options: DefaultFirebaseOptions.currentPlatform,
 | 
				
			||||||
@@ -114,7 +106,8 @@ void main() async {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!kIsWeb && Platform.isAndroid) {
 | 
					  if (!kIsWeb && Platform.isAndroid) {
 | 
				
			||||||
    final ImagePickerPlatform imagePickerImplementation = ImagePickerPlatform.instance;
 | 
					    final ImagePickerPlatform imagePickerImplementation =
 | 
				
			||||||
 | 
					        ImagePickerPlatform.instance;
 | 
				
			||||||
    if (imagePickerImplementation is ImagePickerAndroid) {
 | 
					    if (imagePickerImplementation is ImagePickerAndroid) {
 | 
				
			||||||
      imagePickerImplementation.useAndroidPhotoPicker = true;
 | 
					      imagePickerImplementation.useAndroidPhotoPicker = true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -142,6 +135,9 @@ class SolianApp extends StatelessWidget {
 | 
				
			|||||||
        assetLoader: JsonAssetLoader(),
 | 
					        assetLoader: JsonAssetLoader(),
 | 
				
			||||||
        child: MultiProvider(
 | 
					        child: MultiProvider(
 | 
				
			||||||
          providers: [
 | 
					          providers: [
 | 
				
			||||||
 | 
					            // Infrastructure layer
 | 
				
			||||||
 | 
					            Provider(create: (ctx) => DatabaseProvider(ctx)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // System extensions layer
 | 
					            // System extensions layer
 | 
				
			||||||
            Provider(create: (ctx) => HomeWidgetProvider(ctx)),
 | 
					            Provider(create: (ctx) => HomeWidgetProvider(ctx)),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -230,7 +226,8 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
 | 
				
			|||||||
    if (prefs.containsKey('first_boot_time')) {
 | 
					    if (prefs.containsKey('first_boot_time')) {
 | 
				
			||||||
      final rawTime = prefs.getString('first_boot_time');
 | 
					      final rawTime = prefs.getString('first_boot_time');
 | 
				
			||||||
      final time = DateTime.tryParse(rawTime ?? '');
 | 
					      final time = DateTime.tryParse(rawTime ?? '');
 | 
				
			||||||
      if (time != null && time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) {
 | 
					      if (time != null &&
 | 
				
			||||||
 | 
					          time.isBefore(DateTime.now().subtract(const Duration(days: 3)))) {
 | 
				
			||||||
        final inAppReview = InAppReview.instance;
 | 
					        final inAppReview = InAppReview.instance;
 | 
				
			||||||
        if (prefs.getBool('rating_requested') == true) return;
 | 
					        if (prefs.getBool('rating_requested') == true) return;
 | 
				
			||||||
        if (await inAppReview.isAvailable()) {
 | 
					        if (await inAppReview.isAvailable()) {
 | 
				
			||||||
@@ -258,13 +255,18 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
 | 
				
			|||||||
      ).get(
 | 
					      ).get(
 | 
				
			||||||
        'https://git.solsynth.dev/api/v1/repos/HyperNet/Surface/tags?page=1&limit=1',
 | 
					        'https://git.solsynth.dev/api/v1/repos/HyperNet/Surface/tags?page=1&limit=1',
 | 
				
			||||||
      );
 | 
					      );
 | 
				
			||||||
      final remoteVersionString = (resp.data as List).firstOrNull?['name'] ?? '0.0.0+0';
 | 
					      final remoteVersionString =
 | 
				
			||||||
 | 
					          (resp.data as List).firstOrNull?['name'] ?? '0.0.0+0';
 | 
				
			||||||
      final remoteVersion = Version.parse(remoteVersionString.split('+').first);
 | 
					      final remoteVersion = Version.parse(remoteVersionString.split('+').first);
 | 
				
			||||||
      final localVersion = Version.parse(localVersionString.split('+').first);
 | 
					      final localVersion = Version.parse(localVersionString.split('+').first);
 | 
				
			||||||
      final remoteBuildNumber = int.tryParse(remoteVersionString.split('+').last) ?? 0;
 | 
					      final remoteBuildNumber =
 | 
				
			||||||
      final localBuildNumber = int.tryParse(localVersionString.split('+').last) ?? 0;
 | 
					          int.tryParse(remoteVersionString.split('+').last) ?? 0;
 | 
				
			||||||
 | 
					      final localBuildNumber =
 | 
				
			||||||
 | 
					          int.tryParse(localVersionString.split('+').last) ?? 0;
 | 
				
			||||||
      log("[Update] Local: $localVersionString, Remote: $remoteVersionString");
 | 
					      log("[Update] Local: $localVersionString, Remote: $remoteVersionString");
 | 
				
			||||||
      if ((remoteVersion > localVersion || remoteBuildNumber > localBuildNumber) && mounted) {
 | 
					      if ((remoteVersion > localVersion ||
 | 
				
			||||||
 | 
					              remoteBuildNumber > localBuildNumber) &&
 | 
				
			||||||
 | 
					          mounted) {
 | 
				
			||||||
        final config = context.read<ConfigProvider>();
 | 
					        final config = context.read<ConfigProvider>();
 | 
				
			||||||
        config.setUpdate(remoteVersionString);
 | 
					        config.setUpdate(remoteVersionString);
 | 
				
			||||||
        log("[Update] Update available: $remoteVersionString");
 | 
					        log("[Update] Update available: $remoteVersionString");
 | 
				
			||||||
@@ -331,7 +333,9 @@ class _AppSplashScreenState extends State<_AppSplashScreen> with TrayListener {
 | 
				
			|||||||
  Future<void> _trayInitialization() async {
 | 
					  Future<void> _trayInitialization() async {
 | 
				
			||||||
    if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
 | 
					    if (kIsWeb || Platform.isAndroid || Platform.isIOS) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final icon = Platform.isWindows ? 'assets/icon/tray-icon.ico' : 'assets/icon/tray-icon.png';
 | 
					    final icon = Platform.isWindows
 | 
				
			||||||
 | 
					        ? 'assets/icon/tray-icon.ico'
 | 
				
			||||||
 | 
					        : 'assets/icon/tray-icon.png';
 | 
				
			||||||
    final appVersion = await PackageInfo.fromPlatform();
 | 
					    final appVersion = await PackageInfo.fromPlatform();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    trayManager.addListener(this);
 | 
					    trayManager.addListener(this);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,10 @@
 | 
				
			|||||||
 | 
					import 'dart:convert';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:drift/drift.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.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/database/database.dart';
 | 
				
			||||||
 | 
					import 'package:surface/providers/database.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/providers/user_directory.dart';
 | 
				
			||||||
import 'package:surface/types/chat.dart';
 | 
					import 'package:surface/types/chat.dart';
 | 
				
			||||||
@@ -12,24 +15,32 @@ class ChatChannelProvider extends ChangeNotifier {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  late final SnNetworkProvider _sn;
 | 
					  late final SnNetworkProvider _sn;
 | 
				
			||||||
  late final UserDirectoryProvider _ud;
 | 
					  late final UserDirectoryProvider _ud;
 | 
				
			||||||
 | 
					  late final DatabaseProvider _dt;
 | 
				
			||||||
  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>();
 | 
					    _ud = context.read<UserDirectoryProvider>();
 | 
				
			||||||
    _initializeLocalData();
 | 
					    _dt = context.read<DatabaseProvider>();
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  Future<void> _initializeLocalData() async {
 | 
					 | 
				
			||||||
    await Hive.openBox<SnChannel>(kChatChannelBoxName);
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<void> _saveChannelToLocal(Iterable<SnChannel> channels) async {
 | 
					  Future<void> _saveChannelToLocal(Iterable<SnChannel> channels) async {
 | 
				
			||||||
    if (_channelBox == null) return;
 | 
					    await Future.wait(
 | 
				
			||||||
    await _channelBox!.putAll({
 | 
					      channels.map(
 | 
				
			||||||
      for (final channel in channels) channel.key: channel,
 | 
					        (ele) => _dt.db.snLocalChatChannel.insertOne(
 | 
				
			||||||
    });
 | 
					          SnLocalChatChannelCompanion.insert(
 | 
				
			||||||
 | 
					            id: Value(ele.id),
 | 
				
			||||||
 | 
					            alias: ele.key,
 | 
				
			||||||
 | 
					            content: ele,
 | 
				
			||||||
 | 
					            createdAt: Value(ele.createdAt),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					          onConflict: DoUpdate(
 | 
				
			||||||
 | 
					            (_) => SnLocalChatChannelCompanion.custom(
 | 
				
			||||||
 | 
					              content: Constant(jsonEncode(ele.toJson())),
 | 
				
			||||||
 | 
					            ),
 | 
				
			||||||
 | 
					          ),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					      ),
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Future<List<SnChannel>> _fetchChannelsFromServer({
 | 
					  Future<List<SnChannel>> _fetchChannelsFromServer({
 | 
				
			||||||
@@ -54,12 +65,13 @@ class ChatChannelProvider extends ChangeNotifier {
 | 
				
			|||||||
  /// It will use the local storage as much as possible.
 | 
					  /// It will use the local storage as much as possible.
 | 
				
			||||||
  /// The alias should include the scope, formatted as `scope:alias`.
 | 
					  /// The alias should include the scope, formatted as `scope:alias`.
 | 
				
			||||||
  Future<SnChannel> getChannel(String key) async {
 | 
					  Future<SnChannel> getChannel(String key) async {
 | 
				
			||||||
    if (_channelBox != null) {
 | 
					    final local = await (_dt.db.snLocalChatChannel.select()
 | 
				
			||||||
      final local = _channelBox!.get(key);
 | 
					          ..where((e) => e.alias.equals(key)))
 | 
				
			||||||
      if (local != null) return local;
 | 
					        .getSingleOrNull();
 | 
				
			||||||
    }
 | 
					    if (local != null) return local.content;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var resp = await _sn.client.get('/cgi/im/channels/$key');
 | 
					    var resp =
 | 
				
			||||||
 | 
					        await _sn.client.get('/cgi/im/channels/${key.replaceAll(':', '/')}');
 | 
				
			||||||
    var out = SnChannel.fromJson(resp.data);
 | 
					    var out = SnChannel.fromJson(resp.data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Preload realm of the channel
 | 
					    // Preload realm of the channel
 | 
				
			||||||
@@ -77,8 +89,19 @@ class ChatChannelProvider extends ChangeNotifier {
 | 
				
			|||||||
  /// And the second time is when the data was fetched from the server.
 | 
					  /// And the second time is when the data was fetched from the server.
 | 
				
			||||||
  /// But there is some exception that will only cause one of them to be emitted.
 | 
					  /// But there is some exception that will only cause one of them to be emitted.
 | 
				
			||||||
  /// Like the local storage is broken or the server is down.
 | 
					  /// Like the local storage is broken or the server is down.
 | 
				
			||||||
  Stream<List<SnChannel>> fetchChannels() async* {
 | 
					  Stream<List<SnChannel>> fetchChannels(
 | 
				
			||||||
    if (_channelBox != null) yield _channelBox!.values.toList();
 | 
					      {bool noRemote = false, bool noLocal = false}) async* {
 | 
				
			||||||
 | 
					    if (!noLocal) {
 | 
				
			||||||
 | 
					      final local = await (_dt.db.snLocalChatChannel.select()
 | 
				
			||||||
 | 
					            ..orderBy([
 | 
				
			||||||
 | 
					              (e) =>
 | 
				
			||||||
 | 
					                  OrderingTerm(expression: e.createdAt, mode: OrderingMode.desc)
 | 
				
			||||||
 | 
					            ]))
 | 
				
			||||||
 | 
					          .get();
 | 
				
			||||||
 | 
					      yield local.map((e) => e.content).toList();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (noRemote) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var resp = await _sn.client.get('/cgi/id/realms/me/available');
 | 
					    var resp = await _sn.client.get('/cgi/id/realms/me/available');
 | 
				
			||||||
    final realms = List<SnRealm>.from(
 | 
					    final realms = List<SnRealm>.from(
 | 
				
			||||||
@@ -120,23 +143,23 @@ class ChatChannelProvider extends ChangeNotifier {
 | 
				
			|||||||
  Future<List<SnChatMessage>> getLastMessages(
 | 
					  Future<List<SnChatMessage>> getLastMessages(
 | 
				
			||||||
    Iterable<SnChannel> channels,
 | 
					    Iterable<SnChannel> channels,
 | 
				
			||||||
  ) async {
 | 
					  ) async {
 | 
				
			||||||
    final result = List<SnChatMessage>.empty(growable: true);
 | 
					    final result = List<Future<SnLocalChatMessageData?>>.empty(growable: true);
 | 
				
			||||||
    for (final channel in channels) {
 | 
					    for (final channel in channels) {
 | 
				
			||||||
      final channelBox = await Hive.openBox<SnChatMessage>(
 | 
					      final out = (_dt.db.snLocalChatMessage.select()
 | 
				
			||||||
        '${ChatMessageController.kChatMessageBoxPrefix}${channel.id}',
 | 
					            ..where((e) => e.channelId.equals(channel.id))
 | 
				
			||||||
      );
 | 
					            ..orderBy([
 | 
				
			||||||
      final lastMessage =
 | 
					              (e) =>
 | 
				
			||||||
          channelBox.isNotEmpty ? channelBox.values.reduce((a, b) => a.createdAt.isAfter(b.createdAt) ? a : b) : null;
 | 
					                  OrderingTerm(expression: e.createdAt, mode: OrderingMode.desc)
 | 
				
			||||||
      if (lastMessage != null) result.add(lastMessage);
 | 
					            ])
 | 
				
			||||||
      channelBox.close();
 | 
					            ..limit(1))
 | 
				
			||||||
 | 
					          .getSingleOrNull();
 | 
				
			||||||
 | 
					      result.add(out);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    await _ud.listAccount(result.map((ele) => ele.sender.accountId).toSet());
 | 
					    final out = (await Future.wait(result))
 | 
				
			||||||
    return result;
 | 
					        .where((e) => e != null)
 | 
				
			||||||
  }
 | 
					        .map((e) => e!.content)
 | 
				
			||||||
 | 
					        .toList();
 | 
				
			||||||
  @override
 | 
					    await _ud.listAccount(out.map((ele) => ele.sender.accountId).toSet());
 | 
				
			||||||
  void dispose() {
 | 
					    return out;
 | 
				
			||||||
    _channelBox?.close();
 | 
					 | 
				
			||||||
    super.dispose();
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								lib/providers/database.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								lib/providers/database.dart
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					import 'dart:io';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:path/path.dart' show join;
 | 
				
			||||||
 | 
					import 'package:path_provider/path_provider.dart';
 | 
				
			||||||
 | 
					import 'package:surface/database/database.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DatabaseProvider {
 | 
				
			||||||
 | 
					  late AppDatabase db;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  DatabaseProvider(BuildContext context) {
 | 
				
			||||||
 | 
					    db = AppDatabase();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<int> getDatabaseSize() async {
 | 
				
			||||||
 | 
					    if (kIsWeb) return 0;
 | 
				
			||||||
 | 
					    final basepath = await getApplicationSupportDirectory();
 | 
				
			||||||
 | 
					    return await File(join(basepath.path, 'solar_network_data.sqlite'))
 | 
				
			||||||
 | 
					        .length();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Future<void> removeDatabase() async {
 | 
				
			||||||
 | 
					    if (kIsWeb) return;
 | 
				
			||||||
 | 
					    final basepath = await getApplicationSupportDirectory();
 | 
				
			||||||
 | 
					    final file = File(join(basepath.path, 'solar_network_data.sqlite'));
 | 
				
			||||||
 | 
					    db.close();
 | 
				
			||||||
 | 
					    await file.delete();
 | 
				
			||||||
 | 
					    db = AppDatabase();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -4,10 +4,10 @@ import 'package:easy_localization/easy_localization.dart';
 | 
				
			|||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
import 'package:gap/gap.dart';
 | 
					import 'package:gap/gap.dart';
 | 
				
			||||||
import 'package:go_router/go_router.dart';
 | 
					import 'package:go_router/go_router.dart';
 | 
				
			||||||
import 'package:hive_flutter/hive_flutter.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:styled_widget/styled_widget.dart';
 | 
					import 'package:styled_widget/styled_widget.dart';
 | 
				
			||||||
 | 
					import 'package:surface/providers/database.dart';
 | 
				
			||||||
import 'package:surface/providers/sn_network.dart';
 | 
					import 'package:surface/providers/sn_network.dart';
 | 
				
			||||||
import 'package:surface/providers/userinfo.dart';
 | 
					import 'package:surface/providers/userinfo.dart';
 | 
				
			||||||
import 'package:surface/providers/websocket.dart';
 | 
					import 'package:surface/providers/websocket.dart';
 | 
				
			||||||
@@ -45,7 +45,8 @@ class AccountScreen extends StatelessWidget {
 | 
				
			|||||||
            ? Stack(
 | 
					            ? Stack(
 | 
				
			||||||
                fit: StackFit.expand,
 | 
					                fit: StackFit.expand,
 | 
				
			||||||
                children: [
 | 
					                children: [
 | 
				
			||||||
                  AutoResizeUniversalImage(sn.getAttachmentUrl(ua.user!.banner), fit: BoxFit.cover),
 | 
					                  AutoResizeUniversalImage(sn.getAttachmentUrl(ua.user!.banner),
 | 
				
			||||||
 | 
					                      fit: BoxFit.cover),
 | 
				
			||||||
                  Positioned(
 | 
					                  Positioned(
 | 
				
			||||||
                    top: 0,
 | 
					                    top: 0,
 | 
				
			||||||
                    left: 0,
 | 
					                    left: 0,
 | 
				
			||||||
@@ -79,7 +80,9 @@ class AccountScreen extends StatelessWidget {
 | 
				
			|||||||
        ],
 | 
					        ],
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
      body: SingleChildScrollView(
 | 
					      body: SingleChildScrollView(
 | 
				
			||||||
        child: ua.isAuthorized ? _AuthorizedAccountScreen() : _UnauthorizedAccountScreen(),
 | 
					        child: ua.isAuthorized
 | 
				
			||||||
 | 
					            ? _AuthorizedAccountScreen()
 | 
				
			||||||
 | 
					            : _UnauthorizedAccountScreen(),
 | 
				
			||||||
      ),
 | 
					      ),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -115,12 +118,15 @@ class _AuthorizedAccountScreen extends StatelessWidget {
 | 
				
			|||||||
                    crossAxisAlignment: CrossAxisAlignment.baseline,
 | 
					                    crossAxisAlignment: CrossAxisAlignment.baseline,
 | 
				
			||||||
                    textBaseline: TextBaseline.alphabetic,
 | 
					                    textBaseline: TextBaseline.alphabetic,
 | 
				
			||||||
                    children: [
 | 
					                    children: [
 | 
				
			||||||
                      Text(ua.user!.nick).textStyle(Theme.of(context).textTheme.titleLarge!),
 | 
					                      Text(ua.user!.nick)
 | 
				
			||||||
 | 
					                          .textStyle(Theme.of(context).textTheme.titleLarge!),
 | 
				
			||||||
                      const Gap(4),
 | 
					                      const Gap(4),
 | 
				
			||||||
                      Text('@${ua.user!.name}').textStyle(Theme.of(context).textTheme.bodySmall!),
 | 
					                      Text('@${ua.user!.name}')
 | 
				
			||||||
 | 
					                          .textStyle(Theme.of(context).textTheme.bodySmall!),
 | 
				
			||||||
                    ],
 | 
					                    ],
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                  Text(ua.user!.description).textStyle(Theme.of(context).textTheme.bodyMedium!),
 | 
					                  Text(ua.user!.description)
 | 
				
			||||||
 | 
					                      .textStyle(Theme.of(context).textTheme.bodyMedium!),
 | 
				
			||||||
                ],
 | 
					                ],
 | 
				
			||||||
              ),
 | 
					              ),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
@@ -193,8 +199,7 @@ class _AuthorizedAccountScreen extends StatelessWidget {
 | 
				
			|||||||
            ua.logoutUser();
 | 
					            ua.logoutUser();
 | 
				
			||||||
            final ws = context.read<WebSocketProvider>();
 | 
					            final ws = context.read<WebSocketProvider>();
 | 
				
			||||||
            ws.disconnect();
 | 
					            ws.disconnect();
 | 
				
			||||||
            await Hive.deleteFromDisk();
 | 
					            context.read<DatabaseProvider>().removeDatabase();
 | 
				
			||||||
            await Hive.initFlutter();
 | 
					 | 
				
			||||||
          },
 | 
					          },
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
@@ -220,7 +225,9 @@ class _UnauthorizedAccountScreen extends StatelessWidget {
 | 
				
			|||||||
                  child: Icon(Symbols.waving_hand, size: 28),
 | 
					                  child: Icon(Symbols.waving_hand, size: 28),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
                const Gap(8),
 | 
					                const Gap(8),
 | 
				
			||||||
                Text('accountIntroTitle').tr().textStyle(Theme.of(context).textTheme.titleLarge!),
 | 
					                Text('accountIntroTitle')
 | 
				
			||||||
 | 
					                    .tr()
 | 
				
			||||||
 | 
					                    .textStyle(Theme.of(context).textTheme.titleLarge!),
 | 
				
			||||||
                Text('accountIntroSubtitle').tr(),
 | 
					                Text('accountIntroSubtitle').tr(),
 | 
				
			||||||
              ],
 | 
					              ],
 | 
				
			||||||
            ).padding(all: 20),
 | 
					            ).padding(all: 20),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,9 @@ 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/sn_network.dart';
 | 
				
			||||||
import 'package:surface/providers/user_directory.dart';
 | 
					import 'package:surface/providers/user_directory.dart';
 | 
				
			||||||
 | 
					import 'package:surface/providers/userinfo.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/account/account_select.dart';
 | 
					import 'package:surface/widgets/account/account_select.dart';
 | 
				
			||||||
@@ -17,9 +19,6 @@ import 'package:surface/widgets/navigation/app_scaffold.dart';
 | 
				
			|||||||
import 'package:surface/widgets/unauthorized_hint.dart';
 | 
					import 'package:surface/widgets/unauthorized_hint.dart';
 | 
				
			||||||
import 'package:uuid/uuid.dart';
 | 
					import 'package:uuid/uuid.dart';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import '../providers/sn_network.dart';
 | 
					 | 
				
			||||||
import '../providers/userinfo.dart';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class ChatScreen extends StatefulWidget {
 | 
					class ChatScreen extends StatefulWidget {
 | 
				
			||||||
  const ChatScreen({super.key});
 | 
					  const ChatScreen({super.key});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +34,7 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
  List<SnChannel>? _channels;
 | 
					  List<SnChannel>? _channels;
 | 
				
			||||||
  Map<int, SnChatMessage>? _lastMessages;
 | 
					  Map<int, SnChatMessage>? _lastMessages;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void _refreshChannels() {
 | 
					  void _refreshChannels({bool noRemote = false}) {
 | 
				
			||||||
    final ua = context.read<UserProvider>();
 | 
					    final ua = context.read<UserProvider>();
 | 
				
			||||||
    if (!ua.isAuthorized) {
 | 
					    if (!ua.isAuthorized) {
 | 
				
			||||||
      setState(() => _isBusy = false);
 | 
					      setState(() => _isBusy = false);
 | 
				
			||||||
@@ -43,12 +42,15 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final chan = context.read<ChatChannelProvider>();
 | 
					    final chan = context.read<ChatChannelProvider>();
 | 
				
			||||||
    chan.fetchChannels().listen((channels) async {
 | 
					    chan.fetchChannels(noRemote: noRemote).listen((channels) async {
 | 
				
			||||||
      final lastMessages = await chan.getLastMessages(channels);
 | 
					      final lastMessages = await chan.getLastMessages(channels);
 | 
				
			||||||
      _lastMessages = {for (final val in lastMessages) val.channelId: val};
 | 
					      _lastMessages = {for (final val in lastMessages) val.channelId: val};
 | 
				
			||||||
      channels.sort((a, b) {
 | 
					      channels.sort((a, b) {
 | 
				
			||||||
        if (_lastMessages!.containsKey(a.id) && _lastMessages!.containsKey(b.id)) {
 | 
					        if (_lastMessages!.containsKey(a.id) &&
 | 
				
			||||||
          return _lastMessages![b.id]!.createdAt.compareTo(_lastMessages![a.id]!.createdAt);
 | 
					            _lastMessages!.containsKey(b.id)) {
 | 
				
			||||||
 | 
					          return _lastMessages![b.id]!
 | 
				
			||||||
 | 
					              .createdAt
 | 
				
			||||||
 | 
					              .compareTo(_lastMessages![a.id]!.createdAt);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (_lastMessages!.containsKey(a.id)) return -1;
 | 
					        if (_lastMessages!.containsKey(a.id)) return -1;
 | 
				
			||||||
        if (_lastMessages!.containsKey(b.id)) return 1;
 | 
					        if (_lastMessages!.containsKey(b.id)) return 1;
 | 
				
			||||||
@@ -86,7 +88,8 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
  void _newDirectMessage() async {
 | 
					  void _newDirectMessage() async {
 | 
				
			||||||
    final user = await showModalBottomSheet(
 | 
					    final user = await showModalBottomSheet(
 | 
				
			||||||
      context: context,
 | 
					      context: context,
 | 
				
			||||||
      builder: (context) => AccountSelect(title: 'channelNewDirectMessage'.tr()),
 | 
					      builder: (context) =>
 | 
				
			||||||
 | 
					          AccountSelect(title: 'channelNewDirectMessage'.tr()),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
    if (user == null) return;
 | 
					    if (user == null) return;
 | 
				
			||||||
    if (!mounted) return;
 | 
					    if (!mounted) return;
 | 
				
			||||||
@@ -98,7 +101,8 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
      await sn.client.post('/cgi/im/channels/global/dm', data: {
 | 
					      await sn.client.post('/cgi/im/channels/global/dm', data: {
 | 
				
			||||||
        'alias': uuid.v4().replaceAll('-', '').substring(0, 12),
 | 
					        'alias': uuid.v4().replaceAll('-', '').substring(0, 12),
 | 
				
			||||||
        'name': 'DM',
 | 
					        'name': 'DM',
 | 
				
			||||||
        'description': 'A direct message channel between @${ua.user?.name} and @${user.name}',
 | 
					        'description':
 | 
				
			||||||
 | 
					            'A direct message channel between @${ua.user?.name} and @${user.name}',
 | 
				
			||||||
        'related_user': user.id,
 | 
					        'related_user': user.id,
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
      _fabKey.currentState!.toggle();
 | 
					      _fabKey.currentState!.toggle();
 | 
				
			||||||
@@ -144,20 +148,27 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
        type: ExpandableFabType.up,
 | 
					        type: ExpandableFabType.up,
 | 
				
			||||||
        childrenAnimation: ExpandableFabAnimation.none,
 | 
					        childrenAnimation: ExpandableFabAnimation.none,
 | 
				
			||||||
        overlayStyle: ExpandableFabOverlayStyle(
 | 
					        overlayStyle: ExpandableFabOverlayStyle(
 | 
				
			||||||
          color: Theme.of(context).colorScheme.surface.withAlpha((255 * 0.5).round()),
 | 
					          color: Theme.of(context)
 | 
				
			||||||
 | 
					              .colorScheme
 | 
				
			||||||
 | 
					              .surface
 | 
				
			||||||
 | 
					              .withAlpha((255 * 0.5).round()),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        openButtonBuilder: RotateFloatingActionButtonBuilder(
 | 
					        openButtonBuilder: RotateFloatingActionButtonBuilder(
 | 
				
			||||||
          child: const Icon(Symbols.add, size: 28),
 | 
					          child: const Icon(Symbols.add, size: 28),
 | 
				
			||||||
          fabSize: ExpandableFabSize.regular,
 | 
					          fabSize: ExpandableFabSize.regular,
 | 
				
			||||||
          foregroundColor: Theme.of(context).floatingActionButtonTheme.foregroundColor,
 | 
					          foregroundColor:
 | 
				
			||||||
          backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
 | 
					              Theme.of(context).floatingActionButtonTheme.foregroundColor,
 | 
				
			||||||
 | 
					          backgroundColor:
 | 
				
			||||||
 | 
					              Theme.of(context).floatingActionButtonTheme.backgroundColor,
 | 
				
			||||||
          shape: const CircleBorder(),
 | 
					          shape: const CircleBorder(),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        closeButtonBuilder: DefaultFloatingActionButtonBuilder(
 | 
					        closeButtonBuilder: DefaultFloatingActionButtonBuilder(
 | 
				
			||||||
          child: const Icon(Symbols.close, size: 28),
 | 
					          child: const Icon(Symbols.close, size: 28),
 | 
				
			||||||
          fabSize: ExpandableFabSize.regular,
 | 
					          fabSize: ExpandableFabSize.regular,
 | 
				
			||||||
          foregroundColor: Theme.of(context).floatingActionButtonTheme.foregroundColor,
 | 
					          foregroundColor:
 | 
				
			||||||
          backgroundColor: Theme.of(context).floatingActionButtonTheme.backgroundColor,
 | 
					              Theme.of(context).floatingActionButtonTheme.foregroundColor,
 | 
				
			||||||
 | 
					          backgroundColor:
 | 
				
			||||||
 | 
					              Theme.of(context).floatingActionButtonTheme.backgroundColor,
 | 
				
			||||||
          shape: const CircleBorder(),
 | 
					          shape: const CircleBorder(),
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        children: [
 | 
					        children: [
 | 
				
			||||||
@@ -208,13 +219,17 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
                    final lastMessage = _lastMessages?[channel.id];
 | 
					                    final lastMessage = _lastMessages?[channel.id];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (channel.type == 1) {
 | 
					                    if (channel.type == 1) {
 | 
				
			||||||
                      final otherMember = channel.members?.cast<SnChannelMember?>().firstWhere(
 | 
					                      final otherMember =
 | 
				
			||||||
 | 
					                          channel.members?.cast<SnChannelMember?>().firstWhere(
 | 
				
			||||||
                                (ele) => ele?.accountId != ua.user?.id,
 | 
					                                (ele) => ele?.accountId != ua.user?.id,
 | 
				
			||||||
                                orElse: () => null,
 | 
					                                orElse: () => null,
 | 
				
			||||||
                              );
 | 
					                              );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                      return ListTile(
 | 
					                      return ListTile(
 | 
				
			||||||
                        title: Text(ud.getAccountFromCache(otherMember?.accountId)?.nick ?? channel.name),
 | 
					                        title: Text(ud
 | 
				
			||||||
 | 
					                                .getAccountFromCache(otherMember?.accountId)
 | 
				
			||||||
 | 
					                                ?.nick ??
 | 
				
			||||||
 | 
					                            channel.name),
 | 
				
			||||||
                        subtitle: lastMessage != null
 | 
					                        subtitle: lastMessage != null
 | 
				
			||||||
                            ? Text(
 | 
					                            ? Text(
 | 
				
			||||||
                                '${ud.getAccountFromCache(lastMessage.sender.accountId)?.nick}: ${lastMessage.body['text'] ?? 'Unable preview'}',
 | 
					                                '${ud.getAccountFromCache(lastMessage.sender.accountId)?.nick}: ${lastMessage.body['text'] ?? 'Unable preview'}',
 | 
				
			||||||
@@ -228,9 +243,12 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
                                maxLines: 1,
 | 
					                                maxLines: 1,
 | 
				
			||||||
                                overflow: TextOverflow.ellipsis,
 | 
					                                overflow: TextOverflow.ellipsis,
 | 
				
			||||||
                              ),
 | 
					                              ),
 | 
				
			||||||
                        contentPadding: const EdgeInsets.symmetric(horizontal: 16),
 | 
					                        contentPadding:
 | 
				
			||||||
 | 
					                            const EdgeInsets.symmetric(horizontal: 16),
 | 
				
			||||||
                        leading: AccountImage(
 | 
					                        leading: AccountImage(
 | 
				
			||||||
                          content: ud.getAccountFromCache(otherMember?.accountId)?.avatar,
 | 
					                          content: ud
 | 
				
			||||||
 | 
					                              .getAccountFromCache(otherMember?.accountId)
 | 
				
			||||||
 | 
					                              ?.avatar,
 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                        onTap: () {
 | 
					                        onTap: () {
 | 
				
			||||||
                          GoRouter.of(context).pushNamed(
 | 
					                          GoRouter.of(context).pushNamed(
 | 
				
			||||||
@@ -240,7 +258,7 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
                              'alias': channel.alias,
 | 
					                              'alias': channel.alias,
 | 
				
			||||||
                            },
 | 
					                            },
 | 
				
			||||||
                          ).then((value) {
 | 
					                          ).then((value) {
 | 
				
			||||||
                            if (mounted) _refreshChannels();
 | 
					                            if (mounted) _refreshChannels(noRemote: true);
 | 
				
			||||||
                          });
 | 
					                          });
 | 
				
			||||||
                        },
 | 
					                        },
 | 
				
			||||||
                      );
 | 
					                      );
 | 
				
			||||||
@@ -259,7 +277,8 @@ class _ChatScreenState extends State<ChatScreen> {
 | 
				
			|||||||
                              maxLines: 1,
 | 
					                              maxLines: 1,
 | 
				
			||||||
                              overflow: TextOverflow.ellipsis,
 | 
					                              overflow: TextOverflow.ellipsis,
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
                      contentPadding: const EdgeInsets.symmetric(horizontal: 16),
 | 
					                      contentPadding:
 | 
				
			||||||
 | 
					                          const EdgeInsets.symmetric(horizontal: 16),
 | 
				
			||||||
                      leading: AccountImage(
 | 
					                      leading: AccountImage(
 | 
				
			||||||
                        content: null,
 | 
					                        content: null,
 | 
				
			||||||
                        fallbackWidget: const Icon(Symbols.chat, size: 20),
 | 
					                        fallbackWidget: const Icon(Symbols.chat, size: 20),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -243,7 +243,12 @@ class _ExploreScreenState extends State<ExploreScreen> with SingleTickerProvider
 | 
				
			|||||||
                        children: [
 | 
					                        children: [
 | 
				
			||||||
                          Icon(Symbols.globe, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Icon(Symbols.globe, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
                          const Gap(8),
 | 
					                          const Gap(8),
 | 
				
			||||||
                          Text('postChannelGlobal').tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Flexible(
 | 
				
			||||||
 | 
					                            child: Text(
 | 
				
			||||||
 | 
					                              'postChannelGlobal',
 | 
				
			||||||
 | 
					                              maxLines: 1,
 | 
				
			||||||
 | 
					                            ).tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
 | 
					                          ),
 | 
				
			||||||
                        ],
 | 
					                        ],
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
@@ -254,7 +259,13 @@ class _ExploreScreenState extends State<ExploreScreen> with SingleTickerProvider
 | 
				
			|||||||
                        children: [
 | 
					                        children: [
 | 
				
			||||||
                          Icon(Symbols.group, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Icon(Symbols.group, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
                          const Gap(8),
 | 
					                          const Gap(8),
 | 
				
			||||||
                          Text('postChannelFriends').tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Flexible(
 | 
				
			||||||
 | 
					                            child: Text(
 | 
				
			||||||
 | 
					                              'postChannelFriends',
 | 
				
			||||||
 | 
					                              maxLines: 1,
 | 
				
			||||||
 | 
					                              textAlign: TextAlign.center,
 | 
				
			||||||
 | 
					                            ).tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
 | 
					                          ),
 | 
				
			||||||
                        ],
 | 
					                        ],
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
@@ -265,7 +276,12 @@ class _ExploreScreenState extends State<ExploreScreen> with SingleTickerProvider
 | 
				
			|||||||
                        children: [
 | 
					                        children: [
 | 
				
			||||||
                          Icon(Symbols.subscriptions, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Icon(Symbols.subscriptions, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
                          const Gap(8),
 | 
					                          const Gap(8),
 | 
				
			||||||
                          Text('postChannelFollowing').tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Flexible(
 | 
				
			||||||
 | 
					                            child: Text(
 | 
				
			||||||
 | 
					                              'postChannelFollowing',
 | 
				
			||||||
 | 
					                              maxLines: 1,
 | 
				
			||||||
 | 
					                            ).tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
 | 
					                          ),
 | 
				
			||||||
                        ],
 | 
					                        ],
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
@@ -276,7 +292,12 @@ class _ExploreScreenState extends State<ExploreScreen> with SingleTickerProvider
 | 
				
			|||||||
                        children: [
 | 
					                        children: [
 | 
				
			||||||
                          Icon(Symbols.workspaces, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Icon(Symbols.workspaces, size: 20, color: Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
                          const Gap(8),
 | 
					                          const Gap(8),
 | 
				
			||||||
                          Text('postChannelRealm').tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
					                          Flexible(
 | 
				
			||||||
 | 
					                            child: Text(
 | 
				
			||||||
 | 
					                              'postChannelRealm',
 | 
				
			||||||
 | 
					                              maxLines: 1,
 | 
				
			||||||
 | 
					                            ).tr().textColor(Theme.of(context).appBarTheme.foregroundColor),
 | 
				
			||||||
 | 
					                          ),
 | 
				
			||||||
                        ],
 | 
					                        ],
 | 
				
			||||||
                      ),
 | 
					                      ),
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,8 +5,10 @@ import 'package:dropdown_button2/dropdown_button2.dart';
 | 
				
			|||||||
import 'package:easy_localization/easy_localization.dart';
 | 
					import 'package:easy_localization/easy_localization.dart';
 | 
				
			||||||
import 'package:flutter/foundation.dart';
 | 
					import 'package:flutter/foundation.dart';
 | 
				
			||||||
import 'package:flutter/material.dart';
 | 
					import 'package:flutter/material.dart';
 | 
				
			||||||
 | 
					import 'package:flutter/services.dart';
 | 
				
			||||||
import 'package:flutter_colorpicker/flutter_colorpicker.dart';
 | 
					import 'package:flutter_colorpicker/flutter_colorpicker.dart';
 | 
				
			||||||
import 'package:go_router/go_router.dart';
 | 
					import 'package:go_router/go_router.dart';
 | 
				
			||||||
 | 
					import 'package:google_fonts/google_fonts.dart';
 | 
				
			||||||
import 'package:image_picker/image_picker.dart';
 | 
					import 'package:image_picker/image_picker.dart';
 | 
				
			||||||
import 'package:material_symbols_icons/symbols.dart';
 | 
					import 'package:material_symbols_icons/symbols.dart';
 | 
				
			||||||
import 'package:path_provider/path_provider.dart';
 | 
					import 'package:path_provider/path_provider.dart';
 | 
				
			||||||
@@ -14,6 +16,7 @@ import 'package:provider/provider.dart';
 | 
				
			|||||||
import 'package:shared_preferences/shared_preferences.dart';
 | 
					import 'package:shared_preferences/shared_preferences.dart';
 | 
				
			||||||
import 'package:styled_widget/styled_widget.dart';
 | 
					import 'package:styled_widget/styled_widget.dart';
 | 
				
			||||||
import 'package:surface/providers/config.dart';
 | 
					import 'package:surface/providers/config.dart';
 | 
				
			||||||
 | 
					import 'package:surface/providers/database.dart';
 | 
				
			||||||
import 'package:surface/providers/sn_network.dart';
 | 
					import 'package:surface/providers/sn_network.dart';
 | 
				
			||||||
import 'package:surface/providers/theme.dart';
 | 
					import 'package:surface/providers/theme.dart';
 | 
				
			||||||
import 'package:surface/theme.dart';
 | 
					import 'package:surface/theme.dart';
 | 
				
			||||||
@@ -67,6 +70,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  Widget build(BuildContext context) {
 | 
					  Widget build(BuildContext context) {
 | 
				
			||||||
    final sn = context.read<SnNetworkProvider>();
 | 
					    final sn = context.read<SnNetworkProvider>();
 | 
				
			||||||
 | 
					    final dt = context.read<DatabaseProvider>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return AppScaffold(
 | 
					    return AppScaffold(
 | 
				
			||||||
      appBar: AppBar(
 | 
					      appBar: AppBar(
 | 
				
			||||||
@@ -81,7 +85,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
					              crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                Text('settingsAppearance').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
 | 
					                Text('settingsAppearance')
 | 
				
			||||||
 | 
					                    .bold()
 | 
				
			||||||
 | 
					                    .fontSize(17)
 | 
				
			||||||
 | 
					                    .tr()
 | 
				
			||||||
 | 
					                    .padding(horizontal: 20, bottom: 4),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text('settingsDisplayLanguage').tr(),
 | 
					                  title: Text('settingsDisplayLanguage').tr(),
 | 
				
			||||||
                  subtitle: Text('settingsDisplayLanguageDescription').tr(),
 | 
					                  subtitle: Text('settingsDisplayLanguageDescription').tr(),
 | 
				
			||||||
@@ -91,15 +99,21 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                    child: DropdownButton2<Locale?>(
 | 
					                    child: DropdownButton2<Locale?>(
 | 
				
			||||||
                      isExpanded: true,
 | 
					                      isExpanded: true,
 | 
				
			||||||
                      items: [
 | 
					                      items: [
 | 
				
			||||||
                        ...EasyLocalization.of(context)!.supportedLocales.mapIndexed((idx, ele) {
 | 
					                        ...EasyLocalization.of(context)!
 | 
				
			||||||
 | 
					                            .supportedLocales
 | 
				
			||||||
 | 
					                            .mapIndexed((idx, ele) {
 | 
				
			||||||
                          return DropdownMenuItem<Locale?>(
 | 
					                          return DropdownMenuItem<Locale?>(
 | 
				
			||||||
                            value: ele,
 | 
					                            value: ele,
 | 
				
			||||||
                            child: Text('${ele.languageCode}-${ele.countryCode}').fontSize(14),
 | 
					                            child:
 | 
				
			||||||
 | 
					                                Text('${ele.languageCode}-${ele.countryCode}')
 | 
				
			||||||
 | 
					                                    .fontSize(14),
 | 
				
			||||||
                          );
 | 
					                          );
 | 
				
			||||||
                        }),
 | 
					                        }),
 | 
				
			||||||
                        DropdownMenuItem<Locale?>(
 | 
					                        DropdownMenuItem<Locale?>(
 | 
				
			||||||
                          value: null,
 | 
					                          value: null,
 | 
				
			||||||
                          child: Text('settingsDisplayLanguageSystem').tr().fontSize(14),
 | 
					                          child: Text('settingsDisplayLanguageSystem')
 | 
				
			||||||
 | 
					                              .tr()
 | 
				
			||||||
 | 
					                              .fontSize(14),
 | 
				
			||||||
                        ),
 | 
					                        ),
 | 
				
			||||||
                      ],
 | 
					                      ],
 | 
				
			||||||
                      value: EasyLocalization.of(context)!.currentLocale,
 | 
					                      value: EasyLocalization.of(context)!.currentLocale,
 | 
				
			||||||
@@ -132,10 +146,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                    leading: const Icon(Symbols.image),
 | 
					                    leading: const Icon(Symbols.image),
 | 
				
			||||||
                    trailing: const Icon(Symbols.chevron_right),
 | 
					                    trailing: const Icon(Symbols.chevron_right),
 | 
				
			||||||
                    onTap: () async {
 | 
					                    onTap: () async {
 | 
				
			||||||
                      final image = await ImagePicker().pickImage(source: ImageSource.gallery);
 | 
					                      final image = await ImagePicker()
 | 
				
			||||||
 | 
					                          .pickImage(source: ImageSource.gallery);
 | 
				
			||||||
                      if (image == null) return;
 | 
					                      if (image == null) return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                      await File(image.path).copy('$_docBasepath/app_background_image');
 | 
					                      await File(image.path)
 | 
				
			||||||
 | 
					                          .copy('$_docBasepath/app_background_image');
 | 
				
			||||||
                      _prefs.setBool(kAppBackgroundStoreKey, true);
 | 
					                      _prefs.setBool(kAppBackgroundStoreKey, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                      setState(() {});
 | 
					                      setState(() {});
 | 
				
			||||||
@@ -143,7 +159,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                if (!kIsWeb)
 | 
					                if (!kIsWeb)
 | 
				
			||||||
                  FutureBuilder<bool>(
 | 
					                  FutureBuilder<bool>(
 | 
				
			||||||
                      future: File('$_docBasepath/app_background_image').exists(),
 | 
					                      future:
 | 
				
			||||||
 | 
					                          File('$_docBasepath/app_background_image').exists(),
 | 
				
			||||||
                      builder: (context, snapshot) {
 | 
					                      builder: (context, snapshot) {
 | 
				
			||||||
                        if (!snapshot.hasData || !snapshot.data!) {
 | 
					                        if (!snapshot.hasData || !snapshot.data!) {
 | 
				
			||||||
                          return const SizedBox.shrink();
 | 
					                          return const SizedBox.shrink();
 | 
				
			||||||
@@ -151,12 +168,16 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                        return ListTile(
 | 
					                        return ListTile(
 | 
				
			||||||
                          title: Text('settingsBackgroundImageClear').tr(),
 | 
					                          title: Text('settingsBackgroundImageClear').tr(),
 | 
				
			||||||
                          subtitle: Text('settingsBackgroundImageClearDescription').tr(),
 | 
					                          subtitle:
 | 
				
			||||||
                          contentPadding: const EdgeInsets.symmetric(horizontal: 24),
 | 
					                              Text('settingsBackgroundImageClearDescription')
 | 
				
			||||||
 | 
					                                  .tr(),
 | 
				
			||||||
 | 
					                          contentPadding:
 | 
				
			||||||
 | 
					                              const EdgeInsets.symmetric(horizontal: 24),
 | 
				
			||||||
                          leading: const Icon(Symbols.texture),
 | 
					                          leading: const Icon(Symbols.texture),
 | 
				
			||||||
                          trailing: const Icon(Symbols.chevron_right),
 | 
					                          trailing: const Icon(Symbols.chevron_right),
 | 
				
			||||||
                          onTap: () {
 | 
					                          onTap: () {
 | 
				
			||||||
                            File('$_docBasepath/app_background_image').deleteSync();
 | 
					                            File('$_docBasepath/app_background_image')
 | 
				
			||||||
 | 
					                                .deleteSync();
 | 
				
			||||||
                            _prefs.remove(kAppBackgroundStoreKey);
 | 
					                            _prefs.remove(kAppBackgroundStoreKey);
 | 
				
			||||||
                            setState(() {});
 | 
					                            setState(() {});
 | 
				
			||||||
                          },
 | 
					                          },
 | 
				
			||||||
@@ -186,11 +207,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                  contentPadding: const EdgeInsets.symmetric(horizontal: 24),
 | 
					                  contentPadding: const EdgeInsets.symmetric(horizontal: 24),
 | 
				
			||||||
                  trailing: const Icon(Symbols.chevron_right),
 | 
					                  trailing: const Icon(Symbols.chevron_right),
 | 
				
			||||||
                  onTap: () async {
 | 
					                  onTap: () async {
 | 
				
			||||||
                    Color pickerColor = Color(_prefs.getInt(kAppColorSchemeStoreKey) ?? Colors.indigo.value);
 | 
					                    Color pickerColor = Color(
 | 
				
			||||||
 | 
					                        _prefs.getInt(kAppColorSchemeStoreKey) ??
 | 
				
			||||||
 | 
					                            Colors.indigo.value);
 | 
				
			||||||
                    final color = await showDialog<Color?>(
 | 
					                    final color = await showDialog<Color?>(
 | 
				
			||||||
                      context: context,
 | 
					                      context: context,
 | 
				
			||||||
                      builder: (context) =>
 | 
					                      builder: (context) => AlertDialog(
 | 
				
			||||||
                          AlertDialog(
 | 
					 | 
				
			||||||
                        content: SingleChildScrollView(
 | 
					                        content: SingleChildScrollView(
 | 
				
			||||||
                          child: ColorPicker(
 | 
					                          child: ColorPicker(
 | 
				
			||||||
                            pickerColor: pickerColor,
 | 
					                            pickerColor: pickerColor,
 | 
				
			||||||
@@ -248,16 +270,17 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                      ],
 | 
					                      ],
 | 
				
			||||||
                      value: _prefs.getInt(kAppColorSchemeStoreKey) == null
 | 
					                      value: _prefs.getInt(kAppColorSchemeStoreKey) == null
 | 
				
			||||||
                          ? 1
 | 
					                          ? 1
 | 
				
			||||||
                          : kColorSchemes.values
 | 
					                          : kColorSchemes.values.toList().indexWhere((ele) =>
 | 
				
			||||||
                          .toList()
 | 
					                              ele.value ==
 | 
				
			||||||
                          .indexWhere((ele) => ele.value == _prefs.getInt(kAppColorSchemeStoreKey)),
 | 
					                              _prefs.getInt(kAppColorSchemeStoreKey)),
 | 
				
			||||||
                      onChanged: (int? value) {
 | 
					                      onChanged: (int? value) {
 | 
				
			||||||
                        if (value != null && value != -1) {
 | 
					                        if (value != null && value != -1) {
 | 
				
			||||||
                          _prefs.setInt(kAppColorSchemeStoreKey, kColorSchemes.values
 | 
					                          _prefs.setInt(kAppColorSchemeStoreKey,
 | 
				
			||||||
                              .elementAt(value)
 | 
					                              kColorSchemes.values.elementAt(value).value);
 | 
				
			||||||
                              .value);
 | 
					 | 
				
			||||||
                          final th = context.read<ThemeProvider>();
 | 
					                          final th = context.read<ThemeProvider>();
 | 
				
			||||||
                          th.reloadTheme(seedColorOverride: kColorSchemes.values.elementAt(value));
 | 
					                          th.reloadTheme(
 | 
				
			||||||
 | 
					                              seedColorOverride:
 | 
				
			||||||
 | 
					                                  kColorSchemes.values.elementAt(value));
 | 
				
			||||||
                          setState(() {});
 | 
					                          setState(() {});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                          context.showSnackbar('colorSchemeApplied'.tr());
 | 
					                          context.showSnackbar('colorSchemeApplied'.tr());
 | 
				
			||||||
@@ -293,7 +316,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                CheckboxListTile(
 | 
					                CheckboxListTile(
 | 
				
			||||||
                  secondary: const Icon(Symbols.left_panel_close),
 | 
					                  secondary: const Icon(Symbols.left_panel_close),
 | 
				
			||||||
                  title: Text('settingsDrawerPreferCollapse').tr(),
 | 
					                  title: Text('settingsDrawerPreferCollapse').tr(),
 | 
				
			||||||
                  subtitle: Text('settingsDrawerPreferCollapseDescription').tr(),
 | 
					                  subtitle:
 | 
				
			||||||
 | 
					                      Text('settingsDrawerPreferCollapseDescription').tr(),
 | 
				
			||||||
                  contentPadding: const EdgeInsets.only(left: 24, right: 17),
 | 
					                  contentPadding: const EdgeInsets.only(left: 24, right: 17),
 | 
				
			||||||
                  value: _prefs.getBool(kAppDrawerPreferCollapse) ?? false,
 | 
					                  value: _prefs.getBool(kAppDrawerPreferCollapse) ?? false,
 | 
				
			||||||
                  onChanged: (value) {
 | 
					                  onChanged: (value) {
 | 
				
			||||||
@@ -308,7 +332,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
					              crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                Text('settingsFeatures').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
 | 
					                Text('settingsFeatures')
 | 
				
			||||||
 | 
					                    .bold()
 | 
				
			||||||
 | 
					                    .fontSize(17)
 | 
				
			||||||
 | 
					                    .tr()
 | 
				
			||||||
 | 
					                    .padding(horizontal: 20, bottom: 4),
 | 
				
			||||||
                CheckboxListTile(
 | 
					                CheckboxListTile(
 | 
				
			||||||
                  secondary: const Icon(Symbols.vibration),
 | 
					                  secondary: const Icon(Symbols.vibration),
 | 
				
			||||||
                  contentPadding: const EdgeInsets.only(left: 24, right: 17),
 | 
					                  contentPadding: const EdgeInsets.only(left: 24, right: 17),
 | 
				
			||||||
@@ -350,7 +378,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
					              crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                Text('settingsNetwork').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
 | 
					                Text('settingsNetwork')
 | 
				
			||||||
 | 
					                    .bold()
 | 
				
			||||||
 | 
					                    .fontSize(17)
 | 
				
			||||||
 | 
					                    .tr()
 | 
				
			||||||
 | 
					                    .padding(horizontal: 20, bottom: 4),
 | 
				
			||||||
                TextField(
 | 
					                TextField(
 | 
				
			||||||
                  controller: _serverUrlController,
 | 
					                  controller: _serverUrlController,
 | 
				
			||||||
                  decoration: InputDecoration(
 | 
					                  decoration: InputDecoration(
 | 
				
			||||||
@@ -371,7 +403,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                      },
 | 
					                      },
 | 
				
			||||||
                    ),
 | 
					                    ),
 | 
				
			||||||
                  ),
 | 
					                  ),
 | 
				
			||||||
                  onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
 | 
					                  onTapOutside: (_) =>
 | 
				
			||||||
 | 
					                      FocusManager.instance.primaryFocus?.unfocus(),
 | 
				
			||||||
                ).padding(horizontal: 16, top: 8, bottom: 4),
 | 
					                ).padding(horizontal: 16, top: 8, bottom: 4),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text('settingsNetworkServerPreset').tr(),
 | 
					                  title: Text('settingsNetworkServerPreset').tr(),
 | 
				
			||||||
@@ -383,12 +416,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                      isExpanded: true,
 | 
					                      isExpanded: true,
 | 
				
			||||||
                      items: [
 | 
					                      items: [
 | 
				
			||||||
                        ...kNetworkServerDirectory,
 | 
					                        ...kNetworkServerDirectory,
 | 
				
			||||||
                        if (!kNetworkServerDirectory.map((ele) => ele.$2).contains(_serverUrlController.text))
 | 
					                        if (!kNetworkServerDirectory
 | 
				
			||||||
 | 
					                            .map((ele) => ele.$2)
 | 
				
			||||||
 | 
					                            .contains(_serverUrlController.text))
 | 
				
			||||||
                          ('Custom', _serverUrlController.text),
 | 
					                          ('Custom', _serverUrlController.text),
 | 
				
			||||||
                      ]
 | 
					                      ]
 | 
				
			||||||
                          .map(
 | 
					                          .map(
 | 
				
			||||||
                            (item) =>
 | 
					                            (item) => DropdownMenuItem<String>(
 | 
				
			||||||
                            DropdownMenuItem<String>(
 | 
					 | 
				
			||||||
                              value: item.$2,
 | 
					                              value: item.$2,
 | 
				
			||||||
                              child: Column(
 | 
					                              child: Column(
 | 
				
			||||||
                                mainAxisSize: MainAxisSize.max,
 | 
					                                mainAxisSize: MainAxisSize.max,
 | 
				
			||||||
@@ -396,7 +430,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                                crossAxisAlignment: CrossAxisAlignment.start,
 | 
					                                crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
                                children: [
 | 
					                                children: [
 | 
				
			||||||
                                  Text(item.$1).fontSize(14),
 | 
					                                  Text(item.$1).fontSize(14),
 | 
				
			||||||
                                  Text(item.$2, overflow: TextOverflow.ellipsis).fontSize(11)
 | 
					                                  Text(item.$2, overflow: TextOverflow.ellipsis)
 | 
				
			||||||
 | 
					                                      .fontSize(11)
 | 
				
			||||||
                                ],
 | 
					                                ],
 | 
				
			||||||
                              ),
 | 
					                              ),
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
@@ -442,7 +477,11 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
					              crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                Text('settingsPerformance').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
 | 
					                Text('settingsPerformance')
 | 
				
			||||||
 | 
					                    .bold()
 | 
				
			||||||
 | 
					                    .fontSize(17)
 | 
				
			||||||
 | 
					                    .tr()
 | 
				
			||||||
 | 
					                    .padding(horizontal: 20, bottom: 4),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text('settingsImageQuality').tr(),
 | 
					                  title: Text('settingsImageQuality').tr(),
 | 
				
			||||||
                  subtitle: Text('settingsImageQualityDescription').tr(),
 | 
					                  subtitle: Text('settingsImageQualityDescription').tr(),
 | 
				
			||||||
@@ -450,13 +489,13 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                  leading: const Icon(Symbols.image),
 | 
					                  leading: const Icon(Symbols.image),
 | 
				
			||||||
                  trailing: DropdownButtonHideUnderline(
 | 
					                  trailing: DropdownButtonHideUnderline(
 | 
				
			||||||
                    child: DropdownButton2<FilterQuality>(
 | 
					                    child: DropdownButton2<FilterQuality>(
 | 
				
			||||||
                      value: kImageQualityLevel.values.elementAtOrNull(_prefs.getInt('app_image_quality') ?? 3) ??
 | 
					                      value: kImageQualityLevel.values.elementAtOrNull(
 | 
				
			||||||
 | 
					                              _prefs.getInt('app_image_quality') ?? 3) ??
 | 
				
			||||||
                          FilterQuality.high,
 | 
					                          FilterQuality.high,
 | 
				
			||||||
                      isExpanded: true,
 | 
					                      isExpanded: true,
 | 
				
			||||||
                      items: kImageQualityLevel.entries
 | 
					                      items: kImageQualityLevel.entries
 | 
				
			||||||
                          .map(
 | 
					                          .map(
 | 
				
			||||||
                            (item) =>
 | 
					                            (item) => DropdownMenuItem<FilterQuality>(
 | 
				
			||||||
                            DropdownMenuItem<FilterQuality>(
 | 
					 | 
				
			||||||
                              value: item.value,
 | 
					                              value: item.value,
 | 
				
			||||||
                              child: Text(item.key).tr().fontSize(14),
 | 
					                              child: Text(item.key).tr().fontSize(14),
 | 
				
			||||||
                            ),
 | 
					                            ),
 | 
				
			||||||
@@ -464,7 +503,8 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
                          .toList(),
 | 
					                          .toList(),
 | 
				
			||||||
                      onChanged: (FilterQuality? value) {
 | 
					                      onChanged: (FilterQuality? value) {
 | 
				
			||||||
                        if (value == null) return;
 | 
					                        if (value == null) return;
 | 
				
			||||||
                        _prefs.setInt('app_image_quality', kImageQualityLevel.values.toList().indexOf(value));
 | 
					                        _prefs.setInt('app_image_quality',
 | 
				
			||||||
 | 
					                            kImageQualityLevel.values.toList().indexOf(value));
 | 
				
			||||||
                        setState(() {});
 | 
					                        setState(() {});
 | 
				
			||||||
                      },
 | 
					                      },
 | 
				
			||||||
                      buttonStyleData: const ButtonStyleData(
 | 
					                      buttonStyleData: const ButtonStyleData(
 | 
				
			||||||
@@ -486,7 +526,42 @@ class _SettingsScreenState extends State<SettingsScreen> {
 | 
				
			|||||||
            Column(
 | 
					            Column(
 | 
				
			||||||
              crossAxisAlignment: CrossAxisAlignment.start,
 | 
					              crossAxisAlignment: CrossAxisAlignment.start,
 | 
				
			||||||
              children: [
 | 
					              children: [
 | 
				
			||||||
                Text('settingsMisc').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
 | 
					                Text('settingsMisc')
 | 
				
			||||||
 | 
					                    .bold()
 | 
				
			||||||
 | 
					                    .fontSize(17)
 | 
				
			||||||
 | 
					                    .tr()
 | 
				
			||||||
 | 
					                    .padding(horizontal: 20, bottom: 4),
 | 
				
			||||||
 | 
					                ListTile(
 | 
				
			||||||
 | 
					                  leading: const Icon(Symbols.database),
 | 
				
			||||||
 | 
					                  contentPadding: const EdgeInsets.symmetric(horizontal: 24),
 | 
				
			||||||
 | 
					                  title: Text('databaseSize').tr(),
 | 
				
			||||||
 | 
					                  subtitle: FutureBuilder(
 | 
				
			||||||
 | 
					                    future: dt.getDatabaseSize(),
 | 
				
			||||||
 | 
					                    builder: (context, snapshot) {
 | 
				
			||||||
 | 
					                      if (!snapshot.hasData || kIsWeb) {
 | 
				
			||||||
 | 
					                        return Text('unknown').tr();
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                      return Text(
 | 
				
			||||||
 | 
					                        snapshot.data!.formatBytes(),
 | 
				
			||||||
 | 
					                        style: GoogleFonts.robotoMono(),
 | 
				
			||||||
 | 
					                      );
 | 
				
			||||||
 | 
					                    },
 | 
				
			||||||
 | 
					                  ),
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					                ListTile(
 | 
				
			||||||
 | 
					                  leading: const Icon(Symbols.database_off),
 | 
				
			||||||
 | 
					                  contentPadding: const EdgeInsets.symmetric(horizontal: 24),
 | 
				
			||||||
 | 
					                  title: Text('databaseDelete').tr(),
 | 
				
			||||||
 | 
					                  subtitle: Text('databaseDeleteDescription').tr(),
 | 
				
			||||||
 | 
					                  trailing: const Icon(Symbols.chevron_right),
 | 
				
			||||||
 | 
					                  onTap: () async {
 | 
				
			||||||
 | 
					                    await dt.removeDatabase();
 | 
				
			||||||
 | 
					                    if (!context.mounted) return;
 | 
				
			||||||
 | 
					                    HapticFeedback.heavyImpact();
 | 
				
			||||||
 | 
					                    context.showSnackbar('databaseDeleted'.tr());
 | 
				
			||||||
 | 
					                    setState(() {});
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
                ListTile(
 | 
					                ListTile(
 | 
				
			||||||
                  title: Text('settingsMiscAbout').tr(),
 | 
					                  title: Text('settingsMiscAbout').tr(),
 | 
				
			||||||
                  subtitle: Text('settingsMiscAboutDescription').tr(),
 | 
					                  subtitle: Text('settingsMiscAboutDescription').tr(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,7 @@ class SnAccount with _$SnAccount {
 | 
				
			|||||||
  const SnAccount._();
 | 
					  const SnAccount._();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  const factory SnAccount({
 | 
					  const factory SnAccount({
 | 
				
			||||||
    @HiveField(0) required int id,
 | 
					    required int id,
 | 
				
			||||||
    required DateTime createdAt,
 | 
					    required DateTime createdAt,
 | 
				
			||||||
    required DateTime updatedAt,
 | 
					    required DateTime updatedAt,
 | 
				
			||||||
    required DateTime? deletedAt,
 | 
					    required DateTime? deletedAt,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -58,7 +58,7 @@ abstract class $SnAccountCopyWith<$Res> {
 | 
				
			|||||||
      _$SnAccountCopyWithImpl<$Res, SnAccount>;
 | 
					      _$SnAccountCopyWithImpl<$Res, SnAccount>;
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
@@ -226,7 +226,7 @@ abstract class _$$SnAccountImplCopyWith<$Res>
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
@@ -374,7 +374,7 @@ class __$$SnAccountImplCopyWithImpl<$Res>
 | 
				
			|||||||
@JsonSerializable()
 | 
					@JsonSerializable()
 | 
				
			||||||
class _$SnAccountImpl extends _SnAccount {
 | 
					class _$SnAccountImpl extends _SnAccount {
 | 
				
			||||||
  const _$SnAccountImpl(
 | 
					  const _$SnAccountImpl(
 | 
				
			||||||
      {@HiveField(0) required this.id,
 | 
					      {required this.id,
 | 
				
			||||||
      required this.createdAt,
 | 
					      required this.createdAt,
 | 
				
			||||||
      required this.updatedAt,
 | 
					      required this.updatedAt,
 | 
				
			||||||
      required this.deletedAt,
 | 
					      required this.deletedAt,
 | 
				
			||||||
@@ -556,7 +556,7 @@ class _$SnAccountImpl extends _SnAccount {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abstract class _SnAccount extends SnAccount {
 | 
					abstract class _SnAccount extends SnAccount {
 | 
				
			||||||
  const factory _SnAccount(
 | 
					  const factory _SnAccount(
 | 
				
			||||||
      {@HiveField(0) required final int id,
 | 
					      {required final int id,
 | 
				
			||||||
      required final DateTime createdAt,
 | 
					      required final DateTime createdAt,
 | 
				
			||||||
      required final DateTime updatedAt,
 | 
					      required final DateTime updatedAt,
 | 
				
			||||||
      required final DateTime? deletedAt,
 | 
					      required final DateTime? deletedAt,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -14,21 +14,21 @@ class SnChannel with _$SnChannel {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @HiveType(typeId: 2)
 | 
					  @HiveType(typeId: 2)
 | 
				
			||||||
  const factory SnChannel({
 | 
					  const factory SnChannel({
 | 
				
			||||||
    @HiveField(0) required int id,
 | 
					    required int id,
 | 
				
			||||||
    @HiveField(1) required DateTime createdAt,
 | 
					    required DateTime createdAt,
 | 
				
			||||||
    @HiveField(2) required DateTime updatedAt,
 | 
					    required DateTime updatedAt,
 | 
				
			||||||
    @HiveField(3) required dynamic deletedAt,
 | 
					    required dynamic deletedAt,
 | 
				
			||||||
    @HiveField(4) required String alias,
 | 
					    required String alias,
 | 
				
			||||||
    @HiveField(5) required String name,
 | 
					    required String name,
 | 
				
			||||||
    @HiveField(6) required String description,
 | 
					    required String description,
 | 
				
			||||||
    @HiveField(7) required List<SnChannelMember>? members,
 | 
					    required List<SnChannelMember>? members,
 | 
				
			||||||
    List<SnChatMessage>? messages,
 | 
					    List<SnChatMessage>? messages,
 | 
				
			||||||
    @HiveField(8) required int type,
 | 
					    required int type,
 | 
				
			||||||
    @HiveField(9) required int accountId,
 | 
					    required int accountId,
 | 
				
			||||||
    @HiveField(10) required SnRealm? realm,
 | 
					    required SnRealm? realm,
 | 
				
			||||||
    @HiveField(11) required int? realmId,
 | 
					    required int? realmId,
 | 
				
			||||||
    @HiveField(12) required bool isPublic,
 | 
					    required bool isPublic,
 | 
				
			||||||
    @HiveField(13) required bool isCommunity,
 | 
					    required bool isCommunity,
 | 
				
			||||||
  }) = _SnChannel;
 | 
					  }) = _SnChannel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  factory SnChannel.fromJson(Map<String, dynamic> json) =>
 | 
					  factory SnChannel.fromJson(Map<String, dynamic> json) =>
 | 
				
			||||||
@@ -44,17 +44,17 @@ class SnChannelMember with _$SnChannelMember {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @HiveType(typeId: 3)
 | 
					  @HiveType(typeId: 3)
 | 
				
			||||||
  const factory SnChannelMember({
 | 
					  const factory SnChannelMember({
 | 
				
			||||||
    @HiveField(0) required int id,
 | 
					    required int id,
 | 
				
			||||||
    @HiveField(1) required DateTime createdAt,
 | 
					    required DateTime createdAt,
 | 
				
			||||||
    @HiveField(2) required DateTime updatedAt,
 | 
					    required DateTime updatedAt,
 | 
				
			||||||
    @HiveField(3) required DateTime? deletedAt,
 | 
					    required DateTime? deletedAt,
 | 
				
			||||||
    @HiveField(4) required int channelId,
 | 
					    required int channelId,
 | 
				
			||||||
    @HiveField(5) required int accountId,
 | 
					    required int accountId,
 | 
				
			||||||
    @HiveField(6) required String? nick,
 | 
					    required String? nick,
 | 
				
			||||||
    @HiveField(7) required SnChannel? channel,
 | 
					    required SnChannel? channel,
 | 
				
			||||||
    @HiveField(8) required SnAccount? account,
 | 
					    required SnAccount? account,
 | 
				
			||||||
    @Default(0) int notify,
 | 
					    @Default(0) int notify,
 | 
				
			||||||
    @HiveField(9) required int powerLevel,
 | 
					    required int powerLevel,
 | 
				
			||||||
    dynamic calls,
 | 
					    dynamic calls,
 | 
				
			||||||
    dynamic events,
 | 
					    dynamic events,
 | 
				
			||||||
  }) = _SnChannelMember;
 | 
					  }) = _SnChannelMember;
 | 
				
			||||||
@@ -69,19 +69,19 @@ class SnChatMessage with _$SnChatMessage {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @HiveType(typeId: 4)
 | 
					  @HiveType(typeId: 4)
 | 
				
			||||||
  const factory SnChatMessage({
 | 
					  const factory SnChatMessage({
 | 
				
			||||||
    @HiveField(0) required int id,
 | 
					    required int id,
 | 
				
			||||||
    @HiveField(1) required DateTime createdAt,
 | 
					    required DateTime createdAt,
 | 
				
			||||||
    @HiveField(2) required DateTime updatedAt,
 | 
					    required DateTime updatedAt,
 | 
				
			||||||
    @HiveField(3) required DateTime? deletedAt,
 | 
					    required DateTime? deletedAt,
 | 
				
			||||||
    @HiveField(4) required String uuid,
 | 
					    required String uuid,
 | 
				
			||||||
    @HiveField(5) @Default({}) Map<String, dynamic> body,
 | 
					    @Default({}) Map<String, dynamic> body,
 | 
				
			||||||
    @HiveField(6) required String type,
 | 
					    required String type,
 | 
				
			||||||
    @HiveField(7) required SnChannel channel,
 | 
					    required SnChannel channel,
 | 
				
			||||||
    @HiveField(8) required SnChannelMember sender,
 | 
					    required SnChannelMember sender,
 | 
				
			||||||
    @HiveField(9) required int channelId,
 | 
					    required int channelId,
 | 
				
			||||||
    @HiveField(10) required int senderId,
 | 
					    required int senderId,
 | 
				
			||||||
    @HiveField(11) required int? quoteEventId,
 | 
					    required int? quoteEventId,
 | 
				
			||||||
    @HiveField(12) required int? relatedEventId,
 | 
					    required int? relatedEventId,
 | 
				
			||||||
    SnChatMessagePreload? preload,
 | 
					    SnChatMessagePreload? preload,
 | 
				
			||||||
  }) = _SnChatMessage;
 | 
					  }) = _SnChatMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -66,21 +66,21 @@ abstract class $SnChannelCopyWith<$Res> {
 | 
				
			|||||||
      _$SnChannelCopyWithImpl<$Res, SnChannel>;
 | 
					      _$SnChannelCopyWithImpl<$Res, SnChannel>;
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) dynamic deletedAt,
 | 
					      dynamic deletedAt,
 | 
				
			||||||
      @HiveField(4) String alias,
 | 
					      String alias,
 | 
				
			||||||
      @HiveField(5) String name,
 | 
					      String name,
 | 
				
			||||||
      @HiveField(6) String description,
 | 
					      String description,
 | 
				
			||||||
      @HiveField(7) List<SnChannelMember>? members,
 | 
					      List<SnChannelMember>? members,
 | 
				
			||||||
      List<SnChatMessage>? messages,
 | 
					      List<SnChatMessage>? messages,
 | 
				
			||||||
      @HiveField(8) int type,
 | 
					      int type,
 | 
				
			||||||
      @HiveField(9) int accountId,
 | 
					      int accountId,
 | 
				
			||||||
      @HiveField(10) SnRealm? realm,
 | 
					      SnRealm? realm,
 | 
				
			||||||
      @HiveField(11) int? realmId,
 | 
					      int? realmId,
 | 
				
			||||||
      @HiveField(12) bool isPublic,
 | 
					      bool isPublic,
 | 
				
			||||||
      @HiveField(13) bool isCommunity});
 | 
					      bool isCommunity});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $SnRealmCopyWith<$Res>? get realm;
 | 
					  $SnRealmCopyWith<$Res>? get realm;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -204,21 +204,21 @@ abstract class _$$SnChannelImplCopyWith<$Res>
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) dynamic deletedAt,
 | 
					      dynamic deletedAt,
 | 
				
			||||||
      @HiveField(4) String alias,
 | 
					      String alias,
 | 
				
			||||||
      @HiveField(5) String name,
 | 
					      String name,
 | 
				
			||||||
      @HiveField(6) String description,
 | 
					      String description,
 | 
				
			||||||
      @HiveField(7) List<SnChannelMember>? members,
 | 
					      List<SnChannelMember>? members,
 | 
				
			||||||
      List<SnChatMessage>? messages,
 | 
					      List<SnChatMessage>? messages,
 | 
				
			||||||
      @HiveField(8) int type,
 | 
					      int type,
 | 
				
			||||||
      @HiveField(9) int accountId,
 | 
					      int accountId,
 | 
				
			||||||
      @HiveField(10) SnRealm? realm,
 | 
					      SnRealm? realm,
 | 
				
			||||||
      @HiveField(11) int? realmId,
 | 
					      int? realmId,
 | 
				
			||||||
      @HiveField(12) bool isPublic,
 | 
					      bool isPublic,
 | 
				
			||||||
      @HiveField(13) bool isCommunity});
 | 
					      bool isCommunity});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
  $SnRealmCopyWith<$Res>? get realm;
 | 
					  $SnRealmCopyWith<$Res>? get realm;
 | 
				
			||||||
@@ -323,21 +323,21 @@ class __$$SnChannelImplCopyWithImpl<$Res>
 | 
				
			|||||||
@HiveType(typeId: 2)
 | 
					@HiveType(typeId: 2)
 | 
				
			||||||
class _$SnChannelImpl extends _SnChannel {
 | 
					class _$SnChannelImpl extends _SnChannel {
 | 
				
			||||||
  const _$SnChannelImpl(
 | 
					  const _$SnChannelImpl(
 | 
				
			||||||
      {@HiveField(0) required this.id,
 | 
					      {required this.id,
 | 
				
			||||||
      @HiveField(1) required this.createdAt,
 | 
					      required this.createdAt,
 | 
				
			||||||
      @HiveField(2) required this.updatedAt,
 | 
					      required this.updatedAt,
 | 
				
			||||||
      @HiveField(3) required this.deletedAt,
 | 
					      required this.deletedAt,
 | 
				
			||||||
      @HiveField(4) required this.alias,
 | 
					      required this.alias,
 | 
				
			||||||
      @HiveField(5) required this.name,
 | 
					      required this.name,
 | 
				
			||||||
      @HiveField(6) required this.description,
 | 
					      required this.description,
 | 
				
			||||||
      @HiveField(7) required final List<SnChannelMember>? members,
 | 
					      required final List<SnChannelMember>? members,
 | 
				
			||||||
      final List<SnChatMessage>? messages,
 | 
					      final List<SnChatMessage>? messages,
 | 
				
			||||||
      @HiveField(8) required this.type,
 | 
					      required this.type,
 | 
				
			||||||
      @HiveField(9) required this.accountId,
 | 
					      required this.accountId,
 | 
				
			||||||
      @HiveField(10) required this.realm,
 | 
					      required this.realm,
 | 
				
			||||||
      @HiveField(11) required this.realmId,
 | 
					      required this.realmId,
 | 
				
			||||||
      @HiveField(12) required this.isPublic,
 | 
					      required this.isPublic,
 | 
				
			||||||
      @HiveField(13) required this.isCommunity})
 | 
					      required this.isCommunity})
 | 
				
			||||||
      : _members = members,
 | 
					      : _members = members,
 | 
				
			||||||
        _messages = messages,
 | 
					        _messages = messages,
 | 
				
			||||||
        super._();
 | 
					        super._();
 | 
				
			||||||
@@ -477,21 +477,21 @@ class _$SnChannelImpl extends _SnChannel {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abstract class _SnChannel extends SnChannel {
 | 
					abstract class _SnChannel extends SnChannel {
 | 
				
			||||||
  const factory _SnChannel(
 | 
					  const factory _SnChannel(
 | 
				
			||||||
      {@HiveField(0) required final int id,
 | 
					      {required final int id,
 | 
				
			||||||
      @HiveField(1) required final DateTime createdAt,
 | 
					      required final DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) required final DateTime updatedAt,
 | 
					      required final DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) required final dynamic deletedAt,
 | 
					      required final dynamic deletedAt,
 | 
				
			||||||
      @HiveField(4) required final String alias,
 | 
					      required final String alias,
 | 
				
			||||||
      @HiveField(5) required final String name,
 | 
					      required final String name,
 | 
				
			||||||
      @HiveField(6) required final String description,
 | 
					      required final String description,
 | 
				
			||||||
      @HiveField(7) required final List<SnChannelMember>? members,
 | 
					      required final List<SnChannelMember>? members,
 | 
				
			||||||
      final List<SnChatMessage>? messages,
 | 
					      final List<SnChatMessage>? messages,
 | 
				
			||||||
      @HiveField(8) required final int type,
 | 
					      required final int type,
 | 
				
			||||||
      @HiveField(9) required final int accountId,
 | 
					      required final int accountId,
 | 
				
			||||||
      @HiveField(10) required final SnRealm? realm,
 | 
					      required final SnRealm? realm,
 | 
				
			||||||
      @HiveField(11) required final int? realmId,
 | 
					      required final int? realmId,
 | 
				
			||||||
      @HiveField(12) required final bool isPublic,
 | 
					      required final bool isPublic,
 | 
				
			||||||
      @HiveField(13) required final bool isCommunity}) = _$SnChannelImpl;
 | 
					      required final bool isCommunity}) = _$SnChannelImpl;
 | 
				
			||||||
  const _SnChannel._() : super._();
 | 
					  const _SnChannel._() : super._();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  factory _SnChannel.fromJson(Map<String, dynamic> json) =
 | 
					  factory _SnChannel.fromJson(Map<String, dynamic> json) =
 | 
				
			||||||
@@ -597,17 +597,17 @@ abstract class $SnChannelMemberCopyWith<$Res> {
 | 
				
			|||||||
      _$SnChannelMemberCopyWithImpl<$Res, SnChannelMember>;
 | 
					      _$SnChannelMemberCopyWithImpl<$Res, SnChannelMember>;
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) int channelId,
 | 
					      int channelId,
 | 
				
			||||||
      @HiveField(5) int accountId,
 | 
					      int accountId,
 | 
				
			||||||
      @HiveField(6) String? nick,
 | 
					      String? nick,
 | 
				
			||||||
      @HiveField(7) SnChannel? channel,
 | 
					      SnChannel? channel,
 | 
				
			||||||
      @HiveField(8) SnAccount? account,
 | 
					      SnAccount? account,
 | 
				
			||||||
      int notify,
 | 
					      int notify,
 | 
				
			||||||
      @HiveField(9) int powerLevel,
 | 
					      int powerLevel,
 | 
				
			||||||
      dynamic calls,
 | 
					      dynamic calls,
 | 
				
			||||||
      dynamic events});
 | 
					      dynamic events});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -738,17 +738,17 @@ abstract class _$$SnChannelMemberImplCopyWith<$Res>
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) int channelId,
 | 
					      int channelId,
 | 
				
			||||||
      @HiveField(5) int accountId,
 | 
					      int accountId,
 | 
				
			||||||
      @HiveField(6) String? nick,
 | 
					      String? nick,
 | 
				
			||||||
      @HiveField(7) SnChannel? channel,
 | 
					      SnChannel? channel,
 | 
				
			||||||
      @HiveField(8) SnAccount? account,
 | 
					      SnAccount? account,
 | 
				
			||||||
      int notify,
 | 
					      int notify,
 | 
				
			||||||
      @HiveField(9) int powerLevel,
 | 
					      int powerLevel,
 | 
				
			||||||
      dynamic calls,
 | 
					      dynamic calls,
 | 
				
			||||||
      dynamic events});
 | 
					      dynamic events});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -847,17 +847,17 @@ class __$$SnChannelMemberImplCopyWithImpl<$Res>
 | 
				
			|||||||
@HiveType(typeId: 3)
 | 
					@HiveType(typeId: 3)
 | 
				
			||||||
class _$SnChannelMemberImpl extends _SnChannelMember {
 | 
					class _$SnChannelMemberImpl extends _SnChannelMember {
 | 
				
			||||||
  const _$SnChannelMemberImpl(
 | 
					  const _$SnChannelMemberImpl(
 | 
				
			||||||
      {@HiveField(0) required this.id,
 | 
					      {required this.id,
 | 
				
			||||||
      @HiveField(1) required this.createdAt,
 | 
					      required this.createdAt,
 | 
				
			||||||
      @HiveField(2) required this.updatedAt,
 | 
					      required this.updatedAt,
 | 
				
			||||||
      @HiveField(3) required this.deletedAt,
 | 
					      required this.deletedAt,
 | 
				
			||||||
      @HiveField(4) required this.channelId,
 | 
					      required this.channelId,
 | 
				
			||||||
      @HiveField(5) required this.accountId,
 | 
					      required this.accountId,
 | 
				
			||||||
      @HiveField(6) required this.nick,
 | 
					      required this.nick,
 | 
				
			||||||
      @HiveField(7) required this.channel,
 | 
					      required this.channel,
 | 
				
			||||||
      @HiveField(8) required this.account,
 | 
					      required this.account,
 | 
				
			||||||
      this.notify = 0,
 | 
					      this.notify = 0,
 | 
				
			||||||
      @HiveField(9) required this.powerLevel,
 | 
					      required this.powerLevel,
 | 
				
			||||||
      this.calls,
 | 
					      this.calls,
 | 
				
			||||||
      this.events})
 | 
					      this.events})
 | 
				
			||||||
      : super._();
 | 
					      : super._();
 | 
				
			||||||
@@ -971,17 +971,17 @@ class _$SnChannelMemberImpl extends _SnChannelMember {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abstract class _SnChannelMember extends SnChannelMember {
 | 
					abstract class _SnChannelMember extends SnChannelMember {
 | 
				
			||||||
  const factory _SnChannelMember(
 | 
					  const factory _SnChannelMember(
 | 
				
			||||||
      {@HiveField(0) required final int id,
 | 
					      {required final int id,
 | 
				
			||||||
      @HiveField(1) required final DateTime createdAt,
 | 
					      required final DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) required final DateTime updatedAt,
 | 
					      required final DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) required final DateTime? deletedAt,
 | 
					      required final DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) required final int channelId,
 | 
					      required final int channelId,
 | 
				
			||||||
      @HiveField(5) required final int accountId,
 | 
					      required final int accountId,
 | 
				
			||||||
      @HiveField(6) required final String? nick,
 | 
					      required final String? nick,
 | 
				
			||||||
      @HiveField(7) required final SnChannel? channel,
 | 
					      required final SnChannel? channel,
 | 
				
			||||||
      @HiveField(8) required final SnAccount? account,
 | 
					      required final SnAccount? account,
 | 
				
			||||||
      final int notify,
 | 
					      final int notify,
 | 
				
			||||||
      @HiveField(9) required final int powerLevel,
 | 
					      required final int powerLevel,
 | 
				
			||||||
      final dynamic calls,
 | 
					      final dynamic calls,
 | 
				
			||||||
      final dynamic events}) = _$SnChannelMemberImpl;
 | 
					      final dynamic events}) = _$SnChannelMemberImpl;
 | 
				
			||||||
  const _SnChannelMember._() : super._();
 | 
					  const _SnChannelMember._() : super._();
 | 
				
			||||||
@@ -1085,19 +1085,19 @@ abstract class $SnChatMessageCopyWith<$Res> {
 | 
				
			|||||||
      _$SnChatMessageCopyWithImpl<$Res, SnChatMessage>;
 | 
					      _$SnChatMessageCopyWithImpl<$Res, SnChatMessage>;
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) String uuid,
 | 
					      String uuid,
 | 
				
			||||||
      @HiveField(5) Map<String, dynamic> body,
 | 
					      Map<String, dynamic> body,
 | 
				
			||||||
      @HiveField(6) String type,
 | 
					      String type,
 | 
				
			||||||
      @HiveField(7) SnChannel channel,
 | 
					      SnChannel channel,
 | 
				
			||||||
      @HiveField(8) SnChannelMember sender,
 | 
					      SnChannelMember sender,
 | 
				
			||||||
      @HiveField(9) int channelId,
 | 
					      int channelId,
 | 
				
			||||||
      @HiveField(10) int senderId,
 | 
					      int senderId,
 | 
				
			||||||
      @HiveField(11) int? quoteEventId,
 | 
					      int? quoteEventId,
 | 
				
			||||||
      @HiveField(12) int? relatedEventId,
 | 
					      int? relatedEventId,
 | 
				
			||||||
      SnChatMessagePreload? preload});
 | 
					      SnChatMessagePreload? preload});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  $SnChannelCopyWith<$Res> get channel;
 | 
					  $SnChannelCopyWith<$Res> get channel;
 | 
				
			||||||
@@ -1239,19 +1239,19 @@ abstract class _$$SnChatMessageImplCopyWith<$Res>
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) String uuid,
 | 
					      String uuid,
 | 
				
			||||||
      @HiveField(5) Map<String, dynamic> body,
 | 
					      Map<String, dynamic> body,
 | 
				
			||||||
      @HiveField(6) String type,
 | 
					      String type,
 | 
				
			||||||
      @HiveField(7) SnChannel channel,
 | 
					      SnChannel channel,
 | 
				
			||||||
      @HiveField(8) SnChannelMember sender,
 | 
					      SnChannelMember sender,
 | 
				
			||||||
      @HiveField(9) int channelId,
 | 
					      int channelId,
 | 
				
			||||||
      @HiveField(10) int senderId,
 | 
					      int senderId,
 | 
				
			||||||
      @HiveField(11) int? quoteEventId,
 | 
					      int? quoteEventId,
 | 
				
			||||||
      @HiveField(12) int? relatedEventId,
 | 
					      int? relatedEventId,
 | 
				
			||||||
      SnChatMessagePreload? preload});
 | 
					      SnChatMessagePreload? preload});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @override
 | 
					  @override
 | 
				
			||||||
@@ -1356,19 +1356,19 @@ class __$$SnChatMessageImplCopyWithImpl<$Res>
 | 
				
			|||||||
@HiveType(typeId: 4)
 | 
					@HiveType(typeId: 4)
 | 
				
			||||||
class _$SnChatMessageImpl extends _SnChatMessage {
 | 
					class _$SnChatMessageImpl extends _SnChatMessage {
 | 
				
			||||||
  const _$SnChatMessageImpl(
 | 
					  const _$SnChatMessageImpl(
 | 
				
			||||||
      {@HiveField(0) required this.id,
 | 
					      {required this.id,
 | 
				
			||||||
      @HiveField(1) required this.createdAt,
 | 
					      required this.createdAt,
 | 
				
			||||||
      @HiveField(2) required this.updatedAt,
 | 
					      required this.updatedAt,
 | 
				
			||||||
      @HiveField(3) required this.deletedAt,
 | 
					      required this.deletedAt,
 | 
				
			||||||
      @HiveField(4) required this.uuid,
 | 
					      required this.uuid,
 | 
				
			||||||
      @HiveField(5) final Map<String, dynamic> body = const {},
 | 
					      final Map<String, dynamic> body = const {},
 | 
				
			||||||
      @HiveField(6) required this.type,
 | 
					      required this.type,
 | 
				
			||||||
      @HiveField(7) required this.channel,
 | 
					      required this.channel,
 | 
				
			||||||
      @HiveField(8) required this.sender,
 | 
					      required this.sender,
 | 
				
			||||||
      @HiveField(9) required this.channelId,
 | 
					      required this.channelId,
 | 
				
			||||||
      @HiveField(10) required this.senderId,
 | 
					      required this.senderId,
 | 
				
			||||||
      @HiveField(11) required this.quoteEventId,
 | 
					      required this.quoteEventId,
 | 
				
			||||||
      @HiveField(12) required this.relatedEventId,
 | 
					      required this.relatedEventId,
 | 
				
			||||||
      this.preload})
 | 
					      this.preload})
 | 
				
			||||||
      : _body = body,
 | 
					      : _body = body,
 | 
				
			||||||
        super._();
 | 
					        super._();
 | 
				
			||||||
@@ -1495,19 +1495,19 @@ class _$SnChatMessageImpl extends _SnChatMessage {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abstract class _SnChatMessage extends SnChatMessage {
 | 
					abstract class _SnChatMessage extends SnChatMessage {
 | 
				
			||||||
  const factory _SnChatMessage(
 | 
					  const factory _SnChatMessage(
 | 
				
			||||||
      {@HiveField(0) required final int id,
 | 
					      {required final int id,
 | 
				
			||||||
      @HiveField(1) required final DateTime createdAt,
 | 
					      required final DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) required final DateTime updatedAt,
 | 
					      required final DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) required final DateTime? deletedAt,
 | 
					      required final DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) required final String uuid,
 | 
					      required final String uuid,
 | 
				
			||||||
      @HiveField(5) final Map<String, dynamic> body,
 | 
					      final Map<String, dynamic> body,
 | 
				
			||||||
      @HiveField(6) required final String type,
 | 
					      required final String type,
 | 
				
			||||||
      @HiveField(7) required final SnChannel channel,
 | 
					      required final SnChannel channel,
 | 
				
			||||||
      @HiveField(8) required final SnChannelMember sender,
 | 
					      required final SnChannelMember sender,
 | 
				
			||||||
      @HiveField(9) required final int channelId,
 | 
					      required final int channelId,
 | 
				
			||||||
      @HiveField(10) required final int senderId,
 | 
					      required final int senderId,
 | 
				
			||||||
      @HiveField(11) required final int? quoteEventId,
 | 
					      required final int? quoteEventId,
 | 
				
			||||||
      @HiveField(12) required final int? relatedEventId,
 | 
					      required final int? relatedEventId,
 | 
				
			||||||
      final SnChatMessagePreload? preload}) = _$SnChatMessageImpl;
 | 
					      final SnChatMessagePreload? preload}) = _$SnChatMessageImpl;
 | 
				
			||||||
  const _SnChatMessage._() : super._();
 | 
					  const _SnChatMessage._() : super._();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,20 +29,20 @@ class SnRealm with _$SnRealm {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  @HiveType(typeId: 1)
 | 
					  @HiveType(typeId: 1)
 | 
				
			||||||
  const factory SnRealm({
 | 
					  const factory SnRealm({
 | 
				
			||||||
    @HiveField(0) required int id,
 | 
					    required int id,
 | 
				
			||||||
    @HiveField(1) required DateTime createdAt,
 | 
					    required DateTime createdAt,
 | 
				
			||||||
    @HiveField(2) required DateTime updatedAt,
 | 
					    required DateTime updatedAt,
 | 
				
			||||||
    @HiveField(3) required DateTime? deletedAt,
 | 
					    required DateTime? deletedAt,
 | 
				
			||||||
    @HiveField(4) required String alias,
 | 
					    required String alias,
 | 
				
			||||||
    @HiveField(5) required String name,
 | 
					    required String name,
 | 
				
			||||||
    @HiveField(6) required String description,
 | 
					    required String description,
 | 
				
			||||||
    List<SnRealmMember>? members,
 | 
					    List<SnRealmMember>? members,
 | 
				
			||||||
    @HiveField(7) required String? avatar,
 | 
					    required String? avatar,
 | 
				
			||||||
    @HiveField(8) required String? banner,
 | 
					    required String? banner,
 | 
				
			||||||
    @HiveField(9) required Map<String, dynamic>? accessPolicy,
 | 
					    required Map<String, dynamic>? accessPolicy,
 | 
				
			||||||
    @HiveField(10) required int accountId,
 | 
					    required int accountId,
 | 
				
			||||||
    @HiveField(11) required bool isPublic,
 | 
					    required bool isPublic,
 | 
				
			||||||
    @HiveField(12) required bool isCommunity,
 | 
					    required bool isCommunity,
 | 
				
			||||||
    @Default(0) int popularity,
 | 
					    @Default(0) int popularity,
 | 
				
			||||||
  }) = _SnRealm;
 | 
					  }) = _SnRealm;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -411,20 +411,20 @@ abstract class $SnRealmCopyWith<$Res> {
 | 
				
			|||||||
      _$SnRealmCopyWithImpl<$Res, SnRealm>;
 | 
					      _$SnRealmCopyWithImpl<$Res, SnRealm>;
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) String alias,
 | 
					      String alias,
 | 
				
			||||||
      @HiveField(5) String name,
 | 
					      String name,
 | 
				
			||||||
      @HiveField(6) String description,
 | 
					      String description,
 | 
				
			||||||
      List<SnRealmMember>? members,
 | 
					      List<SnRealmMember>? members,
 | 
				
			||||||
      @HiveField(7) String? avatar,
 | 
					      String? avatar,
 | 
				
			||||||
      @HiveField(8) String? banner,
 | 
					      String? banner,
 | 
				
			||||||
      @HiveField(9) Map<String, dynamic>? accessPolicy,
 | 
					      Map<String, dynamic>? accessPolicy,
 | 
				
			||||||
      @HiveField(10) int accountId,
 | 
					      int accountId,
 | 
				
			||||||
      @HiveField(11) bool isPublic,
 | 
					      bool isPublic,
 | 
				
			||||||
      @HiveField(12) bool isCommunity,
 | 
					      bool isCommunity,
 | 
				
			||||||
      int popularity});
 | 
					      int popularity});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -532,20 +532,20 @@ abstract class _$$SnRealmImplCopyWith<$Res> implements $SnRealmCopyWith<$Res> {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  @useResult
 | 
					  @useResult
 | 
				
			||||||
  $Res call(
 | 
					  $Res call(
 | 
				
			||||||
      {@HiveField(0) int id,
 | 
					      {int id,
 | 
				
			||||||
      @HiveField(1) DateTime createdAt,
 | 
					      DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) DateTime updatedAt,
 | 
					      DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) DateTime? deletedAt,
 | 
					      DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) String alias,
 | 
					      String alias,
 | 
				
			||||||
      @HiveField(5) String name,
 | 
					      String name,
 | 
				
			||||||
      @HiveField(6) String description,
 | 
					      String description,
 | 
				
			||||||
      List<SnRealmMember>? members,
 | 
					      List<SnRealmMember>? members,
 | 
				
			||||||
      @HiveField(7) String? avatar,
 | 
					      String? avatar,
 | 
				
			||||||
      @HiveField(8) String? banner,
 | 
					      String? banner,
 | 
				
			||||||
      @HiveField(9) Map<String, dynamic>? accessPolicy,
 | 
					      Map<String, dynamic>? accessPolicy,
 | 
				
			||||||
      @HiveField(10) int accountId,
 | 
					      int accountId,
 | 
				
			||||||
      @HiveField(11) bool isPublic,
 | 
					      bool isPublic,
 | 
				
			||||||
      @HiveField(12) bool isCommunity,
 | 
					      bool isCommunity,
 | 
				
			||||||
      int popularity});
 | 
					      int popularity});
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -648,20 +648,20 @@ class __$$SnRealmImplCopyWithImpl<$Res>
 | 
				
			|||||||
@HiveType(typeId: 1)
 | 
					@HiveType(typeId: 1)
 | 
				
			||||||
class _$SnRealmImpl extends _SnRealm {
 | 
					class _$SnRealmImpl extends _SnRealm {
 | 
				
			||||||
  const _$SnRealmImpl(
 | 
					  const _$SnRealmImpl(
 | 
				
			||||||
      {@HiveField(0) required this.id,
 | 
					      {required this.id,
 | 
				
			||||||
      @HiveField(1) required this.createdAt,
 | 
					      required this.createdAt,
 | 
				
			||||||
      @HiveField(2) required this.updatedAt,
 | 
					      required this.updatedAt,
 | 
				
			||||||
      @HiveField(3) required this.deletedAt,
 | 
					      required this.deletedAt,
 | 
				
			||||||
      @HiveField(4) required this.alias,
 | 
					      required this.alias,
 | 
				
			||||||
      @HiveField(5) required this.name,
 | 
					      required this.name,
 | 
				
			||||||
      @HiveField(6) required this.description,
 | 
					      required this.description,
 | 
				
			||||||
      final List<SnRealmMember>? members,
 | 
					      final List<SnRealmMember>? members,
 | 
				
			||||||
      @HiveField(7) required this.avatar,
 | 
					      required this.avatar,
 | 
				
			||||||
      @HiveField(8) required this.banner,
 | 
					      required this.banner,
 | 
				
			||||||
      @HiveField(9) required final Map<String, dynamic>? accessPolicy,
 | 
					      required final Map<String, dynamic>? accessPolicy,
 | 
				
			||||||
      @HiveField(10) required this.accountId,
 | 
					      required this.accountId,
 | 
				
			||||||
      @HiveField(11) required this.isPublic,
 | 
					      required this.isPublic,
 | 
				
			||||||
      @HiveField(12) required this.isCommunity,
 | 
					      required this.isCommunity,
 | 
				
			||||||
      this.popularity = 0})
 | 
					      this.popularity = 0})
 | 
				
			||||||
      : _members = members,
 | 
					      : _members = members,
 | 
				
			||||||
        _accessPolicy = accessPolicy,
 | 
					        _accessPolicy = accessPolicy,
 | 
				
			||||||
@@ -805,20 +805,20 @@ class _$SnRealmImpl extends _SnRealm {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
abstract class _SnRealm extends SnRealm {
 | 
					abstract class _SnRealm extends SnRealm {
 | 
				
			||||||
  const factory _SnRealm(
 | 
					  const factory _SnRealm(
 | 
				
			||||||
      {@HiveField(0) required final int id,
 | 
					      {required final int id,
 | 
				
			||||||
      @HiveField(1) required final DateTime createdAt,
 | 
					      required final DateTime createdAt,
 | 
				
			||||||
      @HiveField(2) required final DateTime updatedAt,
 | 
					      required final DateTime updatedAt,
 | 
				
			||||||
      @HiveField(3) required final DateTime? deletedAt,
 | 
					      required final DateTime? deletedAt,
 | 
				
			||||||
      @HiveField(4) required final String alias,
 | 
					      required final String alias,
 | 
				
			||||||
      @HiveField(5) required final String name,
 | 
					      required final String name,
 | 
				
			||||||
      @HiveField(6) required final String description,
 | 
					      required final String description,
 | 
				
			||||||
      final List<SnRealmMember>? members,
 | 
					      final List<SnRealmMember>? members,
 | 
				
			||||||
      @HiveField(7) required final String? avatar,
 | 
					      required final String? avatar,
 | 
				
			||||||
      @HiveField(8) required final String? banner,
 | 
					      required final String? banner,
 | 
				
			||||||
      @HiveField(9) required final Map<String, dynamic>? accessPolicy,
 | 
					      required final Map<String, dynamic>? accessPolicy,
 | 
				
			||||||
      @HiveField(10) required final int accountId,
 | 
					      required final int accountId,
 | 
				
			||||||
      @HiveField(11) required final bool isPublic,
 | 
					      required final bool isPublic,
 | 
				
			||||||
      @HiveField(12) required final bool isCommunity,
 | 
					      required final bool isCommunity,
 | 
				
			||||||
      final int popularity}) = _$SnRealmImpl;
 | 
					      final int popularity}) = _$SnRealmImpl;
 | 
				
			||||||
  const _SnRealm._() : super._();
 | 
					  const _SnRealm._() : super._();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,7 @@
 | 
				
			|||||||
#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
 | 
					#include <media_kit_libs_linux/media_kit_libs_linux_plugin.h>
 | 
				
			||||||
#include <media_kit_video/media_kit_video_plugin.h>
 | 
					#include <media_kit_video/media_kit_video_plugin.h>
 | 
				
			||||||
#include <pasteboard/pasteboard_plugin.h>
 | 
					#include <pasteboard/pasteboard_plugin.h>
 | 
				
			||||||
 | 
					#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
 | 
				
			||||||
#include <tray_manager/tray_manager_plugin.h>
 | 
					#include <tray_manager/tray_manager_plugin.h>
 | 
				
			||||||
#include <url_launcher_linux/url_launcher_plugin.h>
 | 
					#include <url_launcher_linux/url_launcher_plugin.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -46,6 +47,9 @@ void fl_register_plugins(FlPluginRegistry* registry) {
 | 
				
			|||||||
  g_autoptr(FlPluginRegistrar) pasteboard_registrar =
 | 
					  g_autoptr(FlPluginRegistrar) pasteboard_registrar =
 | 
				
			||||||
      fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
 | 
					      fl_plugin_registry_get_registrar_for_plugin(registry, "PasteboardPlugin");
 | 
				
			||||||
  pasteboard_plugin_register_with_registrar(pasteboard_registrar);
 | 
					  pasteboard_plugin_register_with_registrar(pasteboard_registrar);
 | 
				
			||||||
 | 
					  g_autoptr(FlPluginRegistrar) sqlite3_flutter_libs_registrar =
 | 
				
			||||||
 | 
					      fl_plugin_registry_get_registrar_for_plugin(registry, "Sqlite3FlutterLibsPlugin");
 | 
				
			||||||
 | 
					  sqlite3_flutter_libs_plugin_register_with_registrar(sqlite3_flutter_libs_registrar);
 | 
				
			||||||
  g_autoptr(FlPluginRegistrar) tray_manager_registrar =
 | 
					  g_autoptr(FlPluginRegistrar) tray_manager_registrar =
 | 
				
			||||||
      fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin");
 | 
					      fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin");
 | 
				
			||||||
  tray_manager_plugin_register_with_registrar(tray_manager_registrar);
 | 
					  tray_manager_plugin_register_with_registrar(tray_manager_registrar);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -12,6 +12,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
 | 
				
			|||||||
  media_kit_libs_linux
 | 
					  media_kit_libs_linux
 | 
				
			||||||
  media_kit_video
 | 
					  media_kit_video
 | 
				
			||||||
  pasteboard
 | 
					  pasteboard
 | 
				
			||||||
 | 
					  sqlite3_flutter_libs
 | 
				
			||||||
  tray_manager
 | 
					  tray_manager
 | 
				
			||||||
  url_launcher_linux
 | 
					  url_launcher_linux
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -30,6 +30,7 @@ import screen_brightness_macos
 | 
				
			|||||||
import share_plus
 | 
					import share_plus
 | 
				
			||||||
import shared_preferences_foundation
 | 
					import shared_preferences_foundation
 | 
				
			||||||
import sqflite_darwin
 | 
					import sqflite_darwin
 | 
				
			||||||
 | 
					import sqlite3_flutter_libs
 | 
				
			||||||
import tray_manager
 | 
					import tray_manager
 | 
				
			||||||
import url_launcher_macos
 | 
					import url_launcher_macos
 | 
				
			||||||
import video_compress
 | 
					import video_compress
 | 
				
			||||||
@@ -61,6 +62,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
 | 
				
			|||||||
  SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
 | 
					  SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
 | 
				
			||||||
  SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
 | 
					  SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
 | 
				
			||||||
  SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
 | 
					  SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
 | 
				
			||||||
 | 
					  Sqlite3FlutterLibsPlugin.register(with: registry.registrar(forPlugin: "Sqlite3FlutterLibsPlugin"))
 | 
				
			||||||
  TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
 | 
					  TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
 | 
				
			||||||
  UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
 | 
					  UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
 | 
				
			||||||
  VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin"))
 | 
					  VideoCompressPlugin.register(with: registry.registrar(forPlugin: "VideoCompressPlugin"))
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										88
									
								
								pubspec.lock
									
									
									
									
									
								
							
							
						
						
									
										88
									
								
								pubspec.lock
									
									
									
									
									
								
							@@ -230,6 +230,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.3.0"
 | 
					    version: "1.3.0"
 | 
				
			||||||
 | 
					  charcode:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: charcode
 | 
				
			||||||
 | 
					      sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "1.4.0"
 | 
				
			||||||
  checked_yaml:
 | 
					  checked_yaml:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -414,6 +422,30 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "1.0.2"
 | 
					    version: "1.0.2"
 | 
				
			||||||
 | 
					  drift:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: drift
 | 
				
			||||||
 | 
					      sha256: "97d5832657d49f26e7a8e07de397ddc63790b039372878d5117af816d0fdb5cb"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.25.1"
 | 
				
			||||||
 | 
					  drift_dev:
 | 
				
			||||||
 | 
					    dependency: "direct dev"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: drift_dev
 | 
				
			||||||
 | 
					      sha256: f1db88482dbb016b9bbddddf746d5d0a6938b156ff20e07320052981f97388cc
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.25.2"
 | 
				
			||||||
 | 
					  drift_flutter:
 | 
				
			||||||
 | 
					    dependency: "direct main"
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: drift_flutter
 | 
				
			||||||
 | 
					      sha256: "0cadbf3b8733409a6cf61d18ba2e94e149df81df7de26f48ae0695b48fd71922"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.2.4"
 | 
				
			||||||
  dropdown_button2:
 | 
					  dropdown_button2:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -914,30 +946,6 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.3.2"
 | 
					    version: "2.3.2"
 | 
				
			||||||
  hive:
 | 
					 | 
				
			||||||
    dependency: "direct main"
 | 
					 | 
				
			||||||
    description:
 | 
					 | 
				
			||||||
      name: hive
 | 
					 | 
				
			||||||
      sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
 | 
					 | 
				
			||||||
      url: "https://pub.dev"
 | 
					 | 
				
			||||||
    source: hosted
 | 
					 | 
				
			||||||
    version: "2.2.3"
 | 
					 | 
				
			||||||
  hive_flutter:
 | 
					 | 
				
			||||||
    dependency: "direct main"
 | 
					 | 
				
			||||||
    description:
 | 
					 | 
				
			||||||
      name: hive_flutter
 | 
					 | 
				
			||||||
      sha256: dca1da446b1d808a51689fb5d0c6c9510c0a2ba01e22805d492c73b68e33eecc
 | 
					 | 
				
			||||||
      url: "https://pub.dev"
 | 
					 | 
				
			||||||
    source: hosted
 | 
					 | 
				
			||||||
    version: "1.1.0"
 | 
					 | 
				
			||||||
  hive_generator:
 | 
					 | 
				
			||||||
    dependency: "direct dev"
 | 
					 | 
				
			||||||
    description:
 | 
					 | 
				
			||||||
      name: hive_generator
 | 
					 | 
				
			||||||
      sha256: "06cb8f58ace74de61f63500564931f9505368f45f98958bd7a6c35ba24159db4"
 | 
					 | 
				
			||||||
      url: "https://pub.dev"
 | 
					 | 
				
			||||||
    source: hosted
 | 
					 | 
				
			||||||
    version: "2.0.1"
 | 
					 | 
				
			||||||
  home_widget:
 | 
					  home_widget:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -1642,6 +1650,14 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "4.1.0"
 | 
					    version: "4.1.0"
 | 
				
			||||||
 | 
					  recase:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: recase
 | 
				
			||||||
 | 
					      sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "4.1.0"
 | 
				
			||||||
  receive_sharing_intent:
 | 
					  receive_sharing_intent:
 | 
				
			||||||
    dependency: "direct main"
 | 
					    dependency: "direct main"
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
@@ -1935,6 +1951,30 @@ packages:
 | 
				
			|||||||
      url: "https://pub.dev"
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
    source: hosted
 | 
					    source: hosted
 | 
				
			||||||
    version: "2.4.0"
 | 
					    version: "2.4.0"
 | 
				
			||||||
 | 
					  sqlite3:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqlite3
 | 
				
			||||||
 | 
					      sha256: "32b632dda27d664f85520093ed6f735ae5c49b5b75345afb8b19411bc59bb53d"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "2.7.4"
 | 
				
			||||||
 | 
					  sqlite3_flutter_libs:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqlite3_flutter_libs
 | 
				
			||||||
 | 
					      sha256: "57fafacd815c981735406215966ff7caaa8eab984b094f52e692accefcbd9233"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.5.30"
 | 
				
			||||||
 | 
					  sqlparser:
 | 
				
			||||||
 | 
					    dependency: transitive
 | 
				
			||||||
 | 
					    description:
 | 
				
			||||||
 | 
					      name: sqlparser
 | 
				
			||||||
 | 
					      sha256: "27dd0a9f0c02e22ac0eb42a23df9ea079ce69b52bb4a3b478d64e0ef34a263ee"
 | 
				
			||||||
 | 
					      url: "https://pub.dev"
 | 
				
			||||||
 | 
					    source: hosted
 | 
				
			||||||
 | 
					    version: "0.41.0"
 | 
				
			||||||
  stack_trace:
 | 
					  stack_trace:
 | 
				
			||||||
    dependency: transitive
 | 
					    dependency: transitive
 | 
				
			||||||
    description:
 | 
					    description:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -72,8 +72,6 @@ dependencies:
 | 
				
			|||||||
  collection: ^1.18.0
 | 
					  collection: ^1.18.0
 | 
				
			||||||
  mime: ^2.0.0
 | 
					  mime: ^2.0.0
 | 
				
			||||||
  web_socket_channel: ^3.0.1
 | 
					  web_socket_channel: ^3.0.1
 | 
				
			||||||
  hive: ^2.2.3
 | 
					 | 
				
			||||||
  hive_flutter: ^1.1.0
 | 
					 | 
				
			||||||
  swipe_to: ^1.0.6
 | 
					  swipe_to: ^1.0.6
 | 
				
			||||||
  firebase_core: ^3.8.0
 | 
					  firebase_core: ^3.8.0
 | 
				
			||||||
  firebase_messaging: ^15.1.5
 | 
					  firebase_messaging: ^15.1.5
 | 
				
			||||||
@@ -123,6 +121,8 @@ dependencies:
 | 
				
			|||||||
  image_picker_android: ^0.8.12+20
 | 
					  image_picker_android: ^0.8.12+20
 | 
				
			||||||
  cached_network_image_platform_interface: ^4.1.1
 | 
					  cached_network_image_platform_interface: ^4.1.1
 | 
				
			||||||
  image_picker_platform_interface: ^2.10.1
 | 
					  image_picker_platform_interface: ^2.10.1
 | 
				
			||||||
 | 
					  drift: ^2.25.1
 | 
				
			||||||
 | 
					  drift_flutter: ^0.2.4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
dev_dependencies:
 | 
					dev_dependencies:
 | 
				
			||||||
  flutter_test:
 | 
					  flutter_test:
 | 
				
			||||||
@@ -134,13 +134,13 @@ dev_dependencies:
 | 
				
			|||||||
  # package. See that file for information about deactivating specific lint
 | 
					  # package. See that file for information about deactivating specific lint
 | 
				
			||||||
  # rules and activating additional ones.
 | 
					  # rules and activating additional ones.
 | 
				
			||||||
  flutter_lints: ^5.0.0
 | 
					  flutter_lints: ^5.0.0
 | 
				
			||||||
  build_runner: ^2.4.13
 | 
					  build_runner: ^2.4.15
 | 
				
			||||||
  freezed: ^2.5.7
 | 
					  freezed: ^2.5.7
 | 
				
			||||||
  json_serializable: ^6.8.0
 | 
					  json_serializable: ^6.8.0
 | 
				
			||||||
  icons_launcher: ^3.0.0
 | 
					  icons_launcher: ^3.0.0
 | 
				
			||||||
  flutter_native_splash: ^2.4.2
 | 
					  flutter_native_splash: ^2.4.2
 | 
				
			||||||
  hive_generator: ^2.0.1
 | 
					 | 
				
			||||||
  flutter_launcher_icons: ^0.14.1
 | 
					  flutter_launcher_icons: ^0.14.1
 | 
				
			||||||
 | 
					  drift_dev: ^2.25.2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# For information on the generic Dart part of this file, see the
 | 
					# For information on the generic Dart part of this file, see the
 | 
				
			||||||
# following page: https://dart.dev/tools/pub/pubspec
 | 
					# following page: https://dart.dev/tools/pub/pubspec
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										13631
									
								
								web/drift_worker.dart.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13631
									
								
								web/drift_worker.dart.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -1,11 +1,11 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "name": "surface",
 | 
					    "name": "Solar Network",
 | 
				
			||||||
    "short_name": "surface",
 | 
					    "short_name": "Solian",
 | 
				
			||||||
    "start_url": ".",
 | 
					    "start_url": ".",
 | 
				
			||||||
    "display": "standalone",
 | 
					    "display": "standalone",
 | 
				
			||||||
    "background_color": "#ffffff",
 | 
					    "background_color": "#ffffff",
 | 
				
			||||||
    "theme_color": "#ffffff",
 | 
					    "theme_color": "#ffffff",
 | 
				
			||||||
    "description": "A new Flutter project.",
 | 
					    "description": "The Solar Network is a social network app.",
 | 
				
			||||||
    "orientation": "portrait-primary",
 | 
					    "orientation": "portrait-primary",
 | 
				
			||||||
    "prefer_related_applications": false,
 | 
					    "prefer_related_applications": false,
 | 
				
			||||||
    "icons": [
 | 
					    "icons": [
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										
											BIN
										
									
								
								web/sqlite3.wasm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								web/sqlite3.wasm
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -23,6 +23,7 @@
 | 
				
			|||||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
 | 
					#include <permission_handler_windows/permission_handler_windows_plugin.h>
 | 
				
			||||||
#include <screen_brightness_windows/screen_brightness_windows_plugin.h>
 | 
					#include <screen_brightness_windows/screen_brightness_windows_plugin.h>
 | 
				
			||||||
#include <share_plus/share_plus_windows_plugin_c_api.h>
 | 
					#include <share_plus/share_plus_windows_plugin_c_api.h>
 | 
				
			||||||
 | 
					#include <sqlite3_flutter_libs/sqlite3_flutter_libs_plugin.h>
 | 
				
			||||||
#include <tray_manager/tray_manager_plugin.h>
 | 
					#include <tray_manager/tray_manager_plugin.h>
 | 
				
			||||||
#include <url_launcher_windows/url_launcher_windows.h>
 | 
					#include <url_launcher_windows/url_launcher_windows.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -61,6 +62,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
 | 
				
			|||||||
      registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin"));
 | 
					      registry->GetRegistrarForPlugin("ScreenBrightnessWindowsPlugin"));
 | 
				
			||||||
  SharePlusWindowsPluginCApiRegisterWithRegistrar(
 | 
					  SharePlusWindowsPluginCApiRegisterWithRegistrar(
 | 
				
			||||||
      registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
 | 
					      registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
 | 
				
			||||||
 | 
					  Sqlite3FlutterLibsPluginRegisterWithRegistrar(
 | 
				
			||||||
 | 
					      registry->GetRegistrarForPlugin("Sqlite3FlutterLibsPlugin"));
 | 
				
			||||||
  TrayManagerPluginRegisterWithRegistrar(
 | 
					  TrayManagerPluginRegisterWithRegistrar(
 | 
				
			||||||
      registry->GetRegistrarForPlugin("TrayManagerPlugin"));
 | 
					      registry->GetRegistrarForPlugin("TrayManagerPlugin"));
 | 
				
			||||||
  UrlLauncherWindowsRegisterWithRegistrar(
 | 
					  UrlLauncherWindowsRegisterWithRegistrar(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,6 +20,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
 | 
				
			|||||||
  permission_handler_windows
 | 
					  permission_handler_windows
 | 
				
			||||||
  screen_brightness_windows
 | 
					  screen_brightness_windows
 | 
				
			||||||
  share_plus
 | 
					  share_plus
 | 
				
			||||||
 | 
					  sqlite3_flutter_libs
 | 
				
			||||||
  tray_manager
 | 
					  tray_manager
 | 
				
			||||||
  url_launcher_windows
 | 
					  url_launcher_windows
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user