♻️ Refactored the chat loading to use more local data
This commit is contained in:
@@ -358,8 +358,12 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> saveChatRooms(List<SnChatRoom> rooms) async {
|
Future<void> saveChatRooms(
|
||||||
|
List<SnChatRoom> rooms, {
|
||||||
|
bool override = false,
|
||||||
|
}) async {
|
||||||
await transaction(() async {
|
await transaction(() async {
|
||||||
|
if (override) {
|
||||||
// 1. Identify rooms to remove
|
// 1. Identify rooms to remove
|
||||||
final remoteRoomIds = rooms.map((r) => r.id).toSet();
|
final remoteRoomIds = rooms.map((r) => r.id).toSet();
|
||||||
final currentRooms = await select(chatRooms).get();
|
final currentRooms = await select(chatRooms).get();
|
||||||
@@ -369,13 +373,15 @@ class AppDatabase extends _$AppDatabase {
|
|||||||
if (idsToRemove.isNotEmpty) {
|
if (idsToRemove.isNotEmpty) {
|
||||||
final idsList = idsToRemove.toList();
|
final idsList = idsToRemove.toList();
|
||||||
// Remove messages
|
// Remove messages
|
||||||
await (delete(chatMessages)..where((t) => t.roomId.isIn(idsList))).go();
|
await (delete(chatMessages)
|
||||||
|
..where((t) => t.roomId.isIn(idsList))).go();
|
||||||
// Remove members
|
// Remove members
|
||||||
await (delete(chatMembers)
|
await (delete(chatMembers)
|
||||||
..where((t) => t.chatRoomId.isIn(idsList))).go();
|
..where((t) => t.chatRoomId.isIn(idsList))).go();
|
||||||
// Remove rooms
|
// Remove rooms
|
||||||
await (delete(chatRooms)..where((t) => t.id.isIn(idsList))).go();
|
await (delete(chatRooms)..where((t) => t.id.isIn(idsList))).go();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 2. Upsert remote rooms
|
// 2. Upsert remote rooms
|
||||||
await batch((batch) {
|
await batch((batch) {
|
||||||
|
|||||||
@@ -16,10 +16,9 @@ final currentSubscribedChatIdProvider = StateProvider<String?>((ref) => null);
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
||||||
late final String _roomId;
|
late SnChatRoom _chatRoom;
|
||||||
late final SnChatRoom _chatRoom;
|
late SnChatMember _chatIdentity;
|
||||||
late final SnChatMember _chatIdentity;
|
late MessagesNotifier _messagesNotifier;
|
||||||
late final MessagesNotifier _messagesNotifier;
|
|
||||||
|
|
||||||
final List<SnChatMember> _typingStatuses = [];
|
final List<SnChatMember> _typingStatuses = [];
|
||||||
Timer? _typingCleanupTimer;
|
Timer? _typingCleanupTimer;
|
||||||
@@ -29,10 +28,11 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<SnChatMember> build(String roomId) {
|
List<SnChatMember> build(String roomId) {
|
||||||
_roomId = roomId;
|
|
||||||
final ws = ref.watch(websocketProvider);
|
final ws = ref.watch(websocketProvider);
|
||||||
final chatRoomAsync = ref.watch(chatroomProvider(roomId));
|
final chatRoomAsync = ref.watch(ChatRoomNotifierProvider(roomId));
|
||||||
final chatIdentityAsync = ref.watch(chatroomIdentityProvider(roomId));
|
final chatIdentityAsync = ref.watch(
|
||||||
|
ChatRoomIdentityNotifierProvider(roomId),
|
||||||
|
);
|
||||||
_messagesNotifier = ref.watch(messagesNotifierProvider(roomId).notifier);
|
_messagesNotifier = ref.watch(messagesNotifierProvider(roomId).notifier);
|
||||||
|
|
||||||
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
|
||||||
@@ -199,7 +199,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.read',
|
type: 'messages.read',
|
||||||
data: {'chat_room_id': _roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'sphere',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -216,7 +216,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
|
|||||||
jsonEncode(
|
jsonEncode(
|
||||||
WebSocketPacket(
|
WebSocketPacket(
|
||||||
type: 'messages.typing',
|
type: 'messages.typing',
|
||||||
data: {'chat_room_id': _roomId},
|
data: {'chat_room_id': roomId},
|
||||||
endpoint: 'sphere',
|
endpoint: 'sphere',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'chat_subscribe.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$chatSubscribeNotifierHash() =>
|
String _$chatSubscribeNotifierHash() =>
|
||||||
r'c605e0c9c45df64e5ba7b65f8de9b47bde8e2b3b';
|
r'beec1ddf2e13f6d5af8a08c2c81eff740ae9b986';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ part 'messages_notifier.g.dart';
|
|||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
class MessagesNotifier extends _$MessagesNotifier {
|
class MessagesNotifier extends _$MessagesNotifier {
|
||||||
late final Dio _apiClient;
|
late Dio _apiClient;
|
||||||
late final AppDatabase _database;
|
late AppDatabase _database;
|
||||||
late final SnChatRoom _room;
|
late SnChatRoom _room;
|
||||||
late final SnChatMember _identity;
|
late SnChatMember _identity;
|
||||||
|
|
||||||
final Map<String, LocalChatMessage> _pendingMessages = {};
|
final Map<String, LocalChatMessage> _pendingMessages = {};
|
||||||
final Map<String, Map<int, double?>> _fileUploadProgress = {};
|
final Map<String, Map<int, double?>> _fileUploadProgress = {};
|
||||||
@@ -39,7 +39,6 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
bool? _withLinks;
|
bool? _withLinks;
|
||||||
bool? _withAttachments;
|
bool? _withAttachments;
|
||||||
|
|
||||||
late final String _roomId;
|
|
||||||
static const int _pageSize = 20;
|
static const int _pageSize = 20;
|
||||||
bool _hasMore = true;
|
bool _hasMore = true;
|
||||||
bool _isSyncing = false;
|
bool _isSyncing = false;
|
||||||
@@ -48,15 +47,16 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
bool _allRemoteMessagesFetched = false;
|
bool _allRemoteMessagesFetched = false;
|
||||||
DateTime? _lastPauseTime;
|
DateTime? _lastPauseTime;
|
||||||
|
|
||||||
late final Future<SnAccount?> Function(String) _fetchAccount;
|
late Future<SnAccount?> Function(String) _fetchAccount;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FutureOr<List<LocalChatMessage>> build(String roomId) async {
|
FutureOr<List<LocalChatMessage>> build(String roomId) async {
|
||||||
_roomId = roomId;
|
|
||||||
_apiClient = ref.watch(apiClientProvider);
|
_apiClient = ref.watch(apiClientProvider);
|
||||||
_database = ref.watch(databaseProvider);
|
_database = ref.watch(databaseProvider);
|
||||||
final room = await ref.watch(chatroomProvider(roomId).future);
|
final room = await ref.watch(ChatRoomNotifierProvider(roomId).future);
|
||||||
final identity = await ref.watch(chatroomIdentityProvider(roomId).future);
|
final identity = await ref.watch(
|
||||||
|
ChatRoomIdentityNotifierProvider(roomId).future,
|
||||||
|
);
|
||||||
|
|
||||||
// Initialize fetch account method for corrupted data recovery
|
// Initialize fetch account method for corrupted data recovery
|
||||||
_fetchAccount = (String accountId) async {
|
_fetchAccount = (String accountId) async {
|
||||||
@@ -144,14 +144,14 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
if (searchQuery != null && searchQuery.isNotEmpty) {
|
if (searchQuery != null && searchQuery.isNotEmpty) {
|
||||||
dbMessages = await _database.searchMessages(
|
dbMessages = await _database.searchMessages(
|
||||||
_roomId,
|
roomId,
|
||||||
searchQuery,
|
searchQuery,
|
||||||
withAttachments: withAttachments,
|
withAttachments: withAttachments,
|
||||||
fetchAccount: _fetchAccount,
|
fetchAccount: _fetchAccount,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
||||||
_roomId,
|
roomId,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: take,
|
limit: take,
|
||||||
);
|
);
|
||||||
@@ -194,9 +194,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom =
|
||||||
_pendingMessages.values
|
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||||
.where((msg) => msg.roomId == _roomId)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||||
_sortMessages(allMessages); // Use the helper function
|
_sortMessages(allMessages); // Use the helper function
|
||||||
@@ -221,7 +219,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}) async {
|
}) async {
|
||||||
talker.log('Getting all messages for jump from offset $offset, take $take');
|
talker.log('Getting all messages for jump from offset $offset, take $take');
|
||||||
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
final chatMessagesFromDb = await _database.getMessagesForRoom(
|
||||||
_roomId,
|
roomId,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
limit: take,
|
limit: take,
|
||||||
);
|
);
|
||||||
@@ -245,9 +243,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
final pendingForRoom =
|
final pendingForRoom =
|
||||||
_pendingMessages.values
|
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
|
||||||
.where((msg) => msg.roomId == _roomId)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
final allMessages = [...pendingForRoom, ...uniqueMessages];
|
||||||
_sortMessages(allMessages);
|
_sortMessages(allMessages);
|
||||||
@@ -272,7 +268,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
talker.log('Fetching messages from API, offset $offset, take $take');
|
talker.log('Fetching messages from API, offset $offset, take $take');
|
||||||
if (_totalCount == null) {
|
if (_totalCount == null) {
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$_roomId/messages',
|
'/sphere/chat/$roomId/messages',
|
||||||
queryParameters: {'offset': 0, 'take': 1},
|
queryParameters: {'offset': 0, 'take': 1},
|
||||||
);
|
);
|
||||||
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
|
||||||
@@ -284,7 +280,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$_roomId/messages',
|
'/sphere/chat/$roomId/messages',
|
||||||
queryParameters: {'offset': offset, 'take': take},
|
queryParameters: {'offset': offset, 'take': take},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -546,7 +542,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
final mockMessage = SnChatMessage(
|
final mockMessage = SnChatMessage(
|
||||||
id: 'pending_$nonce',
|
id: 'pending_$nonce',
|
||||||
chatRoomId: _roomId,
|
chatRoomId: roomId,
|
||||||
senderId: _identity.id,
|
senderId: _identity.id,
|
||||||
content: content,
|
content: content,
|
||||||
createdAt: DateTime.now(),
|
createdAt: DateTime.now(),
|
||||||
@@ -590,8 +586,8 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
|
|
||||||
final response = await _apiClient.request(
|
final response = await _apiClient.request(
|
||||||
editingTo == null
|
editingTo == null
|
||||||
? '/sphere/chat/$_roomId/messages'
|
? '/sphere/chat/$roomId/messages'
|
||||||
: '/sphere/chat/$_roomId/messages/${editingTo.id}',
|
: '/sphere/chat/$roomId/messages/${editingTo.id}',
|
||||||
data: {
|
data: {
|
||||||
'content': content,
|
'content': content,
|
||||||
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
|
||||||
@@ -731,7 +727,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> receiveMessage(SnChatMessage remoteMessage) async {
|
Future<void> receiveMessage(SnChatMessage remoteMessage) async {
|
||||||
if (remoteMessage.chatRoomId != _roomId) return;
|
if (remoteMessage.chatRoomId != roomId) return;
|
||||||
|
|
||||||
// Block message receiving during jumps to prevent list resets
|
// Block message receiving during jumps to prevent list resets
|
||||||
if (_isJumping) {
|
if (_isJumping) {
|
||||||
@@ -783,7 +779,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> receiveMessageUpdate(SnChatMessage remoteMessage) async {
|
Future<void> receiveMessageUpdate(SnChatMessage remoteMessage) async {
|
||||||
if (remoteMessage.chatRoomId != _roomId) return;
|
if (remoteMessage.chatRoomId != roomId) return;
|
||||||
|
|
||||||
// Block message updates during jumps to prevent list resets
|
// Block message updates during jumps to prevent list resets
|
||||||
if (_isJumping) {
|
if (_isJumping) {
|
||||||
@@ -883,7 +879,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await _apiClient.delete('/sphere/chat/$_roomId/messages/$messageId');
|
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId');
|
||||||
await receiveMessageDeletion(messageId);
|
await receiveMessageDeletion(messageId);
|
||||||
} catch (err, stackTrace) {
|
} catch (err, stackTrace) {
|
||||||
talker.log(
|
talker.log(
|
||||||
@@ -991,7 +987,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final response = await _apiClient.get(
|
final response = await _apiClient.get(
|
||||||
'/sphere/chat/$_roomId/messages/$messageId',
|
'/sphere/chat/$roomId/messages/$messageId',
|
||||||
);
|
);
|
||||||
final remoteMessage = SnChatMessage.fromJson(response.data);
|
final remoteMessage = SnChatMessage.fromJson(response.data);
|
||||||
final message = LocalChatMessage.fromRemoteMessage(
|
final message = LocalChatMessage.fromRemoteMessage(
|
||||||
@@ -1048,7 +1044,7 @@ class MessagesNotifier extends _$MessagesNotifier {
|
|||||||
final query = _database.customSelect(
|
final query = _database.customSelect(
|
||||||
'SELECT COUNT(*) as count FROM chat_messages WHERE room_id = ? AND created_at > ?',
|
'SELECT COUNT(*) as count FROM chat_messages WHERE room_id = ? AND created_at > ?',
|
||||||
variables: [
|
variables: [
|
||||||
Variable.withString(_roomId),
|
Variable.withString(roomId),
|
||||||
Variable.withDateTime(message.createdAt),
|
Variable.withDateTime(message.createdAt),
|
||||||
],
|
],
|
||||||
readsFrom: {_database.chatMessages},
|
readsFrom: {_database.chatMessages},
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ part of 'messages_notifier.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$messagesNotifierHash() => r'27ce32c54e317a04e1d554ed4a70a24e4503fdd1';
|
String _$messagesNotifierHash() => r'd76d799494b06fac2adc42d94b7ecd7b8d68c352';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|||||||
import 'package:island/models/chat.dart';
|
import 'package:island/models/chat.dart';
|
||||||
import 'package:island/models/file.dart';
|
import 'package:island/models/file.dart';
|
||||||
import 'package:island/models/account.dart';
|
import 'package:island/models/account.dart';
|
||||||
|
import 'package:island/database/drift_db.dart';
|
||||||
import 'package:island/pods/database.dart';
|
import 'package:island/pods/database.dart';
|
||||||
import 'package:island/pods/chat/chat_summary.dart';
|
import 'package:island/pods/chat/chat_summary.dart';
|
||||||
import 'package:island/pods/network.dart';
|
import 'package:island/pods/network.dart';
|
||||||
@@ -184,13 +185,100 @@ class ChatRoomListTile extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<List<SnChatRoom>> chatroomsJoined(Ref ref) async {
|
class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
|
||||||
|
@override
|
||||||
|
Future<List<SnChatRoom>> build() async {
|
||||||
final db = ref.watch(databaseProvider);
|
final db = ref.watch(databaseProvider);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final localRoomsData = await db.select(db.chatRooms).get();
|
final localRoomsData = await db.select(db.chatRooms).get();
|
||||||
if (localRoomsData.isNotEmpty) {
|
if (localRoomsData.isNotEmpty) {
|
||||||
final localRooms = await Future.wait(
|
final localRooms = await Future.wait(
|
||||||
|
localRoomsData.map((row) async {
|
||||||
|
final membersRows =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(row.id))).get();
|
||||||
|
final members =
|
||||||
|
membersRows.map((mRow) {
|
||||||
|
final account = SnAccount.fromJson(mRow.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: mRow.id,
|
||||||
|
chatRoomId: mRow.chatRoomId,
|
||||||
|
accountId: mRow.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: mRow.nick,
|
||||||
|
notify: mRow.notify,
|
||||||
|
joinedAt: mRow.joinedAt,
|
||||||
|
breakUntil: mRow.breakUntil,
|
||||||
|
timeoutUntil: mRow.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: mRow.createdAt,
|
||||||
|
updatedAt: mRow.updatedAt,
|
||||||
|
deletedAt: mRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
return SnChatRoom(
|
||||||
|
id: row.id,
|
||||||
|
name: row.name,
|
||||||
|
description: row.description,
|
||||||
|
type: row.type,
|
||||||
|
isPublic: row.isPublic!,
|
||||||
|
isCommunity: row.isCommunity!,
|
||||||
|
picture:
|
||||||
|
row.picture != null
|
||||||
|
? SnCloudFile.fromJson(row.picture!)
|
||||||
|
: null,
|
||||||
|
background:
|
||||||
|
row.background != null
|
||||||
|
? SnCloudFile.fromJson(row.background!)
|
||||||
|
: null,
|
||||||
|
realmId: row.realmId,
|
||||||
|
accountId: row.accountId,
|
||||||
|
realm: null,
|
||||||
|
createdAt: row.createdAt,
|
||||||
|
updatedAt: row.updatedAt,
|
||||||
|
deletedAt: row.deletedAt,
|
||||||
|
members: members,
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Background sync
|
||||||
|
Future(() async {
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat');
|
||||||
|
final remoteRooms =
|
||||||
|
resp.data
|
||||||
|
.map((e) => SnChatRoom.fromJson(e))
|
||||||
|
.cast<SnChatRoom>()
|
||||||
|
.toList();
|
||||||
|
await db.saveChatRooms(remoteRooms, override: true);
|
||||||
|
// Update state with fresh data
|
||||||
|
state = AsyncData(await _buildRoomsFromDb(db));
|
||||||
|
} catch (_) {}
|
||||||
|
}).ignore();
|
||||||
|
|
||||||
|
return localRooms;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback to API
|
||||||
|
final client = ref.watch(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat');
|
||||||
|
final rooms =
|
||||||
|
resp.data
|
||||||
|
.map((e) => SnChatRoom.fromJson(e))
|
||||||
|
.cast<SnChatRoom>()
|
||||||
|
.toList();
|
||||||
|
await db.saveChatRooms(rooms, override: true);
|
||||||
|
return rooms;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<SnChatRoom>> _buildRoomsFromDb(AppDatabase db) async {
|
||||||
|
final localRoomsData = await db.select(db.chatRooms).get();
|
||||||
|
return Future.wait(
|
||||||
localRoomsData.map((row) async {
|
localRoomsData.map((row) async {
|
||||||
final membersRows =
|
final membersRows =
|
||||||
await (db.select(db.chatMembers)
|
await (db.select(db.chatMembers)
|
||||||
@@ -238,33 +326,7 @@ Future<List<SnChatRoom>> chatroomsJoined(Ref ref) async {
|
|||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Background sync
|
|
||||||
Future(() async {
|
|
||||||
try {
|
|
||||||
final client = ref.read(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat');
|
|
||||||
final remoteRooms =
|
|
||||||
resp.data
|
|
||||||
.map((e) => SnChatRoom.fromJson(e))
|
|
||||||
.cast<SnChatRoom>()
|
|
||||||
.toList();
|
|
||||||
await db.saveChatRooms(remoteRooms);
|
|
||||||
ref.invalidateSelf();
|
|
||||||
} catch (_) {}
|
|
||||||
}).ignore();
|
|
||||||
|
|
||||||
return localRooms;
|
|
||||||
}
|
}
|
||||||
} catch (_) {}
|
|
||||||
|
|
||||||
// Fallback to API
|
|
||||||
final client = ref.watch(apiClientProvider);
|
|
||||||
final resp = await client.get('/sphere/chat');
|
|
||||||
final rooms =
|
|
||||||
resp.data.map((e) => SnChatRoom.fromJson(e)).cast<SnChatRoom>().toList();
|
|
||||||
await db.saveChatRooms(rooms);
|
|
||||||
return rooms;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ChatListBodyWidget extends HookConsumerWidget {
|
class ChatListBodyWidget extends HookConsumerWidget {
|
||||||
@@ -281,7 +343,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chats = ref.watch(chatroomsJoinedProvider);
|
final chats = ref.watch(chatRoomJoinedNotifierProvider);
|
||||||
|
|
||||||
Widget bodyWidget = Column(
|
Widget bodyWidget = Column(
|
||||||
children: [
|
children: [
|
||||||
@@ -304,7 +366,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
|||||||
(items) => RefreshIndicator(
|
(items) => RefreshIndicator(
|
||||||
onRefresh:
|
onRefresh:
|
||||||
() => Future.sync(() {
|
() => Future.sync(() {
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
}),
|
}),
|
||||||
child: SuperListView.builder(
|
child: SuperListView.builder(
|
||||||
padding: EdgeInsets.only(bottom: 96),
|
padding: EdgeInsets.only(bottom: 96),
|
||||||
@@ -354,7 +416,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
|
|||||||
(error, stack) => ResponseErrorWidget(
|
(error, stack) => ResponseErrorWidget(
|
||||||
error: error,
|
error: error,
|
||||||
onRetry: () {
|
onRetry: () {
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -431,7 +493,7 @@ class ChatListScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
// Listen for chat rooms refresh events
|
// Listen for chat rooms refresh events
|
||||||
final subscription = eventBus.on<ChatRoomsRefreshEvent>().listen((event) {
|
final subscription = eventBus.on<ChatRoomsRefreshEvent>().listen((event) {
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () {
|
return () {
|
||||||
@@ -600,33 +662,264 @@ class ChatListScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<SnChatRoom?> chatroom(Ref ref, String? identifier) async {
|
class ChatRoomNotifier extends _$ChatRoomNotifier {
|
||||||
|
@override
|
||||||
|
Future<SnChatRoom?> build(String? identifier) async {
|
||||||
if (identifier == null) return null;
|
if (identifier == null) return null;
|
||||||
|
final db = ref.watch(databaseProvider);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to get from local database first
|
||||||
|
final localRoomData =
|
||||||
|
await (db.select(db.chatRooms)
|
||||||
|
..where((r) => r.id.equals(identifier))).getSingleOrNull();
|
||||||
|
|
||||||
|
if (localRoomData != null) {
|
||||||
|
// Fetch members for this room
|
||||||
|
final membersRows =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(localRoomData.id))).get();
|
||||||
|
final members =
|
||||||
|
membersRows.map((mRow) {
|
||||||
|
final account = SnAccount.fromJson(mRow.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: mRow.id,
|
||||||
|
chatRoomId: mRow.chatRoomId,
|
||||||
|
accountId: mRow.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: mRow.nick,
|
||||||
|
notify: mRow.notify,
|
||||||
|
joinedAt: mRow.joinedAt,
|
||||||
|
breakUntil: mRow.breakUntil,
|
||||||
|
timeoutUntil: mRow.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: mRow.createdAt,
|
||||||
|
updatedAt: mRow.updatedAt,
|
||||||
|
deletedAt: mRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
final localRoom = SnChatRoom(
|
||||||
|
id: localRoomData.id,
|
||||||
|
name: localRoomData.name,
|
||||||
|
description: localRoomData.description,
|
||||||
|
type: localRoomData.type,
|
||||||
|
isPublic: localRoomData.isPublic!,
|
||||||
|
isCommunity: localRoomData.isCommunity!,
|
||||||
|
picture:
|
||||||
|
localRoomData.picture != null
|
||||||
|
? SnCloudFile.fromJson(localRoomData.picture!)
|
||||||
|
: null,
|
||||||
|
background:
|
||||||
|
localRoomData.background != null
|
||||||
|
? SnCloudFile.fromJson(localRoomData.background!)
|
||||||
|
: null,
|
||||||
|
realmId: localRoomData.realmId,
|
||||||
|
accountId: localRoomData.accountId,
|
||||||
|
realm: null,
|
||||||
|
createdAt: localRoomData.createdAt,
|
||||||
|
updatedAt: localRoomData.updatedAt,
|
||||||
|
deletedAt: localRoomData.deletedAt,
|
||||||
|
members: members,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Background sync
|
||||||
|
Future(() async {
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.get('/sphere/chat/$identifier');
|
||||||
|
final remoteRoom = SnChatRoom.fromJson(resp.data);
|
||||||
|
await db.saveChatRooms([remoteRoom]);
|
||||||
|
// Update state with fresh data
|
||||||
|
state = AsyncData(await _buildRoomFromDb(db, identifier));
|
||||||
|
} catch (_) {}
|
||||||
|
}).ignore();
|
||||||
|
|
||||||
|
return localRoom;
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback to API
|
||||||
try {
|
try {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/$identifier');
|
final resp = await client.get('/sphere/chat/$identifier');
|
||||||
return SnChatRoom.fromJson(resp.data);
|
final room = SnChatRoom.fromJson(resp.data);
|
||||||
|
await db.saveChatRooms([room]);
|
||||||
|
return room;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is DioException && err.response?.statusCode == 404) {
|
if (err is DioException && err.response?.statusCode == 404) {
|
||||||
return null; // Chat room not found
|
return null; // Chat room not found
|
||||||
}
|
}
|
||||||
rethrow; // Rethrow other errors
|
rethrow; // Rethrow other errors
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SnChatRoom?> _buildRoomFromDb(
|
||||||
|
AppDatabase db,
|
||||||
|
String identifier,
|
||||||
|
) async {
|
||||||
|
final localRoomData =
|
||||||
|
await (db.select(db.chatRooms)
|
||||||
|
..where((r) => r.id.equals(identifier))).getSingleOrNull();
|
||||||
|
|
||||||
|
if (localRoomData == null) return null;
|
||||||
|
|
||||||
|
final membersRows =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(localRoomData.id))).get();
|
||||||
|
final members =
|
||||||
|
membersRows.map((mRow) {
|
||||||
|
final account = SnAccount.fromJson(mRow.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: mRow.id,
|
||||||
|
chatRoomId: mRow.chatRoomId,
|
||||||
|
accountId: mRow.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: mRow.nick,
|
||||||
|
notify: mRow.notify,
|
||||||
|
joinedAt: mRow.joinedAt,
|
||||||
|
breakUntil: mRow.breakUntil,
|
||||||
|
timeoutUntil: mRow.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: mRow.createdAt,
|
||||||
|
updatedAt: mRow.updatedAt,
|
||||||
|
deletedAt: mRow.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
|
||||||
|
return SnChatRoom(
|
||||||
|
id: localRoomData.id,
|
||||||
|
name: localRoomData.name,
|
||||||
|
description: localRoomData.description,
|
||||||
|
type: localRoomData.type,
|
||||||
|
isPublic: localRoomData.isPublic!,
|
||||||
|
isCommunity: localRoomData.isCommunity!,
|
||||||
|
picture:
|
||||||
|
localRoomData.picture != null
|
||||||
|
? SnCloudFile.fromJson(localRoomData.picture!)
|
||||||
|
: null,
|
||||||
|
background:
|
||||||
|
localRoomData.background != null
|
||||||
|
? SnCloudFile.fromJson(localRoomData.background!)
|
||||||
|
: null,
|
||||||
|
realmId: localRoomData.realmId,
|
||||||
|
accountId: localRoomData.accountId,
|
||||||
|
realm: null,
|
||||||
|
createdAt: localRoomData.createdAt,
|
||||||
|
updatedAt: localRoomData.updatedAt,
|
||||||
|
deletedAt: localRoomData.deletedAt,
|
||||||
|
members: members,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
Future<SnChatMember?> chatroomIdentity(Ref ref, String? identifier) async {
|
class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
|
||||||
|
@override
|
||||||
|
Future<SnChatMember?> build(String? identifier) async {
|
||||||
if (identifier == null) return null;
|
if (identifier == null) return null;
|
||||||
|
final db = ref.watch(databaseProvider);
|
||||||
|
final userInfo = ref.watch(userInfoProvider);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Try to get from local database first
|
||||||
|
if (userInfo.value != null) {
|
||||||
|
final localMemberData =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(identifier))
|
||||||
|
..where((m) => m.accountId.equals(userInfo.value!.id)))
|
||||||
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (localMemberData != null) {
|
||||||
|
final account = SnAccount.fromJson(localMemberData.account);
|
||||||
|
final localMember = SnChatMember(
|
||||||
|
id: localMemberData.id,
|
||||||
|
chatRoomId: localMemberData.chatRoomId,
|
||||||
|
accountId: localMemberData.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: localMemberData.nick,
|
||||||
|
notify: localMemberData.notify,
|
||||||
|
joinedAt: localMemberData.joinedAt,
|
||||||
|
breakUntil: localMemberData.breakUntil,
|
||||||
|
timeoutUntil: localMemberData.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: localMemberData.createdAt,
|
||||||
|
updatedAt: localMemberData.updatedAt,
|
||||||
|
deletedAt: localMemberData.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Background sync
|
||||||
|
Future(() async {
|
||||||
|
try {
|
||||||
|
final client = ref.read(apiClientProvider);
|
||||||
|
final resp = await client.get(
|
||||||
|
'/sphere/chat/$identifier/members/me',
|
||||||
|
);
|
||||||
|
final remoteMember = SnChatMember.fromJson(resp.data);
|
||||||
|
await db.saveMember(remoteMember);
|
||||||
|
// Update state with fresh data
|
||||||
|
if (userInfo.value != null) {
|
||||||
|
state = AsyncData(
|
||||||
|
await _buildMemberFromDb(db, identifier, userInfo.value!.id),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
}).ignore();
|
||||||
|
|
||||||
|
return localMember;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
|
// Fallback to API
|
||||||
try {
|
try {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
final resp = await client.get('/sphere/chat/$identifier/members/me');
|
final resp = await client.get('/sphere/chat/$identifier/members/me');
|
||||||
return SnChatMember.fromJson(resp.data);
|
final member = SnChatMember.fromJson(resp.data);
|
||||||
|
await db.saveMember(member);
|
||||||
|
return member;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err is DioException && err.response?.statusCode == 404) {
|
if (err is DioException && err.response?.statusCode == 404) {
|
||||||
return null; // Chat member not found
|
return null; // Chat member not found
|
||||||
}
|
}
|
||||||
rethrow; // Rethrow other errors
|
rethrow; // Rethrow other errors
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<SnChatMember?> _buildMemberFromDb(
|
||||||
|
AppDatabase db,
|
||||||
|
String identifier,
|
||||||
|
String accountId,
|
||||||
|
) async {
|
||||||
|
final localMemberData =
|
||||||
|
await (db.select(db.chatMembers)
|
||||||
|
..where((m) => m.chatRoomId.equals(identifier))
|
||||||
|
..where((m) => m.accountId.equals(accountId)))
|
||||||
|
.getSingleOrNull();
|
||||||
|
|
||||||
|
if (localMemberData == null) return null;
|
||||||
|
|
||||||
|
final account = SnAccount.fromJson(localMemberData.account);
|
||||||
|
return SnChatMember(
|
||||||
|
id: localMemberData.id,
|
||||||
|
chatRoomId: localMemberData.chatRoomId,
|
||||||
|
accountId: localMemberData.accountId,
|
||||||
|
account: account,
|
||||||
|
nick: localMemberData.nick,
|
||||||
|
notify: localMemberData.notify,
|
||||||
|
joinedAt: localMemberData.joinedAt,
|
||||||
|
breakUntil: localMemberData.breakUntil,
|
||||||
|
timeoutUntil: localMemberData.timeoutUntil,
|
||||||
|
status: null,
|
||||||
|
createdAt: localMemberData.createdAt,
|
||||||
|
updatedAt: localMemberData.updatedAt,
|
||||||
|
deletedAt: localMemberData.deletedAt,
|
||||||
|
chatRoom: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
@@ -651,7 +944,7 @@ class _ChatInvitesSheet extends HookConsumerWidget {
|
|||||||
final client = ref.read(apiClientProvider);
|
final client = ref.read(apiClientProvider);
|
||||||
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
|
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
|
||||||
ref.invalidate(chatroomInvitesProvider);
|
ref.invalidate(chatroomInvitesProvider);
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,26 +6,46 @@ part of 'chat.dart';
|
|||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$chatroomsJoinedHash() => r'50abce4f03a7a8509f16d5ad0b1dbf8e3aeb73b6';
|
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
|
||||||
|
|
||||||
/// See also [chatroomsJoined].
|
/// See also [chatroomInvites].
|
||||||
@ProviderFor(chatroomsJoined)
|
@ProviderFor(chatroomInvites)
|
||||||
final chatroomsJoinedProvider =
|
final chatroomInvitesProvider =
|
||||||
AutoDisposeFutureProvider<List<SnChatRoom>>.internal(
|
AutoDisposeFutureProvider<List<SnChatMember>>.internal(
|
||||||
chatroomsJoined,
|
chatroomInvites,
|
||||||
name: r'chatroomsJoinedProvider',
|
name: r'chatroomInvitesProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$chatroomsJoinedHash,
|
: _$chatroomInvitesHash,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
);
|
);
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef ChatroomsJoinedRef = AutoDisposeFutureProviderRef<List<SnChatRoom>>;
|
typedef ChatroomInvitesRef = AutoDisposeFutureProviderRef<List<SnChatMember>>;
|
||||||
String _$chatroomHash() => r'2b17d94728026420d18d6c383d2400cf4a070913';
|
String _$chatRoomJoinedNotifierHash() =>
|
||||||
|
r'c8092225ba0d9c08b2b5bca6f800f1877303b4ff';
|
||||||
|
|
||||||
|
/// See also [ChatRoomJoinedNotifier].
|
||||||
|
@ProviderFor(ChatRoomJoinedNotifier)
|
||||||
|
final chatRoomJoinedNotifierProvider = AutoDisposeAsyncNotifierProvider<
|
||||||
|
ChatRoomJoinedNotifier,
|
||||||
|
List<SnChatRoom>
|
||||||
|
>.internal(
|
||||||
|
ChatRoomJoinedNotifier.new,
|
||||||
|
name: r'chatRoomJoinedNotifierProvider',
|
||||||
|
debugGetCreateSourceHash:
|
||||||
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
|
? null
|
||||||
|
: _$chatRoomJoinedNotifierHash,
|
||||||
|
dependencies: null,
|
||||||
|
allTransitiveDependencies: null,
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef _$ChatRoomJoinedNotifier = AutoDisposeAsyncNotifier<List<SnChatRoom>>;
|
||||||
|
String _$chatRoomNotifierHash() => r'978bd602cf5e93e60e3c7b9f5799d46a87495c79';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
@@ -48,141 +68,30 @@ class _SystemHash {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [chatroom].
|
abstract class _$ChatRoomNotifier
|
||||||
@ProviderFor(chatroom)
|
extends BuildlessAutoDisposeAsyncNotifier<SnChatRoom?> {
|
||||||
const chatroomProvider = ChatroomFamily();
|
late final String? identifier;
|
||||||
|
|
||||||
/// See also [chatroom].
|
FutureOr<SnChatRoom?> build(String? identifier);
|
||||||
class ChatroomFamily extends Family<AsyncValue<SnChatRoom?>> {
|
|
||||||
/// See also [chatroom].
|
|
||||||
const ChatroomFamily();
|
|
||||||
|
|
||||||
/// See also [chatroom].
|
|
||||||
ChatroomProvider call(String? identifier) {
|
|
||||||
return ChatroomProvider(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ChatroomProvider getProviderOverride(covariant ChatroomProvider provider) {
|
|
||||||
return call(provider.identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
|
||||||
|
|
||||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
|
||||||
_allTransitiveDependencies;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get name => r'chatroomProvider';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [chatroom].
|
/// See also [ChatRoomNotifier].
|
||||||
class ChatroomProvider extends AutoDisposeFutureProvider<SnChatRoom?> {
|
@ProviderFor(ChatRoomNotifier)
|
||||||
/// See also [chatroom].
|
const chatRoomNotifierProvider = ChatRoomNotifierFamily();
|
||||||
ChatroomProvider(String? identifier)
|
|
||||||
: this._internal(
|
|
||||||
(ref) => chatroom(ref as ChatroomRef, identifier),
|
|
||||||
from: chatroomProvider,
|
|
||||||
name: r'chatroomProvider',
|
|
||||||
debugGetCreateSourceHash:
|
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
|
||||||
? null
|
|
||||||
: _$chatroomHash,
|
|
||||||
dependencies: ChatroomFamily._dependencies,
|
|
||||||
allTransitiveDependencies: ChatroomFamily._allTransitiveDependencies,
|
|
||||||
identifier: identifier,
|
|
||||||
);
|
|
||||||
|
|
||||||
ChatroomProvider._internal(
|
/// See also [ChatRoomNotifier].
|
||||||
super._createNotifier, {
|
class ChatRoomNotifierFamily extends Family<AsyncValue<SnChatRoom?>> {
|
||||||
required super.name,
|
/// See also [ChatRoomNotifier].
|
||||||
required super.dependencies,
|
const ChatRoomNotifierFamily();
|
||||||
required super.allTransitiveDependencies,
|
|
||||||
required super.debugGetCreateSourceHash,
|
|
||||||
required super.from,
|
|
||||||
required this.identifier,
|
|
||||||
}) : super.internal();
|
|
||||||
|
|
||||||
final String? identifier;
|
/// See also [ChatRoomNotifier].
|
||||||
|
ChatRoomNotifierProvider call(String? identifier) {
|
||||||
@override
|
return ChatRoomNotifierProvider(identifier);
|
||||||
Override overrideWith(
|
|
||||||
FutureOr<SnChatRoom?> Function(ChatroomRef provider) create,
|
|
||||||
) {
|
|
||||||
return ProviderOverride(
|
|
||||||
origin: this,
|
|
||||||
override: ChatroomProvider._internal(
|
|
||||||
(ref) => create(ref as ChatroomRef),
|
|
||||||
from: from,
|
|
||||||
name: null,
|
|
||||||
dependencies: null,
|
|
||||||
allTransitiveDependencies: null,
|
|
||||||
debugGetCreateSourceHash: null,
|
|
||||||
identifier: identifier,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AutoDisposeFutureProviderElement<SnChatRoom?> createElement() {
|
ChatRoomNotifierProvider getProviderOverride(
|
||||||
return _ChatroomProviderElement(this);
|
covariant ChatRoomNotifierProvider provider,
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(Object other) {
|
|
||||||
return other is ChatroomProvider && other.identifier == identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode {
|
|
||||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
|
||||||
hash = _SystemHash.combine(hash, identifier.hashCode);
|
|
||||||
|
|
||||||
return _SystemHash.finish(hash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
|
||||||
// ignore: unused_element
|
|
||||||
mixin ChatroomRef on AutoDisposeFutureProviderRef<SnChatRoom?> {
|
|
||||||
/// The parameter `identifier` of this provider.
|
|
||||||
String? get identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
class _ChatroomProviderElement
|
|
||||||
extends AutoDisposeFutureProviderElement<SnChatRoom?>
|
|
||||||
with ChatroomRef {
|
|
||||||
_ChatroomProviderElement(super.provider);
|
|
||||||
|
|
||||||
@override
|
|
||||||
String? get identifier => (origin as ChatroomProvider).identifier;
|
|
||||||
}
|
|
||||||
|
|
||||||
String _$chatroomIdentityHash() => r'35e19a5a3e31752c79b97ba0358a7ec8fb8f6e99';
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
@ProviderFor(chatroomIdentity)
|
|
||||||
const chatroomIdentityProvider = ChatroomIdentityFamily();
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
class ChatroomIdentityFamily extends Family<AsyncValue<SnChatMember?>> {
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
const ChatroomIdentityFamily();
|
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
|
||||||
ChatroomIdentityProvider call(String? identifier) {
|
|
||||||
return ChatroomIdentityProvider(identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
ChatroomIdentityProvider getProviderOverride(
|
|
||||||
covariant ChatroomIdentityProvider provider,
|
|
||||||
) {
|
) {
|
||||||
return call(provider.identifier);
|
return call(provider.identifier);
|
||||||
}
|
}
|
||||||
@@ -199,29 +108,30 @@ class ChatroomIdentityFamily extends Family<AsyncValue<SnChatMember?>> {
|
|||||||
_allTransitiveDependencies;
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get name => r'chatroomIdentityProvider';
|
String? get name => r'chatRoomNotifierProvider';
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [chatroomIdentity].
|
/// See also [ChatRoomNotifier].
|
||||||
class ChatroomIdentityProvider
|
class ChatRoomNotifierProvider
|
||||||
extends AutoDisposeFutureProvider<SnChatMember?> {
|
extends
|
||||||
/// See also [chatroomIdentity].
|
AutoDisposeAsyncNotifierProviderImpl<ChatRoomNotifier, SnChatRoom?> {
|
||||||
ChatroomIdentityProvider(String? identifier)
|
/// See also [ChatRoomNotifier].
|
||||||
|
ChatRoomNotifierProvider(String? identifier)
|
||||||
: this._internal(
|
: this._internal(
|
||||||
(ref) => chatroomIdentity(ref as ChatroomIdentityRef, identifier),
|
() => ChatRoomNotifier()..identifier = identifier,
|
||||||
from: chatroomIdentityProvider,
|
from: chatRoomNotifierProvider,
|
||||||
name: r'chatroomIdentityProvider',
|
name: r'chatRoomNotifierProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$chatroomIdentityHash,
|
: _$chatRoomNotifierHash,
|
||||||
dependencies: ChatroomIdentityFamily._dependencies,
|
dependencies: ChatRoomNotifierFamily._dependencies,
|
||||||
allTransitiveDependencies:
|
allTransitiveDependencies:
|
||||||
ChatroomIdentityFamily._allTransitiveDependencies,
|
ChatRoomNotifierFamily._allTransitiveDependencies,
|
||||||
identifier: identifier,
|
identifier: identifier,
|
||||||
);
|
);
|
||||||
|
|
||||||
ChatroomIdentityProvider._internal(
|
ChatRoomNotifierProvider._internal(
|
||||||
super._createNotifier, {
|
super._createNotifier, {
|
||||||
required super.name,
|
required super.name,
|
||||||
required super.dependencies,
|
required super.dependencies,
|
||||||
@@ -234,13 +144,16 @@ class ChatroomIdentityProvider
|
|||||||
final String? identifier;
|
final String? identifier;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Override overrideWith(
|
FutureOr<SnChatRoom?> runNotifierBuild(covariant ChatRoomNotifier notifier) {
|
||||||
FutureOr<SnChatMember?> Function(ChatroomIdentityRef provider) create,
|
return notifier.build(identifier);
|
||||||
) {
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(ChatRoomNotifier Function() create) {
|
||||||
return ProviderOverride(
|
return ProviderOverride(
|
||||||
origin: this,
|
origin: this,
|
||||||
override: ChatroomIdentityProvider._internal(
|
override: ChatRoomNotifierProvider._internal(
|
||||||
(ref) => create(ref as ChatroomIdentityRef),
|
() => create()..identifier = identifier,
|
||||||
from: from,
|
from: from,
|
||||||
name: null,
|
name: null,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
@@ -252,13 +165,14 @@ class ChatroomIdentityProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
AutoDisposeFutureProviderElement<SnChatMember?> createElement() {
|
AutoDisposeAsyncNotifierProviderElement<ChatRoomNotifier, SnChatRoom?>
|
||||||
return _ChatroomIdentityProviderElement(this);
|
createElement() {
|
||||||
|
return _ChatRoomNotifierProviderElement(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
return other is ChatroomIdentityProvider && other.identifier == identifier;
|
return other is ChatRoomNotifierProvider && other.identifier == identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -272,38 +186,170 @@ class ChatroomIdentityProvider
|
|||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
mixin ChatroomIdentityRef on AutoDisposeFutureProviderRef<SnChatMember?> {
|
mixin ChatRoomNotifierRef on AutoDisposeAsyncNotifierProviderRef<SnChatRoom?> {
|
||||||
/// The parameter `identifier` of this provider.
|
/// The parameter `identifier` of this provider.
|
||||||
String? get identifier;
|
String? get identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ChatroomIdentityProviderElement
|
class _ChatRoomNotifierProviderElement
|
||||||
extends AutoDisposeFutureProviderElement<SnChatMember?>
|
extends
|
||||||
with ChatroomIdentityRef {
|
AutoDisposeAsyncNotifierProviderElement<ChatRoomNotifier, SnChatRoom?>
|
||||||
_ChatroomIdentityProviderElement(super.provider);
|
with ChatRoomNotifierRef {
|
||||||
|
_ChatRoomNotifierProviderElement(super.provider);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String? get identifier => (origin as ChatroomIdentityProvider).identifier;
|
String? get identifier => (origin as ChatRoomNotifierProvider).identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
|
String _$chatRoomIdentityNotifierHash() =>
|
||||||
|
r'27c17d55366d39be81d7209837e5c01f80a68a24';
|
||||||
|
|
||||||
/// See also [chatroomInvites].
|
abstract class _$ChatRoomIdentityNotifier
|
||||||
@ProviderFor(chatroomInvites)
|
extends BuildlessAutoDisposeAsyncNotifier<SnChatMember?> {
|
||||||
final chatroomInvitesProvider =
|
late final String? identifier;
|
||||||
AutoDisposeFutureProvider<List<SnChatMember>>.internal(
|
|
||||||
chatroomInvites,
|
FutureOr<SnChatMember?> build(String? identifier);
|
||||||
name: r'chatroomInvitesProvider',
|
}
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
@ProviderFor(ChatRoomIdentityNotifier)
|
||||||
|
const chatRoomIdentityNotifierProvider = ChatRoomIdentityNotifierFamily();
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
class ChatRoomIdentityNotifierFamily extends Family<AsyncValue<SnChatMember?>> {
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
const ChatRoomIdentityNotifierFamily();
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
ChatRoomIdentityNotifierProvider call(String? identifier) {
|
||||||
|
return ChatRoomIdentityNotifierProvider(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ChatRoomIdentityNotifierProvider getProviderOverride(
|
||||||
|
covariant ChatRoomIdentityNotifierProvider provider,
|
||||||
|
) {
|
||||||
|
return call(provider.identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||||
|
|
||||||
|
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||||
|
_allTransitiveDependencies;
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get name => r'chatRoomIdentityNotifierProvider';
|
||||||
|
}
|
||||||
|
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
class ChatRoomIdentityNotifierProvider
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderImpl<
|
||||||
|
ChatRoomIdentityNotifier,
|
||||||
|
SnChatMember?
|
||||||
|
> {
|
||||||
|
/// See also [ChatRoomIdentityNotifier].
|
||||||
|
ChatRoomIdentityNotifierProvider(String? identifier)
|
||||||
|
: this._internal(
|
||||||
|
() => ChatRoomIdentityNotifier()..identifier = identifier,
|
||||||
|
from: chatRoomIdentityNotifierProvider,
|
||||||
|
name: r'chatRoomIdentityNotifierProvider',
|
||||||
debugGetCreateSourceHash:
|
debugGetCreateSourceHash:
|
||||||
const bool.fromEnvironment('dart.vm.product')
|
const bool.fromEnvironment('dart.vm.product')
|
||||||
? null
|
? null
|
||||||
: _$chatroomInvitesHash,
|
: _$chatRoomIdentityNotifierHash,
|
||||||
|
dependencies: ChatRoomIdentityNotifierFamily._dependencies,
|
||||||
|
allTransitiveDependencies:
|
||||||
|
ChatRoomIdentityNotifierFamily._allTransitiveDependencies,
|
||||||
|
identifier: identifier,
|
||||||
|
);
|
||||||
|
|
||||||
|
ChatRoomIdentityNotifierProvider._internal(
|
||||||
|
super._createNotifier, {
|
||||||
|
required super.name,
|
||||||
|
required super.dependencies,
|
||||||
|
required super.allTransitiveDependencies,
|
||||||
|
required super.debugGetCreateSourceHash,
|
||||||
|
required super.from,
|
||||||
|
required this.identifier,
|
||||||
|
}) : super.internal();
|
||||||
|
|
||||||
|
final String? identifier;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<SnChatMember?> runNotifierBuild(
|
||||||
|
covariant ChatRoomIdentityNotifier notifier,
|
||||||
|
) {
|
||||||
|
return notifier.build(identifier);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Override overrideWith(ChatRoomIdentityNotifier Function() create) {
|
||||||
|
return ProviderOverride(
|
||||||
|
origin: this,
|
||||||
|
override: ChatRoomIdentityNotifierProvider._internal(
|
||||||
|
() => create()..identifier = identifier,
|
||||||
|
from: from,
|
||||||
|
name: null,
|
||||||
dependencies: null,
|
dependencies: null,
|
||||||
allTransitiveDependencies: null,
|
allTransitiveDependencies: null,
|
||||||
|
debugGetCreateSourceHash: null,
|
||||||
|
identifier: identifier,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<
|
||||||
|
ChatRoomIdentityNotifier,
|
||||||
|
SnChatMember?
|
||||||
|
>
|
||||||
|
createElement() {
|
||||||
|
return _ChatRoomIdentityNotifierProviderElement(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return other is ChatRoomIdentityNotifierProvider &&
|
||||||
|
other.identifier == identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode {
|
||||||
|
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||||
|
hash = _SystemHash.combine(hash, identifier.hashCode);
|
||||||
|
|
||||||
|
return _SystemHash.finish(hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef ChatroomInvitesRef = AutoDisposeFutureProviderRef<List<SnChatMember>>;
|
mixin ChatRoomIdentityNotifierRef
|
||||||
|
on AutoDisposeAsyncNotifierProviderRef<SnChatMember?> {
|
||||||
|
/// The parameter `identifier` of this provider.
|
||||||
|
String? get identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ChatRoomIdentityNotifierProviderElement
|
||||||
|
extends
|
||||||
|
AutoDisposeAsyncNotifierProviderElement<
|
||||||
|
ChatRoomIdentityNotifier,
|
||||||
|
SnChatMember?
|
||||||
|
>
|
||||||
|
with ChatRoomIdentityNotifierRef {
|
||||||
|
_ChatRoomIdentityNotifierProviderElement(super.provider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String? get identifier =>
|
||||||
|
(origin as ChatRoomIdentityNotifierProvider).identifier;
|
||||||
|
}
|
||||||
|
|
||||||
// ignore_for_file: type=lint
|
// ignore_for_file: type=lint
|
||||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class EditChatScreen extends HookConsumerWidget {
|
|||||||
final isPublic = useState(true);
|
final isPublic = useState(true);
|
||||||
final isCommunity = useState(false);
|
final isCommunity = useState(false);
|
||||||
|
|
||||||
final chat = ref.watch(chatroomProvider(id));
|
final chat = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
|
|
||||||
final joinedRealms = ref.watch(realmsJoinedProvider);
|
final joinedRealms = ref.watch(realmsJoinedProvider);
|
||||||
final currentRealm = useState<SnRealm?>(null);
|
final currentRealm = useState<SnRealm?>(null);
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ class PublicRoomPreview extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import "package:island/pods/chat/messages_notifier.dart";
|
|||||||
import "package:island/pods/network.dart";
|
import "package:island/pods/network.dart";
|
||||||
import "package:island/pods/chat/chat_online_count.dart";
|
import "package:island/pods/chat/chat_online_count.dart";
|
||||||
import "package:island/pods/config.dart";
|
import "package:island/pods/config.dart";
|
||||||
|
import "package:island/pods/userinfo.dart";
|
||||||
import "package:island/screens/chat/search_messages.dart";
|
import "package:island/screens/chat/search_messages.dart";
|
||||||
import "package:island/services/file_uploader.dart";
|
import "package:island/services/file_uploader.dart";
|
||||||
import "package:island/screens/chat/chat.dart";
|
import "package:island/screens/chat/chat.dart";
|
||||||
@@ -48,8 +49,8 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chatRoom = ref.watch(chatroomProvider(id));
|
final chatRoom = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
|
final chatIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
|
||||||
final isSyncing = ref.watch(isSyncingProvider);
|
final isSyncing = ref.watch(isSyncingProvider);
|
||||||
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
|
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
|
||||||
final settings = ref.watch(appSettingsNotifierProvider);
|
final settings = ref.watch(appSettingsNotifierProvider);
|
||||||
@@ -100,7 +101,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
await apiClient.post(
|
await apiClient.post(
|
||||||
'/sphere/chat/${room.id}/members/me',
|
'/sphere/chat/${room.id}/members/me',
|
||||||
);
|
);
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(
|
||||||
|
ChatRoomIdentityNotifierProvider(id),
|
||||||
|
);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
@@ -129,7 +132,7 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
appBar: AppBar(leading: const PageBackButton()),
|
appBar: AppBar(leading: const PageBackButton()),
|
||||||
body: ResponseErrorWidget(
|
body: ResponseErrorWidget(
|
||||||
error: error,
|
error: error,
|
||||||
onRetry: () => ref.refresh(chatroomProvider(id)),
|
onRetry: () => ref.refresh(ChatRoomNotifierProvider(id)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -408,6 +411,14 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
final compactHeader = isWideScreen(context);
|
final compactHeader = isWideScreen(context);
|
||||||
|
|
||||||
|
final userInfo = ref.watch(userInfoProvider);
|
||||||
|
|
||||||
|
List<SnChatMember> getValidMembers(List<SnChatMember> members) {
|
||||||
|
return members
|
||||||
|
.where((member) => member.accountId != userInfo.value?.id)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
Widget comfortHeaderWidget(SnChatRoom? room) => Column(
|
Widget comfortHeaderWidget(SnChatRoom? room) => Column(
|
||||||
spacing: 4,
|
spacing: 4,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@@ -428,9 +439,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
(room!.type == 1 && room.picture?.id == null)
|
(room!.type == 1 && room.picture?.id == null)
|
||||||
? SplitAvatarWidget(
|
? SplitAvatarWidget(
|
||||||
filesId:
|
filesId:
|
||||||
room.members!
|
getValidMembers(
|
||||||
.map((e) => e.account.profile.picture?.id)
|
room.members!,
|
||||||
.toList(),
|
).map((e) => e.account.profile.picture?.id).toList(),
|
||||||
)
|
)
|
||||||
: room.picture?.id != null
|
: room.picture?.id != null
|
||||||
? ProfilePictureWidget(
|
? ProfilePictureWidget(
|
||||||
@@ -447,7 +458,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
? room.members!.map((e) => e.account.nick).join(', ')
|
? getValidMembers(
|
||||||
|
room.members!,
|
||||||
|
).map((e) => e.account.nick).join(', ')
|
||||||
: room.name!,
|
: room.name!,
|
||||||
).fontSize(15),
|
).fontSize(15),
|
||||||
],
|
],
|
||||||
@@ -473,9 +486,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
(room!.type == 1 && room.picture?.id == null)
|
(room!.type == 1 && room.picture?.id == null)
|
||||||
? SplitAvatarWidget(
|
? SplitAvatarWidget(
|
||||||
filesId:
|
filesId:
|
||||||
room.members!
|
getValidMembers(
|
||||||
.map((e) => e.account.profile.picture?.id)
|
room.members!,
|
||||||
.toList(),
|
).map((e) => e.account.profile.picture?.id).toList(),
|
||||||
)
|
)
|
||||||
: room.picture?.id != null
|
: room.picture?.id != null
|
||||||
? ProfilePictureWidget(
|
? ProfilePictureWidget(
|
||||||
@@ -492,7 +505,9 @@ class ChatRoomScreen extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
? room.members!.map((e) => e.account.nick).join(', ')
|
? getValidMembers(
|
||||||
|
room.members!,
|
||||||
|
).map((e) => e.account.nick).join(', ')
|
||||||
: room.name!,
|
: room.name!,
|
||||||
).fontSize(19),
|
).fontSize(19),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final roomState = ref.watch(chatroomProvider(id));
|
final roomState = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
final roomIdentity = ref.watch(chatroomIdentityProvider(id));
|
final roomIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
|
||||||
final totalMessages = ref.watch(totalMessagesCountProvider(id));
|
final totalMessages = ref.watch(totalMessagesCountProvider(id));
|
||||||
|
|
||||||
const kNotifyLevelText = [
|
const kNotifyLevelText = [
|
||||||
@@ -56,7 +56,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
'/sphere/chat/$id/members/me/notify',
|
'/sphere/chat/$id/members/me/notify',
|
||||||
data: {'notify_level': level},
|
data: {'notify_level': level},
|
||||||
);
|
);
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showSnackBar(
|
showSnackBar(
|
||||||
'chatNotifyLevelUpdated'.tr(args: [kNotifyLevelText[level].tr()]),
|
'chatNotifyLevelUpdated'.tr(args: [kNotifyLevelText[level].tr()]),
|
||||||
@@ -74,7 +74,7 @@ class ChatDetailScreen extends HookConsumerWidget {
|
|||||||
'/sphere/chat/$id/members/me/notify',
|
'/sphere/chat/$id/members/me/notify',
|
||||||
data: {'break_until': until.toUtc().toIso8601String()},
|
data: {'break_until': until.toUtc().toIso8601String()},
|
||||||
);
|
);
|
||||||
ref.invalidate(chatroomProvider(id));
|
ref.invalidate(ChatRoomNotifierProvider(id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
}
|
}
|
||||||
@@ -439,8 +439,8 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
|
final chatIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
|
||||||
final chatRoom = ref.watch(chatroomProvider(id));
|
final chatRoom = ref.watch(ChatRoomNotifierProvider(id));
|
||||||
|
|
||||||
final isManagable =
|
final isManagable =
|
||||||
chatIdentity.value?.accountId == chatRoom.value?.accountId ||
|
chatIdentity.value?.accountId == chatRoom.value?.accountId ||
|
||||||
@@ -461,7 +461,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
).then((value) {
|
).then((value) {
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
// Invalidate to refresh room data after edit
|
// Invalidate to refresh room data after edit
|
||||||
ref.invalidate(chatroomProvider(id));
|
ref.invalidate(ChatRoomNotifierProvider(id));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -497,7 +497,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
if (confirm) {
|
if (confirm) {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
await client.delete('/sphere/chat/$id');
|
await client.delete('/sphere/chat/$id');
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
@@ -530,7 +530,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
|
|||||||
if (confirm) {
|
if (confirm) {
|
||||||
final client = ref.watch(apiClientProvider);
|
final client = ref.watch(apiClientProvider);
|
||||||
await client.delete('/sphere/chat/$id/members/me');
|
await client.delete('/sphere/chat/$id/members/me');
|
||||||
ref.invalidate(chatroomsJoinedProvider);
|
ref.invalidate(chatRoomJoinedNotifierProvider);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
context.pop();
|
context.pop();
|
||||||
}
|
}
|
||||||
@@ -648,8 +648,8 @@ class _ChatMemberListSheet extends HookConsumerWidget {
|
|||||||
final memberState = ref.watch(chatMemberStateProvider(roomId));
|
final memberState = ref.watch(chatMemberStateProvider(roomId));
|
||||||
final memberNotifier = ref.read(chatMemberStateProvider(roomId).notifier);
|
final memberNotifier = ref.read(chatMemberStateProvider(roomId).notifier);
|
||||||
|
|
||||||
final roomIdentity = ref.watch(chatroomIdentityProvider(roomId));
|
final roomIdentity = ref.watch(ChatRoomIdentityNotifierProvider(roomId));
|
||||||
final chatRoom = ref.watch(chatroomProvider(roomId));
|
final chatRoom = ref.watch(ChatRoomNotifierProvider(roomId));
|
||||||
|
|
||||||
final isManagable =
|
final isManagable =
|
||||||
chatRoom.value?.accountId == roomIdentity.value?.accountId ||
|
chatRoom.value?.accountId == roomIdentity.value?.accountId ||
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import "package:island/models/wallet.dart";
|
|||||||
import "package:island/models/realm.dart";
|
import "package:island/models/realm.dart";
|
||||||
import "package:island/models/sticker.dart";
|
import "package:island/models/sticker.dart";
|
||||||
import "package:island/pods/config.dart";
|
import "package:island/pods/config.dart";
|
||||||
|
import "package:island/pods/userinfo.dart";
|
||||||
import "package:island/services/autocomplete_service.dart";
|
import "package:island/services/autocomplete_service.dart";
|
||||||
import "package:island/services/responsive.dart";
|
import "package:island/services/responsive.dart";
|
||||||
import "package:island/widgets/content/attachment_preview.dart";
|
import "package:island/widgets/content/attachment_preview.dart";
|
||||||
@@ -344,6 +345,14 @@ class ChatInput extends HookConsumerWidget {
|
|||||||
final double rightMargin = isWideScreen(context) ? leftMargin + 8 : 16;
|
final double rightMargin = isWideScreen(context) ? leftMargin + 8 : 16;
|
||||||
const double bottomMargin = 16;
|
const double bottomMargin = 16;
|
||||||
|
|
||||||
|
final userInfo = ref.watch(userInfoProvider);
|
||||||
|
|
||||||
|
List<SnChatMember> getValidMembers(List<SnChatMember> members) {
|
||||||
|
return members
|
||||||
|
.where((member) => member.accountId != userInfo.value?.id)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
left: leftMargin,
|
left: leftMargin,
|
||||||
@@ -878,9 +887,9 @@ class ChatInput extends HookConsumerWidget {
|
|||||||
(chatRoom.type == 1 && chatRoom.name == null)
|
(chatRoom.type == 1 && chatRoom.name == null)
|
||||||
? 'chatDirectMessageHint'.tr(
|
? 'chatDirectMessageHint'.tr(
|
||||||
args: [
|
args: [
|
||||||
chatRoom.members!
|
getValidMembers(
|
||||||
.map((e) => e.account.nick)
|
chatRoom.members!,
|
||||||
.join(', '),
|
).map((e) => e.account.nick).join(', '),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: 'chatMessageHint'.tr(
|
: 'chatMessageHint'.tr(
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ class PublicRoomPreview extends HookConsumerWidget {
|
|||||||
showLoadingModal(context);
|
showLoadingModal(context);
|
||||||
final apiClient = ref.read(apiClientProvider);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
await apiClient.post('/sphere/chat/${room.id}/members/me');
|
||||||
ref.invalidate(chatroomIdentityProvider(id));
|
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showErrorAlert(err);
|
showErrorAlert(err);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -664,7 +664,7 @@ class _ChatRoomsList extends ConsumerWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final chatRooms = ref.watch(chatroomsJoinedProvider);
|
final chatRooms = ref.watch(chatRoomJoinedNotifierProvider);
|
||||||
|
|
||||||
return chatRooms.when(
|
return chatRooms.when(
|
||||||
data: (rooms) {
|
data: (rooms) {
|
||||||
|
|||||||
Reference in New Issue
Block a user