♻️ 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
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user