👽 Changes to API path since sphere no longer handle messages

This commit is contained in:
2026-01-01 23:59:21 +08:00
parent 0a4e797eec
commit 4d92dec45c
20 changed files with 644 additions and 712 deletions

View File

@@ -34,7 +34,7 @@ class NotifyDelegate: UIResponder, UNUserNotificationCenterDelegate {
} }
let serverUrl = UserDefaults.standard.getServerUrl() let serverUrl = UserDefaults.standard.getServerUrl()
let url = "\(serverUrl)/sphere/chat/\(metadata["room_id"] ?? "")/messages" let url = "\(serverUrl)/messager/chat/\(metadata["room_id"] ?? "")/messages"
let parameters: [String: Any?] = [ let parameters: [String: Any?] = [
"content": textResponse.userText, "content": textResponse.userText,

View File

@@ -261,7 +261,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else { guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL) throw URLError(.badURL)
} }
let url = baseURL.appendingPathComponent("/sphere/chat") let url = baseURL.appendingPathComponent("/messager/chat")
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@@ -283,7 +283,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else { guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL) throw URLError(.badURL)
} }
let url = baseURL.appendingPathComponent("/sphere/chat/\(identifier)") let url = baseURL.appendingPathComponent("/messager/chat/\(identifier)")
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@@ -308,7 +308,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else { guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL) throw URLError(.badURL)
} }
let url = baseURL.appendingPathComponent("/sphere/chat/invites") let url = baseURL.appendingPathComponent("/messager/chat/invites")
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "GET" request.httpMethod = "GET"
@@ -330,7 +330,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else { guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL) throw URLError(.badURL)
} }
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/accept") let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/accept")
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
@@ -351,7 +351,7 @@ class NetworkService {
guard let baseURL = URL(string: serverUrl) else { guard let baseURL = URL(string: serverUrl) else {
throw URLError(.badURL) throw URLError(.badURL)
} }
let url = baseURL.appendingPathComponent("/sphere/chat/invites/\(chatRoomId)/decline") let url = baseURL.appendingPathComponent("/messager/chat/invites/\(chatRoomId)/decline")
var request = URLRequest(url: url) var request = URLRequest(url: url)
request.httpMethod = "POST" request.httpMethod = "POST"
@@ -375,9 +375,9 @@ class NetworkService {
throw URLError(.badURL) throw URLError(.badURL)
} }
// Try a different pattern: /sphere/chat/messages with roomId as query param // Try a different pattern: /messager/chat/messages with roomId as query param
var components = URLComponents( var components = URLComponents(
url: baseURL.appendingPathComponent("/sphere/chat/\(chatRoomId)/messages"), url: baseURL.appendingPathComponent("/messager/chat/\(chatRoomId)/messages"),
resolvingAgainstBaseURL: false resolvingAgainstBaseURL: false
)! )!
var queryItems = [ var queryItems = [

View File

@@ -455,7 +455,7 @@ struct ChatRoomView: View {
] ]
// Create the URL // Create the URL
guard let url = URL(string: "\(serverUrl)/sphere/chat/\(room.id)/messages") else { guard let url = URL(string: "\(serverUrl)/messager/chat/\(room.id)/messages") else {
throw URLError(.badURL) throw URLError(.badURL)
} }

View File

@@ -245,7 +245,7 @@ class CallNotifier extends _$CallNotifier {
final apiClient = ref.read(apiClientProvider); final apiClient = ref.read(apiClientProvider);
final ongoingCall = await ref.read(ongoingCallProvider(roomId).future); final ongoingCall = await ref.read(ongoingCallProvider(roomId).future);
final response = await apiClient.get( final response = await apiClient.get(
'/sphere/chat/realtime/$roomId/join', '/messager/chat/realtime/$roomId/join',
); );
if (response.statusCode == 200 && response.data != null) { if (response.statusCode == 200 && response.data != null) {
final data = response.data; final data = response.data;

View File

@@ -15,7 +15,7 @@ class ChatOnlineCountNotifier extends _$ChatOnlineCountNotifier {
// Fetch initial online count // Fetch initial online count
final response = await apiClient.get( final response = await apiClient.get(
'/sphere/chat/$chatroomId/members/online', '/messager/chat/$chatroomId/members/online',
); );
final initialCount = response.data as int; final initialCount = response.data as int;

View File

@@ -105,7 +105,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
Future(() async { Future(() async {
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
final resp = await client.get('/sphere/chat'); final resp = await client.get('/messager/chat');
final remoteRooms = resp.data final remoteRooms = resp.data
.map((e) => SnChatRoom.fromJson(e)) .map((e) => SnChatRoom.fromJson(e))
.cast<SnChatRoom>() .cast<SnChatRoom>()
@@ -122,7 +122,7 @@ class ChatRoomJoinedNotifier extends _$ChatRoomJoinedNotifier {
// Fallback to API // Fallback to API
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat'); final resp = await client.get('/messager/chat');
final rooms = resp.data final rooms = resp.data
.map((e) => SnChatRoom.fromJson(e)) .map((e) => SnChatRoom.fromJson(e))
.cast<SnChatRoom>() .cast<SnChatRoom>()
@@ -306,7 +306,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
Future(() async { Future(() async {
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
final resp = await client.get('/sphere/chat/$identifier'); final resp = await client.get('/messager/chat/$identifier');
final remoteRoom = SnChatRoom.fromJson(resp.data); final remoteRoom = SnChatRoom.fromJson(resp.data);
// Update state with fresh data directly without saving to DB // Update state with fresh data directly without saving to DB
// DB will be updated by ChatRoomJoinedNotifier's full sync // DB will be updated by ChatRoomJoinedNotifier's full sync
@@ -321,7 +321,7 @@ class ChatRoomNotifier extends _$ChatRoomNotifier {
// Fallback to API // 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('/messager/chat/$identifier');
final room = SnChatRoom.fromJson(resp.data); final room = SnChatRoom.fromJson(resp.data);
await db.saveChatRooms([room]); await db.saveChatRooms([room]);
return room; return room;
@@ -375,7 +375,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
final resp = await client.get( final resp = await client.get(
'/sphere/chat/$identifier/members/me', '/messager/chat/$identifier/members/me',
); );
final remoteMember = SnChatMember.fromJson(resp.data); final remoteMember = SnChatMember.fromJson(resp.data);
await db.saveMember(remoteMember); await db.saveMember(remoteMember);
@@ -396,7 +396,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
// Fallback to API // 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('/messager/chat/$identifier/members/me');
final member = SnChatMember.fromJson(resp.data); final member = SnChatMember.fromJson(resp.data);
await db.saveMember(member); await db.saveMember(member);
return member; return member;
@@ -444,7 +444,7 @@ class ChatRoomIdentityNotifier extends _$ChatRoomIdentityNotifier {
@riverpod @riverpod
Future<List<SnChatMember>> chatroomInvites(Ref ref) async { Future<List<SnChatMember>> chatroomInvites(Ref ref) async {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat/invites'); final resp = await client.get('/messager/chat/invites');
return resp.data return resp.data
.map((e) => SnChatMember.fromJson(e)) .map((e) => SnChatMember.fromJson(e))
.cast<SnChatMember>() .cast<SnChatMember>()

View File

@@ -61,7 +61,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.subscribe', type: 'messages.subscribe',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );
@@ -98,7 +98,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.subscribe', type: 'messages.subscribe',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );
@@ -116,7 +116,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.unsubscribe', type: 'messages.unsubscribe',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );
@@ -128,7 +128,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.subscribe', type: 'messages.subscribe',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );
@@ -143,7 +143,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.unsubscribe', type: 'messages.unsubscribe',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );
@@ -207,7 +207,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.read', type: 'messages.read',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );
@@ -224,7 +224,7 @@ class ChatSubscribeNotifier extends _$ChatSubscribeNotifier {
WebSocketPacket( WebSocketPacket(
type: 'messages.typing', type: 'messages.typing',
data: {'chat_room_id': roomId}, data: {'chat_room_id': roomId},
endpoint: 'sphere', endpoint: 'messager',
), ),
), ),
); );

View File

@@ -24,7 +24,7 @@ class ChatUnreadCountNotifier extends _$ChatUnreadCountNotifier {
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
final response = await client.get('/sphere/chat/unread'); final response = await client.get('/messager/chat/unread');
return (response.data as num).toInt(); return (response.data as num).toInt();
} catch (_) { } catch (_) {
return 0; return 0;
@@ -65,7 +65,7 @@ class ChatSummary extends _$ChatSummary {
@override @override
Future<Map<String, SnChatSummary>> build() async { Future<Map<String, SnChatSummary>> build() async {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
final resp = await client.get('/sphere/chat/summary'); final resp = await client.get('/messager/chat/summary');
final Map<String, dynamic> data = resp.data; final Map<String, dynamic> data = resp.data;
final summaries = data.map( final summaries = data.map(

View File

@@ -281,7 +281,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', '/messager/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');
@@ -293,7 +293,7 @@ class MessagesNotifier extends _$MessagesNotifier {
} }
final response = await _apiClient.get( final response = await _apiClient.get(
'/sphere/chat/$roomId/messages', '/messager/chat/$roomId/messages',
queryParameters: {'offset': offset, 'take': take}, queryParameters: {'offset': offset, 'take': take},
); );
@@ -373,7 +373,7 @@ class MessagesNotifier extends _$MessagesNotifier {
do { do {
final resp = await _apiClient.post( final resp = await _apiClient.post(
'/sphere/chat/${_room.id}/sync', '/messager/chat/${_room.id}/sync',
data: {'last_sync_timestamp': lastSyncTimestamp}, data: {'last_sync_timestamp': lastSyncTimestamp},
); );
@@ -603,8 +603,8 @@ class MessagesNotifier extends _$MessagesNotifier {
final response = await _apiClient.request( final response = await _apiClient.request(
editingTo == null editingTo == null
? '/sphere/chat/$roomId/messages' ? '/messager/chat/$roomId/messages'
: '/sphere/chat/$roomId/messages/${editingTo.id}', : '/messager/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(),
@@ -688,7 +688,7 @@ class MessagesNotifier extends _$MessagesNotifier {
try { try {
var remoteMessage = message.toRemoteMessage(); var remoteMessage = message.toRemoteMessage();
final response = await _apiClient.post( final response = await _apiClient.post(
'/sphere/chat/${message.roomId}/messages', '/messager/chat/${message.roomId}/messages',
data: { data: {
'content': remoteMessage.content, 'content': remoteMessage.content,
'attachments_id': remoteMessage.attachments, 'attachments_id': remoteMessage.attachments,
@@ -925,7 +925,7 @@ class MessagesNotifier extends _$MessagesNotifier {
} }
try { try {
await _apiClient.delete('/sphere/chat/$roomId/messages/$messageId'); await _apiClient.delete('/messager/chat/$roomId/messages/$messageId');
await receiveMessageDeletion(messageId); await receiveMessageDeletion(messageId);
} catch (err, stackTrace) { } catch (err, stackTrace) {
talker.log( talker.log(
@@ -1033,7 +1033,7 @@ class MessagesNotifier extends _$MessagesNotifier {
} }
final response = await _apiClient.get( final response = await _apiClient.get(
'/sphere/chat/$roomId/messages/$messageId', '/messager/chat/$roomId/messages/$messageId',
); );
final remoteMessage = SnChatMessage.fromJson(response.data); final remoteMessage = SnChatMessage.fromJson(response.data);
final message = LocalChatMessage.fromRemoteMessage( final message = LocalChatMessage.fromRemoteMessage(

View File

@@ -678,7 +678,7 @@ Future<SnChatRoom?> accountDirectChat(Ref ref, String uname) async {
final account = await ref.watch(accountProvider(uname).future); final account = await ref.watch(accountProvider(uname).future);
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
try { try {
final resp = await apiClient.get("/sphere/chat/direct/${account.id}"); final resp = await apiClient.get("/messager/chat/direct/${account.id}");
return SnChatRoom.fromJson(resp.data); return SnChatRoom.fromJson(resp.data);
} catch (err) { } catch (err) {
if (err is DioException && err.response?.statusCode == 404) { if (err is DioException && err.response?.statusCode == 404) {
@@ -807,7 +807,7 @@ class AccountProfileScreen extends HookConsumerWidget {
try { try {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
final resp = await client.post( final resp = await client.post(
'/sphere/chat/direct', '/messager/chat/direct',
data: {'related_user_id': account.value!.id}, data: {'related_user_id': account.value!.id},
); );
final chat = SnChatRoom.fromJson(resp.data); final chat = SnChatRoom.fromJson(resp.data);

View File

@@ -505,7 +505,7 @@ class ChatListScreen extends HookConsumerWidget {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
try { try {
await client.post( await client.post(
'/sphere/chat/direct', '/messager/chat/direct',
data: {'related_user_id': result.id}, data: {'related_user_id': result.id},
); );
eventBus.fire(const ChatRoomsRefreshEvent()); eventBus.fire(const ChatRoomsRefreshEvent());
@@ -622,7 +622,9 @@ class _ChatInvitesSheet extends HookConsumerWidget {
Future<void> acceptInvite(SnChatMember invite) async { Future<void> acceptInvite(SnChatMember invite) async {
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
await client.post('/sphere/chat/invites/${invite.chatRoom!.id}/accept'); await client.post(
'/messager/chat/invites/${invite.chatRoom!.id}/accept',
);
ref.invalidate(chatroomInvitesProvider); ref.invalidate(chatroomInvitesProvider);
ref.invalidate(chatRoomJoinedProvider); ref.invalidate(chatRoomJoinedProvider);
} catch (err) { } catch (err) {
@@ -634,7 +636,7 @@ class _ChatInvitesSheet extends HookConsumerWidget {
try { try {
final client = ref.read(apiClientProvider); final client = ref.read(apiClientProvider);
await client.post( await client.post(
'/sphere/chat/invites/${invite.chatRoom!.id}/decline', '/messager/chat/invites/${invite.chatRoom!.id}/decline',
); );
ref.invalidate(chatroomInvitesProvider); ref.invalidate(chatroomInvitesProvider);
} catch (err) { } catch (err) {

View File

@@ -97,13 +97,9 @@ class EditChatScreen extends HookConsumerWidget {
submitting.value = true; submitting.value = true;
try { try {
final cloudFile = final cloudFile = await FileUploader.createCloudFile(
await FileUploader.createCloudFile(
ref: ref, ref: ref,
fileData: UniversalFile( fileData: UniversalFile(data: result, type: UniversalFileType.image),
data: result,
type: UniversalFileType.image,
),
).future; ).future;
if (cloudFile == null) { if (cloudFile == null) {
throw ArgumentError('Failed to upload the file...'); throw ArgumentError('Failed to upload the file...');
@@ -129,7 +125,7 @@ class EditChatScreen extends HookConsumerWidget {
try { try {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
final resp = await client.request( final resp = await client.request(
id == null ? '/sphere/chat' : '/sphere/chat/$id', id == null ? '/messager/chat' : '/messager/chat/$id',
data: { data: {
'name': nameController.text, 'name': nameController.text,
'description': descriptionController.text, 'description': descriptionController.text,
@@ -166,8 +162,7 @@ class EditChatScreen extends HookConsumerWidget {
GestureDetector( GestureDetector(
child: Container( child: Container(
color: Theme.of(context).colorScheme.surfaceContainerHigh, color: Theme.of(context).colorScheme.surfaceContainerHigh,
child: child: background.value != null
background.value != null
? CloudFileWidget( ? CloudFileWidget(
item: background.value!, item: background.value!,
fit: BoxFit.cover, fit: BoxFit.cover,
@@ -208,8 +203,8 @@ class EditChatScreen extends HookConsumerWidget {
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
), ),
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
TextFormField( TextFormField(
@@ -223,8 +218,8 @@ class EditChatScreen extends HookConsumerWidget {
), ),
minLines: 3, minLines: 3,
maxLines: null, maxLines: null,
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(), FocusManager.instance.primaryFocus?.unfocus(),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
DropdownButtonFormField<SnRealm>( DropdownButtonFormField<SnRealm>(
@@ -241,8 +236,7 @@ class EditChatScreen extends HookConsumerWidget {
child: Text('none'.tr()), child: Text('none'.tr()),
), ),
...joinedRealms.maybeWhen( ...joinedRealms.maybeWhen(
data: data: (realms) => realms.map(
(realms) => realms.map(
(realm) => DropdownMenuItem( (realm) => DropdownMenuItem(
value: realm, value: realm,
child: Text(realm.name), child: Text(realm.name),
@@ -251,8 +245,7 @@ class EditChatScreen extends HookConsumerWidget {
orElse: () => [], orElse: () => [],
), ),
], ],
onChanged: onChanged: joinedRealms.isLoading
joinedRealms.isLoading
? null ? null
: (SnRealm? value) { : (SnRealm? value) {
currentRealm.value = value; currentRealm.value = value;

View File

@@ -65,8 +65,9 @@ class PublicRoomPreview extends HookConsumerWidget {
extentEstimation: (_, _) => 40, extentEstimation: (_, _) => 40,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final message = messageList[index]; final message = messageList[index];
final nextMessage = final nextMessage = index < messageList.length - 1
index < messageList.length - 1 ? messageList[index + 1] : null; ? messageList[index + 1]
: null;
final isLastInGroup = final isLastInGroup =
nextMessage == null || nextMessage == null ||
nextMessage.senderId != message.senderId || nextMessage.senderId != message.senderId ||
@@ -97,11 +98,9 @@ class PublicRoomPreview extends HookConsumerWidget {
SizedBox( SizedBox(
height: 26, height: 26,
width: 26, width: 26,
child: child: (room.type == 1 && room.picture?.id == null)
(room.type == 1 && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: room.members!
room.members!
.map((e) => e.account.profile.picture?.id) .map((e) => e.account.profile.picture?.id)
.toList(), .toList(),
) )
@@ -132,11 +131,9 @@ class PublicRoomPreview extends HookConsumerWidget {
SizedBox( SizedBox(
height: 26, height: 26,
width: 26, width: 26,
child: child: (room.type == 1 && room.picture?.id == null)
(room.type == 1 && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: room.members!
room.members!
.map((e) => e.account.profile.picture?.id) .map((e) => e.account.profile.picture?.id)
.toList(), .toList(),
) )
@@ -181,14 +178,11 @@ class PublicRoomPreview extends HookConsumerWidget {
children: [ children: [
Expanded( Expanded(
child: messages.when( child: messages.when(
data: data: (messageList) => messageList.isEmpty
(messageList) =>
messageList.isEmpty
? Center(child: Text('No messages yet'.tr())) ? Center(child: Text('No messages yet'.tr()))
: chatMessageListWidget(messageList), : chatMessageListWidget(messageList),
loading: () => const Center(child: CircularProgressIndicator()), loading: () => const Center(child: CircularProgressIndicator()),
error: error: (error, _) => ResponseErrorWidget(
(error, _) => ResponseErrorWidget(
error: error, error: error,
onRetry: () => messagesNotifier.loadInitial(), onRetry: () => messagesNotifier.loadInitial(),
), ),
@@ -202,7 +196,7 @@ class PublicRoomPreview extends HookConsumerWidget {
try { try {
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('/messager/chat/${room.id}/members/me');
ref.invalidate(chatRoomIdentityProvider(id)); ref.invalidate(chatRoomIdentityProvider(id));
} catch (err) { } catch (err) {
showErrorAlert(err); showErrorAlert(err);

View File

@@ -71,8 +71,7 @@ class ChatRoomScreen extends HookConsumerWidget {
return AppScaffold( return AppScaffold(
appBar: AppBar(leading: const PageBackButton()), appBar: AppBar(leading: const PageBackButton()),
body: Center( body: Center(
child: child: ConstrainedBox(
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 280), constraints: const BoxConstraints(maxWidth: 280),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
@@ -98,7 +97,7 @@ class ChatRoomScreen extends HookConsumerWidget {
showLoadingModal(context); showLoadingModal(context);
final apiClient = ref.read(apiClientProvider); final apiClient = ref.read(apiClientProvider);
await apiClient.post( await apiClient.post(
'/sphere/chat/${room.id}/members/me', '/messager/chat/${room.id}/members/me',
); );
ref.invalidate(chatRoomIdentityProvider(id)); ref.invalidate(chatRoomIdentityProvider(id));
} catch (err) { } catch (err) {
@@ -119,13 +118,11 @@ class ChatRoomScreen extends HookConsumerWidget {
); );
} }
}, },
loading: loading: () => AppScaffold(
() => AppScaffold(
appBar: AppBar(leading: const PageBackButton()), appBar: AppBar(leading: const PageBackButton()),
body: CircularProgressIndicator().center(), body: CircularProgressIndicator().center(),
), ),
error: error: (error, _) => AppScaffold(
(error, _) => AppScaffold(
appBar: AppBar(leading: const PageBackButton()), appBar: AppBar(leading: const PageBackButton()),
body: ResponseErrorWidget( body: ResponseErrorWidget(
error: error, error: error,
@@ -186,8 +183,7 @@ class ChatRoomScreen extends HookConsumerWidget {
case MessageItemAction.edit: case MessageItemAction.edit:
messageEditingTo.value = message.toRemoteMessage(); messageEditingTo.value = message.toRemoteMessage();
messageController.text = messageEditingTo.value?.content ?? ''; messageController.text = messageEditingTo.value?.content ?? '';
attachments.value = attachments.value = messageEditingTo.value!.attachments
messageEditingTo.value!.attachments
.map((e) => UniversalFile.fromAttachment(e)) .map((e) => UniversalFile.fromAttachment(e))
.toList(); .toList();
case MessageItemAction.forward: case MessageItemAction.forward:
@@ -424,17 +420,16 @@ class ChatRoomScreen extends HookConsumerWidget {
label: Text('${(onlineCount.value ?? 0)}'), label: Text('${(onlineCount.value ?? 0)}'),
textStyle: GoogleFonts.robotoMono(fontSize: 10), textStyle: GoogleFonts.robotoMono(fontSize: 10),
textColor: Colors.white, textColor: Colors.white,
backgroundColor: backgroundColor: (onlineCount.value ?? 0) > 1
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey, ? Colors.green
: Colors.grey,
offset: Offset(6, 14), offset: Offset(6, 14),
child: SizedBox( child: SizedBox(
height: 26, height: 26,
width: 26, width: 26,
child: child: (room!.type == 1 && room.picture?.id == null)
(room!.type == 1 && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: getValidMembers(
getValidMembers(
room.members!, room.members!,
).map((e) => e.account.profile.picture?.id).toList(), ).map((e) => e.account.profile.picture?.id).toList(),
) )
@@ -470,18 +465,17 @@ class ChatRoomScreen extends HookConsumerWidget {
isLabelVisible: (onlineCount.value ?? 0) > 1, isLabelVisible: (onlineCount.value ?? 0) > 1,
label: Text('${(onlineCount.value ?? 0)}'), label: Text('${(onlineCount.value ?? 0)}'),
textStyle: GoogleFonts.robotoMono(fontSize: 10), textStyle: GoogleFonts.robotoMono(fontSize: 10),
backgroundColor: backgroundColor: (onlineCount.value ?? 0) > 1
(onlineCount.value ?? 0) > 1 ? Colors.green : Colors.grey, ? Colors.green
: Colors.grey,
textColor: Colors.white, textColor: Colors.white,
offset: Offset(6, 14), offset: Offset(6, 14),
child: SizedBox( child: SizedBox(
height: 28, height: 28,
width: 28, width: 28,
child: child: (room!.type == 1 && room.picture?.id == null)
(room!.type == 1 && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: getValidMembers(
getValidMembers(
room.members!, room.members!,
).map((e) => e.account.profile.picture?.id).toList(), ).map((e) => e.account.profile.picture?.id).toList(),
) )
@@ -531,10 +525,8 @@ class ChatRoomScreen extends HookConsumerWidget {
index: index, index: index,
scrollController: scrollController, scrollController: scrollController,
alignment: 0.5, alignment: 0.5,
duration: duration: (estimatedDistance) => Duration(
(estimatedDistance) => Duration( milliseconds: (estimatedDistance * 0.5).clamp(200, 800).toInt(),
milliseconds:
(estimatedDistance * 0.5).clamp(200, 800).toInt(),
), ),
curve: (estimatedDistance) => Curves.easeOutCubic, curve: (estimatedDistance) => Curves.easeOutCubic,
); );
@@ -605,8 +597,7 @@ class ChatRoomScreen extends HookConsumerWidget {
final config = await showModalBottomSheet<AttachmentUploadConfig>( final config = await showModalBottomSheet<AttachmentUploadConfig>(
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
builder: builder: (context) => AttachmentUploaderSheet(
(context) => AttachmentUploaderSheet(
ref: ref, ref: ref,
attachments: attachments.value, attachments: attachments.value,
index: index, index: index,
@@ -621,13 +612,11 @@ class ChatRoomScreen extends HookConsumerWidget {
'chat-upload': {index: 0}, 'chat-upload': {index: 0},
}; };
final cloudFile = final cloudFile = await FileUploader.createCloudFile(
await FileUploader.createCloudFile(
ref: ref, ref: ref,
fileData: attachment, fileData: attachment,
poolId: config.poolId, poolId: config.poolId,
mode: mode: attachment.type == UniversalFileType.file
attachment.type == UniversalFileType.file
? FileUploadMode.generic ? FileUploadMode.generic
: FileUploadMode.mediaSafe, : FileUploadMode.mediaSafe,
onProgress: (progress, _) { onProgress: (progress, _) {
@@ -690,8 +679,7 @@ class ChatRoomScreen extends HookConsumerWidget {
extentEstimation: (_, _) => 40, extentEstimation: (_, _) => 40,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final message = messageList[index]; final message = messageList[index];
final nextMessage = final nextMessage = index < messageList.length - 1
index < messageList.length - 1
? messageList[index + 1] ? messageList[index + 1]
: null; : null;
final isLastInGroup = final isLastInGroup =
@@ -718,8 +706,7 @@ class ChatRoomScreen extends HookConsumerWidget {
toggleSelectionMode: toggleSelectionMode, toggleSelectionMode: toggleSelectionMode,
toggleMessageSelection: toggleMessageSelection, toggleMessageSelection: toggleMessageSelection,
onMessageAction: onMessageAction, onMessageAction: onMessageAction,
onJump: onJump: (messageId) => scrollToMessage(
(messageId) => scrollToMessage(
messageId: messageId, messageId: messageId,
messageList: messageList, messageList: messageList,
messagesNotifier: messagesNotifier, messagesNotifier: messagesNotifier,
@@ -744,14 +731,11 @@ class ChatRoomScreen extends HookConsumerWidget {
automaticallyImplyLeading: false, automaticallyImplyLeading: false,
toolbarHeight: compactHeader ? null : 74, toolbarHeight: compactHeader ? null : 74,
title: chatRoom.when( title: chatRoom.when(
data: data: (room) => compactHeader
(room) =>
compactHeader
? compactHeaderWidget(room) ? compactHeaderWidget(room)
: comfortHeaderWidget(room), : comfortHeaderWidget(room),
loading: () => const Text('Loading...'), loading: () => const Text('Loading...'),
error: error: (err, _) => ResponseErrorWidget(
(err, _) => ResponseErrorWidget(
error: err, error: err,
onRetry: () => messagesNotifier.loadInitial(), onRetry: () => messagesNotifier.loadInitial(),
), ),
@@ -787,10 +771,8 @@ class ChatRoomScreen extends HookConsumerWidget {
index: index, index: index,
scrollController: scrollController, scrollController: scrollController,
alignment: 0.5, alignment: 0.5,
duration: duration: (estimatedDistance) => Duration(
(estimatedDistance) => Duration( milliseconds: (estimatedDistance * 0.5)
milliseconds:
(estimatedDistance * 0.5)
.clamp(200, 800) .clamp(200, 800)
.toInt(), .toInt(),
), ),
@@ -819,34 +801,31 @@ class ChatRoomScreen extends HookConsumerWidget {
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
switchInCurve: Curves.easeOutCubic, switchInCurve: Curves.easeOutCubic,
switchOutCurve: Curves.easeInCubic, switchOutCurve: Curves.easeInCubic,
transitionBuilder: ( transitionBuilder:
Widget child, (Widget child, Animation<double> animation) {
Animation<double> animation,
) {
return SlideTransition( return SlideTransition(
position: Tween<Offset>( position: Tween<Offset>(
begin: const Offset(0, 0.05), begin: const Offset(0, 0.05),
end: Offset.zero, end: Offset.zero,
).animate(animation), ).animate(animation),
child: FadeTransition(opacity: animation, child: child), child: FadeTransition(
opacity: animation,
child: child,
),
); );
}, },
child: messages.when( child: messages.when(
data: data: (messageList) => messageList.isEmpty
(messageList) =>
messageList.isEmpty
? Center( ? Center(
key: const ValueKey('empty-messages'), key: const ValueKey('empty-messages'),
child: Text('No messages yet'.tr()), child: Text('No messages yet'.tr()),
) )
: chatMessageListWidget(messageList), : chatMessageListWidget(messageList),
loading: loading: () => const Center(
() => const Center(
key: ValueKey('loading-messages'), key: ValueKey('loading-messages'),
child: CircularProgressIndicator(), child: CircularProgressIndicator(),
), ),
error: error: (error, _) => ResponseErrorWidget(
(error, _) => ResponseErrorWidget(
key: const ValueKey('error-messages'), key: const ValueKey('error-messages'),
error: error, error: error,
onRetry: () => messagesNotifier.loadInitial(), onRetry: () => messagesNotifier.loadInitial(),
@@ -862,10 +841,8 @@ class ChatRoomScreen extends HookConsumerWidget {
right: 0, right: 0,
top: 0, top: 0,
child: chatRoom.when( child: chatRoom.when(
data: data: (data) =>
(data) => CallOverlayBar( CallOverlayBar(room: data!).padding(horizontal: 8, top: 12),
room: data!,
).padding(horizontal: 8, top: 12),
error: (_, _) => const SizedBox.shrink(), error: (_, _) => const SizedBox.shrink(),
loading: () => const SizedBox.shrink(), loading: () => const SizedBox.shrink(),
), ),
@@ -903,8 +880,7 @@ class ChatRoomScreen extends HookConsumerWidget {
if (!isSelectionMode.value) if (!isSelectionMode.value)
AnimatedBuilder( AnimatedBuilder(
animation: bottomGradientNotifier.value, animation: bottomGradientNotifier.value,
builder: builder: (context, child) => Positioned(
(context, child) => Positioned(
left: 0, left: 0,
right: 0, right: 0,
bottom: 0, bottom: 0,
@@ -940,8 +916,7 @@ class ChatRoomScreen extends HookConsumerWidget {
right: 0, right: 0,
bottom: 0, // At the very bottom, above gradient bottom: 0, // At the very bottom, above gradient
child: chatRoom.when( child: chatRoom.when(
data: data: (room) => Column(
(room) => Column(
key: inputKey, key: inputKey,
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [

View File

@@ -67,7 +67,7 @@ class ChatDetailScreen extends HookConsumerWidget {
try { try {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
await client.patch( await client.patch(
'/sphere/chat/$id/members/me/notify', '/messager/chat/$id/members/me/notify',
data: {'notify_level': level}, data: {'notify_level': level},
); );
ref.invalidate(chatRoomIdentityProvider(id)); ref.invalidate(chatRoomIdentityProvider(id));
@@ -85,7 +85,7 @@ class ChatDetailScreen extends HookConsumerWidget {
try { try {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
await client.patch( await client.patch(
'/sphere/chat/$id/members/me/notify', '/messager/chat/$id/members/me/notify',
data: {'break_until': until.toUtc().toIso8601String()}, data: {'break_until': until.toUtc().toIso8601String()},
); );
ref.invalidate(chatRoomIdentityProvider(id)); ref.invalidate(chatRoomIdentityProvider(id));
@@ -529,7 +529,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
).then((confirm) async { ).then((confirm) async {
if (confirm) { if (confirm) {
final client = ref.watch(apiClientProvider); final client = ref.watch(apiClientProvider);
await client.delete('/sphere/chat/$id'); await client.delete('/messager/chat/$id');
ref.invalidate(chatRoomJoinedProvider); ref.invalidate(chatRoomJoinedProvider);
if (context.mounted) { if (context.mounted) {
context.pop(); context.pop();
@@ -560,7 +560,7 @@ class _ChatRoomActionMenu extends HookConsumerWidget {
).then((confirm) async { ).then((confirm) async {
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('/messager/chat/$id/members/me');
ref.invalidate(chatRoomJoinedProvider); ref.invalidate(chatRoomJoinedProvider);
if (context.mounted) { if (context.mounted) {
context.pop(); context.pop();
@@ -600,7 +600,7 @@ class ChatMemberListNotifier
Future<List<SnChatMember>> fetch() async { Future<List<SnChatMember>> fetch() async {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
final response = await apiClient.get( final response = await apiClient.get(
'/sphere/chat/$arg/members', '/messager/chat/$arg/members',
queryParameters: { queryParameters: {
'offset': fetchedCount.toString(), 'offset': fetchedCount.toString(),
'take': pageSize, 'take': pageSize,
@@ -645,7 +645,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
try { try {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
await apiClient.post( await apiClient.post(
'/sphere/chat/invites/$roomId', '/messager/chat/invites/$roomId',
data: {'related_user_id': result.id, 'role': 0}, data: {'related_user_id': result.id, 'role': 0},
); );
memberNotifier.refresh(); memberNotifier.refresh();
@@ -735,7 +735,7 @@ class _ChatMemberListSheet extends HookConsumerWidget {
try { try {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
await apiClient.delete( await apiClient.delete(
'/sphere/chat/$roomId/members/${member.accountId}', '/messager/chat/$roomId/members/${member.accountId}',
); );
// Refresh both providers // Refresh both providers
memberNotifier.refresh(); memberNotifier.refresh();

View File

@@ -18,7 +18,7 @@ class AutocompleteService {
String content, String content,
) async { ) async {
final response = await _client.post( final response = await _client.post(
'/sphere/chat/$roomId/autocomplete', '/messager/chat/$roomId/autocomplete',
data: {'content': content}, data: {'content': content},
); );

View File

@@ -16,7 +16,7 @@ Future<SnRealtimeCall?> ongoingCall(Ref ref, String roomId) async {
if (roomId.isEmpty) return null; if (roomId.isEmpty) return null;
try { try {
final apiClient = ref.watch(apiClientProvider); final apiClient = ref.watch(apiClientProvider);
final resp = await apiClient.get('/sphere/chat/realtime/$roomId'); final resp = await apiClient.get('/messager/chat/realtime/$roomId');
return SnRealtimeCall.fromJson(resp.data); return SnRealtimeCall.fromJson(resp.data);
} catch (e) { } catch (e) {
if (e is DioException && e.response?.statusCode == 404) { if (e is DioException && e.response?.statusCode == 404) {
@@ -42,7 +42,7 @@ class AudioCallButton extends HookConsumerWidget {
Future<void> handleJoin() async { Future<void> handleJoin() async {
isLoading.value = true; isLoading.value = true;
try { try {
await apiClient.post('/sphere/chat/realtime/${room.id}'); await apiClient.post('/messager/chat/realtime/${room.id}');
ref.invalidate(ongoingCallProvider(room.id)); ref.invalidate(ongoingCallProvider(room.id));
// Just join the room, the overlay will handle the UI // Just join the room, the overlay will handle the UI
await callNotifier.joinRoom(room); await callNotifier.joinRoom(room);
@@ -56,7 +56,7 @@ class AudioCallButton extends HookConsumerWidget {
Future<void> handleEnd() async { Future<void> handleEnd() async {
isLoading.value = true; isLoading.value = true;
try { try {
await apiClient.delete('/sphere/chat/realtime/${room.id}'); await apiClient.delete('/messager/chat/realtime/${room.id}');
callNotifier.dispose(); // Clean up call resources callNotifier.dispose(); // Clean up call resources
} catch (e) { } catch (e) {
showErrorAlert(e); showErrorAlert(e);

View File

@@ -117,7 +117,7 @@ class CallControlsBar extends HookConsumerWidget {
try { try {
showLoadingModal(context); showLoadingModal(context);
await apiClient.delete( await apiClient.delete(
'/sphere/chat/realtime/${callNotifier.roomId}', '/messager/chat/realtime/${callNotifier.roomId}',
); );
callNotifier.dispose(); callNotifier.dispose();
if (context.mounted && popOnLeaves) { if (context.mounted && popOnLeaves) {

View File

@@ -66,8 +66,9 @@ class PublicRoomPreview extends HookConsumerWidget {
extentEstimation: (_, _) => 40, extentEstimation: (_, _) => 40,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final message = messageList[index]; final message = messageList[index];
final nextMessage = final nextMessage = index < messageList.length - 1
index < messageList.length - 1 ? messageList[index + 1] : null; ? messageList[index + 1]
: null;
final isLastInGroup = final isLastInGroup =
nextMessage == null || nextMessage == null ||
nextMessage.senderId != message.senderId || nextMessage.senderId != message.senderId ||
@@ -98,11 +99,9 @@ class PublicRoomPreview extends HookConsumerWidget {
SizedBox( SizedBox(
height: 26, height: 26,
width: 26, width: 26,
child: child: (room.type == 1 && room.picture?.id == null)
(room.type == 1 && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: room.members!
room.members!
.map((e) => e.account.profile.picture?.id) .map((e) => e.account.profile.picture?.id)
.toList(), .toList(),
) )
@@ -133,11 +132,9 @@ class PublicRoomPreview extends HookConsumerWidget {
SizedBox( SizedBox(
height: 26, height: 26,
width: 26, width: 26,
child: child: (room.type == 1 && room.picture?.id == null)
(room.type == 1 && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: room.members!
room.members!
.map((e) => e.account.profile.picture?.id) .map((e) => e.account.profile.picture?.id)
.toList(), .toList(),
) )
@@ -182,14 +179,11 @@ class PublicRoomPreview extends HookConsumerWidget {
children: [ children: [
Expanded( Expanded(
child: messages.when( child: messages.when(
data: data: (messageList) => messageList.isEmpty
(messageList) =>
messageList.isEmpty
? Center(child: Text('No messages yet'.tr())) ? Center(child: Text('No messages yet'.tr()))
: chatMessageListWidget(messageList), : chatMessageListWidget(messageList),
loading: () => const Center(child: CircularProgressIndicator()), loading: () => const Center(child: CircularProgressIndicator()),
error: error: (error, _) => ResponseErrorWidget(
(error, _) => ResponseErrorWidget(
error: error, error: error,
onRetry: () => messagesNotifier.loadInitial(), onRetry: () => messagesNotifier.loadInitial(),
), ),
@@ -203,7 +197,7 @@ class PublicRoomPreview extends HookConsumerWidget {
try { try {
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('/messager/chat/${room.id}/members/me');
ref.invalidate(chatRoomIdentityProvider(id)); ref.invalidate(chatRoomIdentityProvider(id));
} catch (err) { } catch (err) {
showErrorAlert(err); showErrorAlert(err);

View File

@@ -218,8 +218,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
case ShareContentType.file: case ShareContentType.file:
// Upload files to cloud storage // Upload files to cloud storage
if (widget.content.files?.isNotEmpty == true) { if (widget.content.files?.isNotEmpty == true) {
final universalFiles = final universalFiles = widget.content.files!.map((file) {
widget.content.files!.map((file) {
UniversalFileType fileType; UniversalFileType fileType;
if (file.mimeType?.startsWith('image/') == true) { if (file.mimeType?.startsWith('image/') == true) {
fileType = UniversalFileType.image; fileType = UniversalFileType.image;
@@ -243,15 +242,13 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
// Upload each file // Upload each file
for (var idx = 0; idx < universalFiles.length; idx++) { for (var idx = 0; idx < universalFiles.length; idx++) {
final file = universalFiles[idx]; final file = universalFiles[idx];
final cloudFile = final cloudFile = await FileUploader.createCloudFile(
await FileUploader.createCloudFile(
ref: ref, ref: ref,
fileData: file, fileData: file,
onProgress: (progress, _) { onProgress: (progress, _) {
if (mounted) { if (mounted) {
setState(() { setState(() {
_fileUploadProgress[messageId]?[idx] = _fileUploadProgress[messageId]?[idx] = progress ?? 0.0;
progress ?? 0.0;
}); });
} }
}, },
@@ -272,7 +269,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
// Send message to chat room // Send message to chat room
await apiClient.post( await apiClient.post(
'/sphere/chat/${chatRoom.id}/messages', '/messager/chat/${chatRoom.id}/messages',
data: {'content': content, 'attachments_id': attachmentIds, 'meta': {}}, data: {'content': content, 'attachments_id': attachmentIds, 'meta': {}},
); );
@@ -359,8 +356,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
setState(() => _isLoading = true); setState(() => _isLoading = true);
try { try {
final universalFiles = final universalFiles = widget.content.files!.map((file) {
widget.content.files!.map((file) {
UniversalFileType fileType; UniversalFileType fileType;
if (file.mimeType?.startsWith('image/') == true) { if (file.mimeType?.startsWith('image/') == true) {
fileType = UniversalFileType.image; fileType = UniversalFileType.image;
@@ -383,8 +379,7 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
// Upload each file // Upload each file
for (var idx = 0; idx < universalFiles.length; idx++) { for (var idx = 0; idx < universalFiles.length; idx++) {
final file = universalFiles[idx]; final file = universalFiles[idx];
final cloudFile = final cloudFile = await FileUploader.createCloudFile(
await FileUploader.createCloudFile(
ref: ref, ref: ref,
fileData: file, fileData: file,
onProgress: (progress, _) { onProgress: (progress, _) {
@@ -481,8 +476,9 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
margin: const EdgeInsets.all(16), margin: const EdgeInsets.all(16),
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: Theme.of(
Theme.of(context).colorScheme.surfaceContainerHighest, context,
).colorScheme.surfaceContainerHighest,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: Column( child: Column(
@@ -490,11 +486,11 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
children: [ children: [
Text( Text(
'contentToShare'.tr(), 'contentToShare'.tr(),
style: Theme.of( style: Theme.of(context).textTheme.labelMedium
?.copyWith(
color: Theme.of(
context, context,
).textTheme.labelMedium?.copyWith( ).colorScheme.onSurfaceVariant,
color:
Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
@@ -510,11 +506,11 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
children: [ children: [
Text( Text(
'quickActions'.tr(), 'quickActions'.tr(),
style: Theme.of( style: Theme.of(context).textTheme.titleSmall
?.copyWith(
color: Theme.of(
context, context,
).textTheme.titleSmall?.copyWith( ).colorScheme.onSurfaceVariant,
color:
Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
@@ -568,11 +564,11 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
children: [ children: [
Text( Text(
'sendToChat'.tr(), 'sendToChat'.tr(),
style: Theme.of( style: Theme.of(context).textTheme.titleSmall
?.copyWith(
color: Theme.of(
context, context,
).textTheme.titleSmall?.copyWith( ).colorScheme.onSurfaceVariant,
color:
Theme.of(context).colorScheme.onSurfaceVariant,
), ),
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
@@ -592,10 +588,8 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
vertical: 12, vertical: 12,
), ),
), ),
onTapOutside: onTapOutside: (_) =>
(_) => FocusManager.instance.primaryFocus?.unfocus(),
FocusManager.instance.primaryFocus
?.unfocus(),
maxLines: 3, maxLines: 3,
minLines: 1, minLines: 1,
enabled: !_isLoading, enabled: !_isLoading,
@@ -603,8 +597,9 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
), ),
_ChatRoomsList( _ChatRoomsList(
onChatSelected: onChatSelected: _isLoading
_isLoading ? null : _shareToSpecificChat, ? null
: _shareToSpecificChat,
), ),
], ],
), ),
@@ -627,11 +622,9 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
if (_fileUploadProgress.isNotEmpty) if (_fileUploadProgress.isNotEmpty)
..._fileUploadProgress.entries.map((entry) { ..._fileUploadProgress.entries.map((entry) {
final progress = entry.value; final progress = entry.value;
final averageProgress = final averageProgress = progress.isEmpty
progress.isEmpty
? 0.0 ? 0.0
: progress.reduce((a, b) => a + b) / : progress.reduce((a, b) => a + b) / progress.length;
progress.length;
return Column( return Column(
children: [ children: [
Text( Text(
@@ -699,15 +692,15 @@ class _ChatRoomsList extends ConsumerWidget {
final room = rooms[index]; final room = rooms[index];
return _ChatRoomOption( return _ChatRoomOption(
room: room, room: room,
onTap: onTap: onChatSelected != null
onChatSelected != null ? () => onChatSelected!(room) : null, ? () => onChatSelected!(room)
: null,
); );
}, },
), ),
); );
}, },
loading: loading: () => SizedBox(
() => SizedBox(
height: 80, height: 80,
child: Center( child: Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
@@ -716,8 +709,7 @@ class _ChatRoomsList extends ConsumerWidget {
), ),
), ),
), ),
error: error: (error, stack) => Container(
(error, stack) => Container(
height: 80, height: 80,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.errorContainer, color: Theme.of(context).colorScheme.errorContainer,
@@ -746,8 +738,7 @@ class _ChatRoomOption extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) { Widget build(BuildContext context, WidgetRef ref) {
final userInfo = ref.watch(userInfoProvider); final userInfo = ref.watch(userInfoProvider);
final validMembers = final validMembers = (room.members ?? [])
(room.members ?? [])
.where((m) => m.accountId != userInfo.value?.id) .where((m) => m.accountId != userInfo.value?.id)
.toList(); .toList();
@@ -764,8 +755,7 @@ class _ChatRoomOption extends HookConsumerWidget {
width: 72, width: 72,
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: onTap != null
onTap != null
? Theme.of(context).colorScheme.surfaceContainerHighest ? Theme.of(context).colorScheme.surfaceContainerHighest
: Theme.of( : Theme.of(
context, context,
@@ -786,11 +776,9 @@ class _ChatRoomOption extends HookConsumerWidget {
color: Theme.of(context).colorScheme.primary.withOpacity(0.1), color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
child: child: (isDirect && room.picture?.id == null)
(isDirect && room.picture?.id == null)
? SplitAvatarWidget( ? SplitAvatarWidget(
filesId: filesId: validMembers
validMembers
.map((e) => e.account.profile.picture?.id) .map((e) => e.account.profile.picture?.id)
.toList(), .toList(),
radius: 16, radius: 16,
@@ -800,18 +788,14 @@ class _ChatRoomOption extends HookConsumerWidget {
radius: 16, radius: 16,
child: Text(room.name![0].toUpperCase()), child: Text(room.name![0].toUpperCase()),
) )
: ProfilePictureWidget( : ProfilePictureWidget(fileId: room.picture?.id, radius: 16),
fileId: room.picture?.id,
radius: 16,
),
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
// Chat room name // Chat room name
Text( Text(
displayName, displayName,
style: Theme.of(context).textTheme.labelSmall?.copyWith( style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: color: onTap != null
onTap != null
? Theme.of(context).colorScheme.onSurface ? Theme.of(context).colorScheme.onSurface
: Theme.of( : Theme.of(
context, context,
@@ -847,8 +831,7 @@ class _CompactShareOption extends StatelessWidget {
width: 72, width: 72,
padding: const EdgeInsets.all(8), padding: const EdgeInsets.all(8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: onTap != null
onTap != null
? Theme.of(context).colorScheme.surfaceContainerHighest ? Theme.of(context).colorScheme.surfaceContainerHighest
: Theme.of( : Theme.of(
context, context,
@@ -864,8 +847,7 @@ class _CompactShareOption extends StatelessWidget {
Icon( Icon(
icon, icon,
size: 24, size: 24,
color: color: onTap != null
onTap != null
? Theme.of(context).colorScheme.primary ? Theme.of(context).colorScheme.primary
: Theme.of( : Theme.of(
context, context,
@@ -875,8 +857,7 @@ class _CompactShareOption extends StatelessWidget {
Text( Text(
title, title,
style: Theme.of(context).textTheme.labelSmall?.copyWith( style: Theme.of(context).textTheme.labelSmall?.copyWith(
color: color: onTap != null
onTap != null
? Theme.of(context).colorScheme.onSurface ? Theme.of(context).colorScheme.onSurface
: Theme.of( : Theme.of(
context, context,
@@ -937,8 +918,7 @@ class _LinkPreview extends ConsumerWidget {
final linkPreviewAsync = ref.watch(linkPreviewProvider(link)); final linkPreviewAsync = ref.watch(linkPreviewProvider(link));
return linkPreviewAsync.when( return linkPreviewAsync.when(
loading: loading: () => Container(
() => Container(
constraints: const BoxConstraints(maxHeight: kPreviewMaxHeight), constraints: const BoxConstraints(maxHeight: kPreviewMaxHeight),
child: Row( child: Row(
children: [ children: [
@@ -979,13 +959,13 @@ class _LinkPreview extends ConsumerWidget {
margin: const EdgeInsets.only(right: 12), margin: const EdgeInsets.only(right: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: color: Theme.of(
Theme.of(context).colorScheme.surfaceContainerHighest, context,
).colorScheme.surfaceContainerHighest,
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: child: embed.imageUrl != null
embed.imageUrl != null
? Image.network( ? Image.network(
embed.imageUrl!, embed.imageUrl!,
fit: BoxFit.cover, fit: BoxFit.cover,
@@ -1033,11 +1013,11 @@ class _LinkPreview extends ConsumerWidget {
padding: const EdgeInsets.only(top: 4), padding: const EdgeInsets.only(top: 4),
child: Text( child: Text(
embed.description!, embed.description!,
style: Theme.of( style: Theme.of(context).textTheme.bodySmall
?.copyWith(
color: Theme.of(
context, context,
).textTheme.bodySmall?.copyWith( ).colorScheme.onSurfaceVariant,
color:
Theme.of(context).colorScheme.onSurfaceVariant,
), ),
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -1231,15 +1211,13 @@ class _FilePreview extends StatelessWidget {
return Container( return Container(
width: 40, width: 40,
height: 40, height: 40,
color: color: Theme.of(
Theme.of(
context, context,
).colorScheme.surfaceVariant, ).colorScheme.surfaceVariant,
child: Icon( child: Icon(
Symbols.broken_image, Symbols.broken_image,
size: 20, size: 20,
color: color: Theme.of(
Theme.of(
context, context,
).colorScheme.onSurfaceVariant, ).colorScheme.onSurfaceVariant,
), ),
@@ -1252,15 +1230,15 @@ class _FilePreview extends StatelessWidget {
width: 40, width: 40,
height: 40, height: 40,
decoration: BoxDecoration( decoration: BoxDecoration(
color: color: Theme.of(
Theme.of(context).colorScheme.primaryContainer, context,
).colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
child: Icon( child: Icon(
_getFileIcon(file.name), _getFileIcon(file.name),
size: 20, size: 20,
color: color: Theme.of(
Theme.of(
context, context,
).colorScheme.onPrimaryContainer, ).colorScheme.onPrimaryContainer,
), ),
@@ -1281,19 +1259,16 @@ class _FilePreview extends StatelessWidget {
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.hasData) { if (snapshot.hasData) {
final size = snapshot.data!; final size = snapshot.data!;
final sizeStr = final sizeStr = size < 1024
size < 1024
? '${size}B' ? '${size}B'
: size < 1024 * 1024 : size < 1024 * 1024
? '${(size / 1024).toStringAsFixed(1)}KB' ? '${(size / 1024).toStringAsFixed(1)}KB'
: '${(size / (1024 * 1024)).toStringAsFixed(1)}MB'; : '${(size / (1024 * 1024)).toStringAsFixed(1)}MB';
return Text( return Text(
sizeStr, sizeStr,
style: Theme.of( style: Theme.of(context).textTheme.bodySmall
context, ?.copyWith(
).textTheme.bodySmall?.copyWith( color: Theme.of(
color:
Theme.of(
context, context,
).colorScheme.onSurfaceVariant, ).colorScheme.onSurfaceVariant,
), ),
@@ -1329,8 +1304,7 @@ void showShareSheet({
context: context, context: context,
isScrollControlled: true, isScrollControlled: true,
useRootNavigator: true, useRootNavigator: true,
builder: builder: (context) => ShareSheet(
(context) => ShareSheet(
content: content, content: content,
title: title, title: title,
toSystem: toSystem, toSystem: toSystem,