♻️ Refactored the chat loading to use more local data

This commit is contained in:
2025-12-04 22:10:07 +08:00
parent dfcb089c69
commit 31b83b2d27
14 changed files with 731 additions and 366 deletions

View File

@@ -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 {
if (override) {
// 1. Identify rooms to remove
final remoteRoomIds = rooms.map((r) => r.id).toSet();
final currentRooms = await select(chatRooms).get();
@@ -369,13 +373,15 @@ class AppDatabase extends _$AppDatabase {
if (idsToRemove.isNotEmpty) {
final idsList = idsToRemove.toList();
// Remove messages
await (delete(chatMessages)..where((t) => t.roomId.isIn(idsList))).go();
await (delete(chatMessages)
..where((t) => t.roomId.isIn(idsList))).go();
// Remove members
await (delete(chatMembers)
..where((t) => t.chatRoomId.isIn(idsList))).go();
// Remove rooms
await (delete(chatRooms)..where((t) => t.id.isIn(idsList))).go();
}
}
// 2. Upsert remote rooms
await batch((batch) {

View File

@@ -16,10 +16,9 @@ final currentSubscribedChatIdProvider = StateProvider<String?>((ref) => null);
@riverpod
class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
late final String _roomId;
late final SnChatRoom _chatRoom;
late final SnChatMember _chatIdentity;
late final MessagesNotifier _messagesNotifier;
late SnChatRoom _chatRoom;
late SnChatMember _chatIdentity;
late MessagesNotifier _messagesNotifier;
final List<SnChatMember> _typingStatuses = [];
Timer? _typingCleanupTimer;
@@ -29,10 +28,11 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
@override
List<SnChatMember> build(String roomId) {
_roomId = roomId;
final ws = ref.watch(websocketProvider);
final chatRoomAsync = ref.watch(chatroomProvider(roomId));
final chatIdentityAsync = ref.watch(chatroomIdentityProvider(roomId));
final chatRoomAsync = ref.watch(ChatRoomNotifierProvider(roomId));
final chatIdentityAsync = ref.watch(
ChatRoomIdentityNotifierProvider(roomId),
);
_messagesNotifier = ref.watch(messagesNotifierProvider(roomId).notifier);
if (chatRoomAsync.isLoading || chatIdentityAsync.isLoading) {
@@ -199,7 +199,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
jsonEncode(
WebSocketPacket(
type: 'messages.read',
data: {'chat_room_id': _roomId},
data: {'chat_room_id': roomId},
endpoint: 'sphere',
),
),
@@ -216,7 +216,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
jsonEncode(
WebSocketPacket(
type: 'messages.typing',
data: {'chat_room_id': _roomId},
data: {'chat_room_id': roomId},
endpoint: 'sphere',
),
),

View File

@@ -7,7 +7,7 @@ part of 'chat_subscribe.dart';
// **************************************************************************
String _$chatSubscribeNotifierHash() =>
r'c605e0c9c45df64e5ba7b65f8de9b47bde8e2b3b';
r'beec1ddf2e13f6d5af8a08c2c81eff740ae9b986';
/// Copied from Dart SDK
class _SystemHash {

View File

@@ -27,10 +27,10 @@ part 'messages_notifier.g.dart';
@riverpod
class MessagesNotifier extends _$MessagesNotifier {
late final Dio _apiClient;
late final AppDatabase _database;
late final SnChatRoom _room;
late final SnChatMember _identity;
late Dio _apiClient;
late AppDatabase _database;
late SnChatRoom _room;
late SnChatMember _identity;
final Map<String, LocalChatMessage> _pendingMessages = {};
final Map<String, Map<int, double?>> _fileUploadProgress = {};
@@ -39,7 +39,6 @@ class MessagesNotifier extends _$MessagesNotifier {
bool? _withLinks;
bool? _withAttachments;
late final String _roomId;
static const int _pageSize = 20;
bool _hasMore = true;
bool _isSyncing = false;
@@ -48,15 +47,16 @@ class MessagesNotifier extends _$MessagesNotifier {
bool _allRemoteMessagesFetched = false;
DateTime? _lastPauseTime;
late final Future<SnAccount?> Function(String) _fetchAccount;
late Future<SnAccount?> Function(String) _fetchAccount;
@override
FutureOr<List<LocalChatMessage>> build(String roomId) async {
_roomId = roomId;
_apiClient = ref.watch(apiClientProvider);
_database = ref.watch(databaseProvider);
final room = await ref.watch(chatroomProvider(roomId).future);
final identity = await ref.watch(chatroomIdentityProvider(roomId).future);
final room = await ref.watch(ChatRoomNotifierProvider(roomId).future);
final identity = await ref.watch(
ChatRoomIdentityNotifierProvider(roomId).future,
);
// Initialize fetch account method for corrupted data recovery
_fetchAccount = (String accountId) async {
@@ -144,14 +144,14 @@ class MessagesNotifier extends _$MessagesNotifier {
if (searchQuery != null && searchQuery.isNotEmpty) {
dbMessages = await _database.searchMessages(
_roomId,
roomId,
searchQuery,
withAttachments: withAttachments,
fetchAccount: _fetchAccount,
);
} else {
final chatMessagesFromDb = await _database.getMessagesForRoom(
_roomId,
roomId,
offset: offset,
limit: take,
);
@@ -194,9 +194,7 @@ class MessagesNotifier extends _$MessagesNotifier {
if (offset == 0) {
final pendingForRoom =
_pendingMessages.values
.where((msg) => msg.roomId == _roomId)
.toList();
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
final allMessages = [...pendingForRoom, ...uniqueMessages];
_sortMessages(allMessages); // Use the helper function
@@ -221,7 +219,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}) async {
talker.log('Getting all messages for jump from offset $offset, take $take');
final chatMessagesFromDb = await _database.getMessagesForRoom(
_roomId,
roomId,
offset: offset,
limit: take,
);
@@ -245,9 +243,7 @@ class MessagesNotifier extends _$MessagesNotifier {
if (offset == 0) {
final pendingForRoom =
_pendingMessages.values
.where((msg) => msg.roomId == _roomId)
.toList();
_pendingMessages.values.where((msg) => msg.roomId == roomId).toList();
final allMessages = [...pendingForRoom, ...uniqueMessages];
_sortMessages(allMessages);
@@ -272,7 +268,7 @@ class MessagesNotifier extends _$MessagesNotifier {
talker.log('Fetching messages from API, offset $offset, take $take');
if (_totalCount == null) {
final response = await _apiClient.get(
'/sphere/chat/$_roomId/messages',
'/sphere/chat/$roomId/messages',
queryParameters: {'offset': 0, 'take': 1},
);
_totalCount = int.parse(response.headers['x-total']?.firstOrNull ?? '0');
@@ -284,7 +280,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
final response = await _apiClient.get(
'/sphere/chat/$_roomId/messages',
'/sphere/chat/$roomId/messages',
queryParameters: {'offset': offset, 'take': take},
);
@@ -546,7 +542,7 @@ class MessagesNotifier extends _$MessagesNotifier {
final mockMessage = SnChatMessage(
id: 'pending_$nonce',
chatRoomId: _roomId,
chatRoomId: roomId,
senderId: _identity.id,
content: content,
createdAt: DateTime.now(),
@@ -590,8 +586,8 @@ class MessagesNotifier extends _$MessagesNotifier {
final response = await _apiClient.request(
editingTo == null
? '/sphere/chat/$_roomId/messages'
: '/sphere/chat/$_roomId/messages/${editingTo.id}',
? '/sphere/chat/$roomId/messages'
: '/sphere/chat/$roomId/messages/${editingTo.id}',
data: {
'content': content,
'attachments_id': cloudAttachments.map((e) => e.id).toList(),
@@ -731,7 +727,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
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
if (_isJumping) {
@@ -783,7 +779,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
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
if (_isJumping) {
@@ -883,7 +879,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
try {
await _apiClient.delete('/sphere/chat/$_roomId/messages/$messageId');
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId');
await receiveMessageDeletion(messageId);
} catch (err, stackTrace) {
talker.log(
@@ -991,7 +987,7 @@ class MessagesNotifier extends _$MessagesNotifier {
}
final response = await _apiClient.get(
'/sphere/chat/$_roomId/messages/$messageId',
'/sphere/chat/$roomId/messages/$messageId',
);
final remoteMessage = SnChatMessage.fromJson(response.data);
final message = LocalChatMessage.fromRemoteMessage(
@@ -1048,7 +1044,7 @@ class MessagesNotifier extends _$MessagesNotifier {
final query = _database.customSelect(
'SELECT COUNT(*) as count FROM chat_messages WHERE room_id = ? AND created_at > ?',
variables: [
Variable.withString(_roomId),
Variable.withString(roomId),
Variable.withDateTime(message.createdAt),
],
readsFrom: {_database.chatMessages},

View File

@@ -6,7 +6,7 @@ part of 'messages_notifier.dart';
// RiverpodGenerator
// **************************************************************************
String _$messagesNotifierHash() => r'27ce32c54e317a04e1d554ed4a70a24e4503fdd1';
String _$messagesNotifierHash() => r'd76d799494b06fac2adc42d94b7ecd7b8d68c352';
/// Copied from Dart SDK
class _SystemHash {

View File

@@ -9,6 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:island/models/chat.dart';
import 'package:island/models/file.dart';
import 'package:island/models/account.dart';
import 'package:island/database/drift_db.dart';
import 'package:island/pods/database.dart';
import 'package:island/pods/chat/chat_summary.dart';
import 'package:island/pods/network.dart';
@@ -184,13 +185,100 @@ class ChatRoomListTile extends HookConsumerWidget {
}
@riverpod
Future<List<SnChatRoom>> chatroomsJoined(Ref ref) async {
class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
@override
Future<List<SnChatRoom>> build() async {
final db = ref.watch(databaseProvider);
try {
final localRoomsData = await db.select(db.chatRooms).get();
if (localRoomsData.isNotEmpty) {
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 {
final membersRows =
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 {
@@ -281,7 +343,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final chats = ref.watch(chatroomsJoinedProvider);
final chats = ref.watch(chatRoomJoinedNotifierProvider);
Widget bodyWidget = Column(
children: [
@@ -304,7 +366,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
(items) => RefreshIndicator(
onRefresh:
() => Future.sync(() {
ref.invalidate(chatroomsJoinedProvider);
ref.invalidate(chatRoomJoinedNotifierProvider);
}),
child: SuperListView.builder(
padding: EdgeInsets.only(bottom: 96),
@@ -354,7 +416,7 @@ class ChatListBodyWidget extends HookConsumerWidget {
(error, stack) => ResponseErrorWidget(
error: error,
onRetry: () {
ref.invalidate(chatroomsJoinedProvider);
ref.invalidate(chatRoomJoinedNotifierProvider);
},
),
),
@@ -431,7 +493,7 @@ class ChatListScreen extends HookConsumerWidget {
// Listen for chat rooms refresh events
final subscription = eventBus.on<ChatRoomsRefreshEvent>().listen((event) {
ref.invalidate(chatroomsJoinedProvider);
ref.invalidate(chatRoomJoinedNotifierProvider);
});
return () {
@@ -600,33 +662,264 @@ class ChatListScreen extends HookConsumerWidget {
}
@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;
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 {
final client = ref.watch(apiClientProvider);
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) {
if (err is DioException && err.response?.statusCode == 404) {
return null; // Chat room not found
}
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
Future<SnChatMember?> chatroomIdentity(Ref ref, String? identifier) async {
class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
@override
Future<SnChatMember?> build(String? identifier) async {
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 {
final client = ref.watch(apiClientProvider);
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) {
if (err is DioException && err.response?.statusCode == 404) {
return null; // Chat member not found
}
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
@@ -651,7 +944,7 @@ class _ChatInvitesSheet extends HookConsumerWidget {
final client = ref.read(apiClientProvider);
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept');
ref.invalidate(chatroomInvitesProvider);
ref.invalidate(chatroomsJoinedProvider);
ref.invalidate(chatRoomJoinedNotifierProvider);
} catch (err) {
showErrorAlert(err);
}

View File

@@ -6,26 +6,46 @@ part of 'chat.dart';
// RiverpodGenerator
// **************************************************************************
String _$chatroomsJoinedHash() => r'50abce4f03a7a8509f16d5ad0b1dbf8e3aeb73b6';
String _$chatroomInvitesHash() => r'5cd6391b09c5517ede19bacce43b45c8d71dd087';
/// See also [chatroomsJoined].
@ProviderFor(chatroomsJoined)
final chatroomsJoinedProvider =
AutoDisposeFutureProvider<List<SnChatRoom>>.internal(
chatroomsJoined,
name: r'chatroomsJoinedProvider',
/// See also [chatroomInvites].
@ProviderFor(chatroomInvites)
final chatroomInvitesProvider =
AutoDisposeFutureProvider<List<SnChatMember>>.internal(
chatroomInvites,
name: r'chatroomInvitesProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$chatroomsJoinedHash,
: _$chatroomInvitesHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef ChatroomsJoinedRef = AutoDisposeFutureProviderRef<List<SnChatRoom>>;
String _$chatroomHash() => r'2b17d94728026420d18d6c383d2400cf4a070913';
typedef ChatroomInvitesRef = AutoDisposeFutureProviderRef<List<SnChatMember>>;
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
class _SystemHash {
@@ -48,141 +68,30 @@ class _SystemHash {
}
}
/// See also [chatroom].
@ProviderFor(chatroom)
const chatroomProvider = ChatroomFamily();
abstract class _$ChatRoomNotifier
extends BuildlessAutoDisposeAsyncNotifier<SnChatRoom?> {
late final String? identifier;
/// See also [chatroom].
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';
FutureOr<SnChatRoom?> build(String? identifier);
}
/// See also [chatroom].
class ChatroomProvider extends AutoDisposeFutureProvider<SnChatRoom?> {
/// See also [chatroom].
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,
);
/// See also [ChatRoomNotifier].
@ProviderFor(ChatRoomNotifier)
const chatRoomNotifierProvider = ChatRoomNotifierFamily();
ChatroomProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.identifier,
}) : super.internal();
/// See also [ChatRoomNotifier].
class ChatRoomNotifierFamily extends Family<AsyncValue<SnChatRoom?>> {
/// See also [ChatRoomNotifier].
const ChatRoomNotifierFamily();
final String? identifier;
@override
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,
),
);
/// See also [ChatRoomNotifier].
ChatRoomNotifierProvider call(String? identifier) {
return ChatRoomNotifierProvider(identifier);
}
@override
AutoDisposeFutureProviderElement<SnChatRoom?> createElement() {
return _ChatroomProviderElement(this);
}
@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,
ChatRoomNotifierProvider getProviderOverride(
covariant ChatRoomNotifierProvider provider,
) {
return call(provider.identifier);
}
@@ -199,29 +108,30 @@ class ChatroomIdentityFamily extends Family<AsyncValue<SnChatMember?>> {
_allTransitiveDependencies;
@override
String? get name => r'chatroomIdentityProvider';
String? get name => r'chatRoomNotifierProvider';
}
/// See also [chatroomIdentity].
class ChatroomIdentityProvider
extends AutoDisposeFutureProvider<SnChatMember?> {
/// See also [chatroomIdentity].
ChatroomIdentityProvider(String? identifier)
/// See also [ChatRoomNotifier].
class ChatRoomNotifierProvider
extends
AutoDisposeAsyncNotifierProviderImpl<ChatRoomNotifier, SnChatRoom?> {
/// See also [ChatRoomNotifier].
ChatRoomNotifierProvider(String? identifier)
: this._internal(
(ref) => chatroomIdentity(ref as ChatroomIdentityRef, identifier),
from: chatroomIdentityProvider,
name: r'chatroomIdentityProvider',
() => ChatRoomNotifier()..identifier = identifier,
from: chatRoomNotifierProvider,
name: r'chatRoomNotifierProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$chatroomIdentityHash,
dependencies: ChatroomIdentityFamily._dependencies,
: _$chatRoomNotifierHash,
dependencies: ChatRoomNotifierFamily._dependencies,
allTransitiveDependencies:
ChatroomIdentityFamily._allTransitiveDependencies,
ChatRoomNotifierFamily._allTransitiveDependencies,
identifier: identifier,
);
ChatroomIdentityProvider._internal(
ChatRoomNotifierProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
@@ -234,13 +144,16 @@ class ChatroomIdentityProvider
final String? identifier;
@override
Override overrideWith(
FutureOr<SnChatMember?> Function(ChatroomIdentityRef provider) create,
) {
FutureOr<SnChatRoom?> runNotifierBuild(covariant ChatRoomNotifier notifier) {
return notifier.build(identifier);
}
@override
Override overrideWith(ChatRoomNotifier Function() create) {
return ProviderOverride(
origin: this,
override: ChatroomIdentityProvider._internal(
(ref) => create(ref as ChatroomIdentityRef),
override: ChatRoomNotifierProvider._internal(
() => create()..identifier = identifier,
from: from,
name: null,
dependencies: null,
@@ -252,13 +165,14 @@ class ChatroomIdentityProvider
}
@override
AutoDisposeFutureProviderElement<SnChatMember?> createElement() {
return _ChatroomIdentityProviderElement(this);
AutoDisposeAsyncNotifierProviderElement<ChatRoomNotifier, SnChatRoom?>
createElement() {
return _ChatRoomNotifierProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is ChatroomIdentityProvider && other.identifier == identifier;
return other is ChatRoomNotifierProvider && other.identifier == identifier;
}
@override
@@ -272,38 +186,170 @@ class ChatroomIdentityProvider
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin ChatroomIdentityRef on AutoDisposeFutureProviderRef<SnChatMember?> {
mixin ChatRoomNotifierRef on AutoDisposeAsyncNotifierProviderRef<SnChatRoom?> {
/// The parameter `identifier` of this provider.
String? get identifier;
}
class _ChatroomIdentityProviderElement
extends AutoDisposeFutureProviderElement<SnChatMember?>
with ChatroomIdentityRef {
_ChatroomIdentityProviderElement(super.provider);
class _ChatRoomNotifierProviderElement
extends
AutoDisposeAsyncNotifierProviderElement<ChatRoomNotifier, SnChatRoom?>
with ChatRoomNotifierRef {
_ChatRoomNotifierProviderElement(super.provider);
@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].
@ProviderFor(chatroomInvites)
final chatroomInvitesProvider =
AutoDisposeFutureProvider<List<SnChatMember>>.internal(
chatroomInvites,
name: r'chatroomInvitesProvider',
abstract class _$ChatRoomIdentityNotifier
extends BuildlessAutoDisposeAsyncNotifier<SnChatMember?> {
late final String? identifier;
FutureOr<SnChatMember?> build(String? identifier);
}
/// 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:
const bool.fromEnvironment('dart.vm.product')
? 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,
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')
// 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: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package

View File

@@ -47,7 +47,7 @@ class EditChatScreen extends HookConsumerWidget {
final isPublic = useState(true);
final isCommunity = useState(false);
final chat = ref.watch(chatroomProvider(id));
final chat = ref.watch(ChatRoomNotifierProvider(id));
final joinedRealms = ref.watch(realmsJoinedProvider);
final currentRealm = useState<SnRealm?>(null);

View File

@@ -203,7 +203,7 @@ class PublicRoomPreview extends HookConsumerWidget {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
await apiClient.post('/sphere/chat/${room.id}/members/me');
ref.invalidate(chatroomIdentityProvider(id));
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
} catch (err) {
showErrorAlert(err);
} finally {

View File

@@ -20,6 +20,7 @@ import "package:island/pods/chat/messages_notifier.dart";
import "package:island/pods/network.dart";
import "package:island/pods/chat/chat_online_count.dart";
import "package:island/pods/config.dart";
import "package:island/pods/userinfo.dart";
import "package:island/screens/chat/search_messages.dart";
import "package:island/services/file_uploader.dart";
import "package:island/screens/chat/chat.dart";
@@ -48,8 +49,8 @@ class ChatRoomScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final chatRoom = ref.watch(chatroomProvider(id));
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
final chatRoom = ref.watch(ChatRoomNotifierProvider(id));
final chatIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
final isSyncing = ref.watch(isSyncingProvider);
final onlineCount = ref.watch(chatOnlineCountNotifierProvider(id));
final settings = ref.watch(appSettingsNotifierProvider);
@@ -100,7 +101,9 @@ class ChatRoomScreen extends HookConsumerWidget {
await apiClient.post(
'/sphere/chat/${room.id}/members/me',
);
ref.invalidate(chatroomIdentityProvider(id));
ref.invalidate(
ChatRoomIdentityNotifierProvider(id),
);
} catch (err) {
showErrorAlert(err);
} finally {
@@ -129,7 +132,7 @@ class ChatRoomScreen extends HookConsumerWidget {
appBar: AppBar(leading: const PageBackButton()),
body: ResponseErrorWidget(
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 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(
spacing: 4,
mainAxisAlignment: MainAxisAlignment.center,
@@ -428,9 +439,9 @@ class ChatRoomScreen extends HookConsumerWidget {
(room!.type == 1 && room.picture?.id == null)
? SplitAvatarWidget(
filesId:
room.members!
.map((e) => e.account.profile.picture?.id)
.toList(),
getValidMembers(
room.members!,
).map((e) => e.account.profile.picture?.id).toList(),
)
: room.picture?.id != null
? ProfilePictureWidget(
@@ -447,7 +458,9 @@ class ChatRoomScreen extends HookConsumerWidget {
),
Text(
(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!,
).fontSize(15),
],
@@ -473,9 +486,9 @@ class ChatRoomScreen extends HookConsumerWidget {
(room!.type == 1 && room.picture?.id == null)
? SplitAvatarWidget(
filesId:
room.members!
.map((e) => e.account.profile.picture?.id)
.toList(),
getValidMembers(
room.members!,
).map((e) => e.account.profile.picture?.id).toList(),
)
: room.picture?.id != null
? ProfilePictureWidget(
@@ -492,7 +505,9 @@ class ChatRoomScreen extends HookConsumerWidget {
),
Text(
(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!,
).fontSize(19),
],

View File

@@ -39,8 +39,8 @@ class ChatDetailScreen extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final roomState = ref.watch(chatroomProvider(id));
final roomIdentity = ref.watch(chatroomIdentityProvider(id));
final roomState = ref.watch(ChatRoomNotifierProvider(id));
final roomIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
final totalMessages = ref.watch(totalMessagesCountProvider(id));
const kNotifyLevelText = [
@@ -56,7 +56,7 @@ class ChatDetailScreen extends HookConsumerWidget {
'/sphere/chat/$id/members/me/notify',
data: {'notify_level': level},
);
ref.invalidate(chatroomIdentityProvider(id));
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
if (context.mounted) {
showSnackBar(
'chatNotifyLevelUpdated'.tr(args: [kNotifyLevelText[level].tr()]),
@@ -74,7 +74,7 @@ class ChatDetailScreen extends HookConsumerWidget {
'/sphere/chat/$id/members/me/notify',
data: {'break_until': until.toUtc().toIso8601String()},
);
ref.invalidate(chatroomProvider(id));
ref.invalidate(ChatRoomNotifierProvider(id));
} catch (err) {
showErrorAlert(err);
}
@@ -439,8 +439,8 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final chatIdentity = ref.watch(chatroomIdentityProvider(id));
final chatRoom = ref.watch(chatroomProvider(id));
final chatIdentity = ref.watch(ChatRoomIdentityNotifierProvider(id));
final chatRoom = ref.watch(ChatRoomNotifierProvider(id));
final isManagable =
chatIdentity.value?.accountId == chatRoom.value?.accountId ||
@@ -461,7 +461,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
).then((value) {
if (value != null) {
// 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) {
final client = ref.watch(apiClientProvider);
await client.delete('/sphere/chat/$id');
ref.invalidate(chatroomsJoinedProvider);
ref.invalidate(chatRoomJoinedNotifierProvider);
if (context.mounted) {
context.pop();
}
@@ -530,7 +530,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
if (confirm) {
final client = ref.watch(apiClientProvider);
await client.delete('/sphere/chat/$id/members/me');
ref.invalidate(chatroomsJoinedProvider);
ref.invalidate(chatRoomJoinedNotifierProvider);
if (context.mounted) {
context.pop();
}
@@ -648,8 +648,8 @@ class _ChatMemberListSheet extends HookConsumerWidget {
final memberState = ref.watch(chatMemberStateProvider(roomId));
final memberNotifier = ref.read(chatMemberStateProvider(roomId).notifier);
final roomIdentity = ref.watch(chatroomIdentityProvider(roomId));
final chatRoom = ref.watch(chatroomProvider(roomId));
final roomIdentity = ref.watch(ChatRoomIdentityNotifierProvider(roomId));
final chatRoom = ref.watch(ChatRoomNotifierProvider(roomId));
final isManagable =
chatRoom.value?.accountId == roomIdentity.value?.accountId ||

View File

@@ -17,6 +17,7 @@ import "package:island/models/wallet.dart";
import "package:island/models/realm.dart";
import "package:island/models/sticker.dart";
import "package:island/pods/config.dart";
import "package:island/pods/userinfo.dart";
import "package:island/services/autocomplete_service.dart";
import "package:island/services/responsive.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;
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(
margin: EdgeInsets.only(
left: leftMargin,
@@ -878,9 +887,9 @@ class ChatInput extends HookConsumerWidget {
(chatRoom.type == 1 && chatRoom.name == null)
? 'chatDirectMessageHint'.tr(
args: [
chatRoom.members!
.map((e) => e.account.nick)
.join(', '),
getValidMembers(
chatRoom.members!,
).map((e) => e.account.nick).join(', '),
],
)
: 'chatMessageHint'.tr(

View File

@@ -205,7 +205,7 @@ class PublicRoomPreview extends HookConsumerWidget {
showLoadingModal(context);
final apiClient = ref.read(apiClientProvider);
await apiClient.post('/sphere/chat/${room.id}/members/me');
ref.invalidate(chatroomIdentityProvider(id));
ref.invalidate(ChatRoomIdentityNotifierProvider(id));
} catch (err) {
showErrorAlert(err);
} finally {

View File

@@ -664,7 +664,7 @@ class _ChatRoomsList extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final chatRooms = ref.watch(chatroomsJoinedProvider);
final chatRooms = ref.watch(chatRoomJoinedNotifierProvider);
return chatRooms.when(
data: (rooms) {