👽 Changes to API path since sphere no longer handle messages
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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 = [
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
@@ -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>()
|
||||||
|
|||||||
@@ -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',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -97,14 +97,10 @@ 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(data: result, type: UniversalFileType.image),
|
||||||
fileData: UniversalFile(
|
).future;
|
||||||
data: result,
|
|
||||||
type: UniversalFileType.image,
|
|
||||||
),
|
|
||||||
).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,13 +162,12 @@ 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,
|
)
|
||||||
)
|
: const SizedBox.shrink(),
|
||||||
: const SizedBox.shrink(),
|
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setPicture('background');
|
setPicture('background');
|
||||||
@@ -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,22 +236,20 @@ 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),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
orElse: () => [],
|
orElse: () => [],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onChanged:
|
onChanged: joinedRealms.isLoading
|
||||||
joinedRealms.isLoading
|
? null
|
||||||
? null
|
: (SnRealm? value) {
|
||||||
: (SnRealm? value) {
|
currentRealm.value = value;
|
||||||
currentRealm.value = value;
|
},
|
||||||
},
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Card(
|
Card(
|
||||||
|
|||||||
@@ -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,25 +98,23 @@ 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: room.members!
|
||||||
filesId:
|
.map((e) => e.account.profile.picture?.id)
|
||||||
room.members!
|
.toList(),
|
||||||
.map((e) => e.account.profile.picture?.id)
|
)
|
||||||
.toList(),
|
: room.picture?.id != null
|
||||||
)
|
? ProfilePictureWidget(
|
||||||
: room.picture?.id != null
|
fileId: room.picture?.id,
|
||||||
? ProfilePictureWidget(
|
fallbackIcon: Symbols.chat,
|
||||||
fileId: room.picture?.id,
|
)
|
||||||
fallbackIcon: Symbols.chat,
|
: CircleAvatar(
|
||||||
)
|
child: Text(
|
||||||
: CircleAvatar(
|
room.name![0].toUpperCase(),
|
||||||
child: Text(
|
style: const TextStyle(fontSize: 12),
|
||||||
room.name![0].toUpperCase(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
@@ -132,25 +131,23 @@ 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: room.members!
|
||||||
filesId:
|
.map((e) => e.account.profile.picture?.id)
|
||||||
room.members!
|
.toList(),
|
||||||
.map((e) => e.account.profile.picture?.id)
|
)
|
||||||
.toList(),
|
: room.picture?.id != null
|
||||||
)
|
? ProfilePictureWidget(
|
||||||
: room.picture?.id != null
|
fileId: room.picture?.id,
|
||||||
? ProfilePictureWidget(
|
fallbackIcon: Symbols.chat,
|
||||||
fileId: room.picture?.id,
|
)
|
||||||
fallbackIcon: Symbols.chat,
|
: CircleAvatar(
|
||||||
)
|
child: Text(
|
||||||
: CircleAvatar(
|
room.name![0].toUpperCase(),
|
||||||
child: Text(
|
style: const TextStyle(fontSize: 12),
|
||||||
room.name![0].toUpperCase(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
@@ -181,17 +178,14 @@ class PublicRoomPreview extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: messages.when(
|
child: messages.when(
|
||||||
data:
|
data: (messageList) => messageList.isEmpty
|
||||||
(messageList) =>
|
? Center(child: Text('No messages yet'.tr()))
|
||||||
messageList.isEmpty
|
: chatMessageListWidget(messageList),
|
||||||
? Center(child: Text('No messages yet'.tr()))
|
|
||||||
: 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(),
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Join button at the bottom for public rooms
|
// Join button at the bottom for public rooms
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -71,67 +71,64 @@ 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,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
children: [
|
||||||
children: [
|
Icon(
|
||||||
Icon(
|
room.isCommunity == true
|
||||||
room.isCommunity == true
|
? Symbols.person_add
|
||||||
? Symbols.person_add
|
: Symbols.person_remove,
|
||||||
: Symbols.person_remove,
|
size: 36,
|
||||||
size: 36,
|
fill: 1,
|
||||||
fill: 1,
|
).padding(bottom: 4),
|
||||||
).padding(bottom: 4),
|
Text('chatNotJoined').tr(),
|
||||||
Text('chatNotJoined').tr(),
|
if (room.isCommunity != true)
|
||||||
if (room.isCommunity != true)
|
Text(
|
||||||
Text(
|
'chatUnableJoin',
|
||||||
'chatUnableJoin',
|
textAlign: TextAlign.center,
|
||||||
textAlign: TextAlign.center,
|
).tr().bold()
|
||||||
).tr().bold()
|
else
|
||||||
else
|
FilledButton.tonalIcon(
|
||||||
FilledButton.tonalIcon(
|
onPressed: () async {
|
||||||
onPressed: () async {
|
try {
|
||||||
try {
|
showLoadingModal(context);
|
||||||
showLoadingModal(context);
|
final apiClient = ref.read(apiClientProvider);
|
||||||
final apiClient = ref.read(apiClientProvider);
|
await apiClient.post(
|
||||||
await apiClient.post(
|
'/messager/chat/${room.id}/members/me',
|
||||||
'/sphere/chat/${room.id}/members/me',
|
);
|
||||||
);
|
ref.invalidate(chatRoomIdentityProvider(id));
|
||||||
ref.invalidate(chatRoomIdentityProvider(id));
|
} catch (err) {
|
||||||
} catch (err) {
|
showErrorAlert(err);
|
||||||
showErrorAlert(err);
|
} finally {
|
||||||
} finally {
|
if (context.mounted) {
|
||||||
if (context.mounted) {
|
hideLoadingModal(context);
|
||||||
hideLoadingModal(context);
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
label: Text('chatJoin').tr(),
|
||||||
label: Text('chatJoin').tr(),
|
icon: const Icon(Icons.add),
|
||||||
icon: const Icon(Icons.add),
|
).padding(top: 8),
|
||||||
).padding(top: 8),
|
],
|
||||||
],
|
),
|
||||||
),
|
).center(),
|
||||||
).center(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loading:
|
loading: () => AppScaffold(
|
||||||
() => AppScaffold(
|
appBar: AppBar(leading: const PageBackButton()),
|
||||||
appBar: AppBar(leading: const PageBackButton()),
|
body: CircularProgressIndicator().center(),
|
||||||
body: CircularProgressIndicator().center(),
|
),
|
||||||
),
|
error: (error, _) => AppScaffold(
|
||||||
error:
|
appBar: AppBar(leading: const PageBackButton()),
|
||||||
(error, _) => AppScaffold(
|
body: ResponseErrorWidget(
|
||||||
appBar: AppBar(leading: const PageBackButton()),
|
error: error,
|
||||||
body: ResponseErrorWidget(
|
onRetry: () => ref.refresh(chatRoomProvider(id)),
|
||||||
error: error,
|
),
|
||||||
onRetry: () => ref.refresh(chatRoomProvider(id)),
|
),
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,10 +183,9 @@ 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:
|
||||||
messageForwardingTo.value = message.toRemoteMessage();
|
messageForwardingTo.value = message.toRemoteMessage();
|
||||||
case MessageItemAction.reply:
|
case MessageItemAction.reply:
|
||||||
@@ -424,38 +420,37 @@ 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: getValidMembers(
|
||||||
filesId:
|
room.members!,
|
||||||
getValidMembers(
|
).map((e) => e.account.profile.picture?.id).toList(),
|
||||||
room.members!,
|
)
|
||||||
).map((e) => e.account.profile.picture?.id).toList(),
|
: room.picture?.id != null
|
||||||
)
|
? ProfilePictureWidget(
|
||||||
: room.picture?.id != null
|
fileId: room.picture?.id,
|
||||||
? ProfilePictureWidget(
|
fallbackIcon: Symbols.chat,
|
||||||
fileId: room.picture?.id,
|
)
|
||||||
fallbackIcon: Symbols.chat,
|
: CircleAvatar(
|
||||||
)
|
child: Text(
|
||||||
: CircleAvatar(
|
room.name![0].toUpperCase(),
|
||||||
child: Text(
|
style: const TextStyle(fontSize: 12),
|
||||||
room.name![0].toUpperCase(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
? getValidMembers(
|
? getValidMembers(
|
||||||
room.members!,
|
room.members!,
|
||||||
).map((e) => e.account.nick).join(', ')
|
).map((e) => e.account.nick).join(', ')
|
||||||
: room.name!,
|
: room.name!,
|
||||||
).fontSize(15),
|
).fontSize(15),
|
||||||
],
|
],
|
||||||
@@ -470,39 +465,38 @@ 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: getValidMembers(
|
||||||
filesId:
|
room.members!,
|
||||||
getValidMembers(
|
).map((e) => e.account.profile.picture?.id).toList(),
|
||||||
room.members!,
|
)
|
||||||
).map((e) => e.account.profile.picture?.id).toList(),
|
: room.picture?.id != null
|
||||||
)
|
? ProfilePictureWidget(
|
||||||
: room.picture?.id != null
|
fileId: room.picture?.id,
|
||||||
? ProfilePictureWidget(
|
fallbackIcon: Symbols.chat,
|
||||||
fileId: room.picture?.id,
|
)
|
||||||
fallbackIcon: Symbols.chat,
|
: CircleAvatar(
|
||||||
)
|
child: Text(
|
||||||
: CircleAvatar(
|
room.name![0].toUpperCase(),
|
||||||
child: Text(
|
style: const TextStyle(fontSize: 12),
|
||||||
room.name![0].toUpperCase(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
? getValidMembers(
|
? getValidMembers(
|
||||||
room.members!,
|
room.members!,
|
||||||
).map((e) => e.account.nick).join(', ')
|
).map((e) => e.account.nick).join(', ')
|
||||||
: room.name!,
|
: room.name!,
|
||||||
).fontSize(19),
|
).fontSize(19),
|
||||||
],
|
],
|
||||||
@@ -531,11 +525,9 @@ 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,12 +597,11 @@ 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,
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
if (config == null) return;
|
if (config == null) return;
|
||||||
|
|
||||||
@@ -621,22 +612,20 @@ 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: attachment.type == UniversalFileType.file
|
||||||
mode:
|
? FileUploadMode.generic
|
||||||
attachment.type == UniversalFileType.file
|
: FileUploadMode.mediaSafe,
|
||||||
? FileUploadMode.generic
|
onProgress: (progress, _) {
|
||||||
: FileUploadMode.mediaSafe,
|
attachmentProgress.value = {
|
||||||
onProgress: (progress, _) {
|
...attachmentProgress.value,
|
||||||
attachmentProgress.value = {
|
'chat-upload': {index: progress ?? 0.0},
|
||||||
...attachmentProgress.value,
|
};
|
||||||
'chat-upload': {index: progress ?? 0.0},
|
},
|
||||||
};
|
).future;
|
||||||
},
|
|
||||||
).future;
|
|
||||||
|
|
||||||
if (cloudFile == null) {
|
if (cloudFile == null) {
|
||||||
throw ArgumentError('Failed to upload the file...');
|
throw ArgumentError('Failed to upload the file...');
|
||||||
@@ -690,10 +679,9 @@ 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 =
|
||||||
nextMessage == null ||
|
nextMessage == null ||
|
||||||
nextMessage.senderId != message.senderId ||
|
nextMessage.senderId != message.senderId ||
|
||||||
@@ -718,15 +706,14 @@ 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,
|
listController: listController,
|
||||||
listController: listController,
|
scrollController: scrollController,
|
||||||
scrollController: scrollController,
|
ref: ref,
|
||||||
ref: ref,
|
),
|
||||||
),
|
|
||||||
attachmentProgress: attachmentProgress.value,
|
attachmentProgress: attachmentProgress.value,
|
||||||
disableAnimation: settings.disableAnimation,
|
disableAnimation: settings.disableAnimation,
|
||||||
roomOpenTime: roomOpenTime,
|
roomOpenTime: roomOpenTime,
|
||||||
@@ -744,17 +731,14 @@ 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) =>
|
? compactHeaderWidget(room)
|
||||||
compactHeader
|
: comfortHeaderWidget(room),
|
||||||
? compactHeaderWidget(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(),
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
chatRoom.when(
|
chatRoom.when(
|
||||||
@@ -787,13 +771,11 @@ 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:
|
.clamp(200, 800)
|
||||||
(estimatedDistance * 0.5)
|
.toInt(),
|
||||||
.clamp(200, 800)
|
),
|
||||||
.toInt(),
|
|
||||||
),
|
|
||||||
curve: (estimatedDistance) => Curves.easeOutCubic,
|
curve: (estimatedDistance) => Curves.easeOutCubic,
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -819,38 +801,35 @@ 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(
|
||||||
) {
|
position: Tween<Offset>(
|
||||||
return SlideTransition(
|
begin: const Offset(0, 0.05),
|
||||||
position: Tween<Offset>(
|
end: Offset.zero,
|
||||||
begin: const Offset(0, 0.05),
|
).animate(animation),
|
||||||
end: Offset.zero,
|
child: FadeTransition(
|
||||||
).animate(animation),
|
opacity: animation,
|
||||||
child: FadeTransition(opacity: animation, child: child),
|
child: child,
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
|
},
|
||||||
child: messages.when(
|
child: messages.when(
|
||||||
data:
|
data: (messageList) => messageList.isEmpty
|
||||||
(messageList) =>
|
? Center(
|
||||||
messageList.isEmpty
|
key: const ValueKey('empty-messages'),
|
||||||
? Center(
|
child: Text('No messages yet'.tr()),
|
||||||
key: const ValueKey('empty-messages'),
|
)
|
||||||
child: Text('No messages yet'.tr()),
|
: chatMessageListWidget(messageList),
|
||||||
)
|
loading: () => const Center(
|
||||||
: chatMessageListWidget(messageList),
|
key: ValueKey('loading-messages'),
|
||||||
loading:
|
child: CircularProgressIndicator(),
|
||||||
() => const Center(
|
),
|
||||||
key: ValueKey('loading-messages'),
|
error: (error, _) => ResponseErrorWidget(
|
||||||
child: CircularProgressIndicator(),
|
key: const ValueKey('error-messages'),
|
||||||
),
|
error: error,
|
||||||
error:
|
onRetry: () => messagesNotifier.loadInitial(),
|
||||||
(error, _) => ResponseErrorWidget(
|
),
|
||||||
key: const ValueKey('error-messages'),
|
|
||||||
error: error,
|
|
||||||
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,35 +880,34 @@ 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,
|
child: Opacity(
|
||||||
child: Opacity(
|
opacity: bottomGradientNotifier.value.value,
|
||||||
opacity: bottomGradientNotifier.value.value,
|
child: Container(
|
||||||
child: Container(
|
height: math.min(
|
||||||
height: math.min(
|
MediaQuery.of(context).size.height * 0.1,
|
||||||
MediaQuery.of(context).size.height * 0.1,
|
128,
|
||||||
128,
|
),
|
||||||
),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
gradient: LinearGradient(
|
||||||
gradient: LinearGradient(
|
begin: Alignment.bottomCenter,
|
||||||
begin: Alignment.bottomCenter,
|
end: Alignment.topCenter,
|
||||||
end: Alignment.topCenter,
|
colors: [
|
||||||
colors: [
|
Theme.of(
|
||||||
Theme.of(
|
context,
|
||||||
context,
|
).colorScheme.surfaceContainer.withOpacity(0.8),
|
||||||
).colorScheme.surfaceContainer.withOpacity(0.8),
|
Theme.of(
|
||||||
Theme.of(
|
context,
|
||||||
context,
|
).colorScheme.surfaceContainer.withOpacity(0.0),
|
||||||
).colorScheme.surfaceContainer.withOpacity(0.0),
|
],
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
// Chat Input positioned above gradient (higher z-index)
|
// Chat Input positioned above gradient (higher z-index)
|
||||||
if (!isSelectionMode.value)
|
if (!isSelectionMode.value)
|
||||||
@@ -940,74 +916,73 @@ 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: [
|
ChatInput(
|
||||||
ChatInput(
|
messageController: messageController,
|
||||||
messageController: messageController,
|
chatRoom: room!,
|
||||||
chatRoom: room!,
|
onSend: sendMessage,
|
||||||
onSend: sendMessage,
|
onClear: () {
|
||||||
onClear: () {
|
if (messageEditingTo.value != null) {
|
||||||
if (messageEditingTo.value != null) {
|
attachments.value.clear();
|
||||||
attachments.value.clear();
|
messageController.clear();
|
||||||
messageController.clear();
|
}
|
||||||
}
|
messageEditingTo.value = null;
|
||||||
messageEditingTo.value = null;
|
messageReplyingTo.value = null;
|
||||||
messageReplyingTo.value = null;
|
messageForwardingTo.value = null;
|
||||||
messageForwardingTo.value = null;
|
selectedPoll.value = null;
|
||||||
selectedPoll.value = null;
|
selectedFund.value = null;
|
||||||
selectedFund.value = null;
|
},
|
||||||
},
|
messageEditingTo: messageEditingTo.value,
|
||||||
messageEditingTo: messageEditingTo.value,
|
messageReplyingTo: messageReplyingTo.value,
|
||||||
messageReplyingTo: messageReplyingTo.value,
|
messageForwardingTo: messageForwardingTo.value,
|
||||||
messageForwardingTo: messageForwardingTo.value,
|
selectedPoll: selectedPoll.value,
|
||||||
selectedPoll: selectedPoll.value,
|
onPollSelected: (poll) => selectedPoll.value = poll,
|
||||||
onPollSelected: (poll) => selectedPoll.value = poll,
|
selectedFund: selectedFund.value,
|
||||||
selectedFund: selectedFund.value,
|
onFundSelected: (fund) => selectedFund.value = fund,
|
||||||
onFundSelected: (fund) => selectedFund.value = fund,
|
onPickFile: (bool isPhoto) {
|
||||||
onPickFile: (bool isPhoto) {
|
if (isPhoto) {
|
||||||
if (isPhoto) {
|
pickPhotoMedia();
|
||||||
pickPhotoMedia();
|
} else {
|
||||||
} else {
|
pickVideoMedia();
|
||||||
pickVideoMedia();
|
}
|
||||||
}
|
},
|
||||||
},
|
onPickAudio: pickAudioMedia,
|
||||||
onPickAudio: pickAudioMedia,
|
onPickGeneralFile: pickGeneralFile,
|
||||||
onPickGeneralFile: pickGeneralFile,
|
onLinkAttachment: linkAttachment,
|
||||||
onLinkAttachment: linkAttachment,
|
attachments: attachments.value,
|
||||||
attachments: attachments.value,
|
onUploadAttachment: uploadAttachment,
|
||||||
onUploadAttachment: uploadAttachment,
|
onDeleteAttachment: (index) async {
|
||||||
onDeleteAttachment: (index) async {
|
final attachment = attachments.value[index];
|
||||||
final attachment = attachments.value[index];
|
if (attachment.isOnCloud && !attachment.isLink) {
|
||||||
if (attachment.isOnCloud && !attachment.isLink) {
|
final client = ref.watch(apiClientProvider);
|
||||||
final client = ref.watch(apiClientProvider);
|
await client.delete(
|
||||||
await client.delete(
|
'/drive/files/${attachment.data.id}',
|
||||||
'/drive/files/${attachment.data.id}',
|
);
|
||||||
);
|
}
|
||||||
}
|
final clone = List.of(attachments.value);
|
||||||
final clone = List.of(attachments.value);
|
clone.removeAt(index);
|
||||||
clone.removeAt(index);
|
attachments.value = clone;
|
||||||
attachments.value = clone;
|
},
|
||||||
},
|
onMoveAttachment: (idx, delta) {
|
||||||
onMoveAttachment: (idx, delta) {
|
if (idx + delta < 0 ||
|
||||||
if (idx + delta < 0 ||
|
idx + delta >= attachments.value.length) {
|
||||||
idx + delta >= attachments.value.length) {
|
return;
|
||||||
return;
|
}
|
||||||
}
|
final clone = List.of(attachments.value);
|
||||||
final clone = List.of(attachments.value);
|
clone.insert(idx + delta, clone.removeAt(idx));
|
||||||
clone.insert(idx + delta, clone.removeAt(idx));
|
attachments.value = clone;
|
||||||
attachments.value = clone;
|
},
|
||||||
},
|
onAttachmentsChanged: (newAttachments) {
|
||||||
onAttachmentsChanged: (newAttachments) {
|
attachments.value = newAttachments;
|
||||||
attachments.value = newAttachments;
|
},
|
||||||
},
|
attachmentProgress: attachmentProgress.value,
|
||||||
attachmentProgress: attachmentProgress.value,
|
|
||||||
),
|
|
||||||
Gap(MediaQuery.of(context).padding.bottom),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
Gap(MediaQuery.of(context).padding.bottom),
|
||||||
|
],
|
||||||
|
),
|
||||||
error: (_, _) => const SizedBox.shrink(),
|
error: (_, _) => const SizedBox.shrink(),
|
||||||
loading: () => const SizedBox.shrink(),
|
loading: () => const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,25 +99,23 @@ 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: room.members!
|
||||||
filesId:
|
.map((e) => e.account.profile.picture?.id)
|
||||||
room.members!
|
.toList(),
|
||||||
.map((e) => e.account.profile.picture?.id)
|
)
|
||||||
.toList(),
|
: room.picture?.id != null
|
||||||
)
|
? ProfilePictureWidget(
|
||||||
: room.picture?.id != null
|
fileId: room.picture?.id,
|
||||||
? ProfilePictureWidget(
|
fallbackIcon: Symbols.chat,
|
||||||
fileId: room.picture?.id,
|
)
|
||||||
fallbackIcon: Symbols.chat,
|
: CircleAvatar(
|
||||||
)
|
child: Text(
|
||||||
: CircleAvatar(
|
room.name![0].toUpperCase(),
|
||||||
child: Text(
|
style: const TextStyle(fontSize: 12),
|
||||||
room.name![0].toUpperCase(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
@@ -133,25 +132,23 @@ 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: room.members!
|
||||||
filesId:
|
.map((e) => e.account.profile.picture?.id)
|
||||||
room.members!
|
.toList(),
|
||||||
.map((e) => e.account.profile.picture?.id)
|
)
|
||||||
.toList(),
|
: room.picture?.id != null
|
||||||
)
|
? ProfilePictureWidget(
|
||||||
: room.picture?.id != null
|
fileId: room.picture?.id,
|
||||||
? ProfilePictureWidget(
|
fallbackIcon: Symbols.chat,
|
||||||
fileId: room.picture?.id,
|
)
|
||||||
fallbackIcon: Symbols.chat,
|
: CircleAvatar(
|
||||||
)
|
child: Text(
|
||||||
: CircleAvatar(
|
room.name![0].toUpperCase(),
|
||||||
child: Text(
|
style: const TextStyle(fontSize: 12),
|
||||||
room.name![0].toUpperCase(),
|
|
||||||
style: const TextStyle(fontSize: 12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
(room.type == 1 && room.name == null)
|
(room.type == 1 && room.name == null)
|
||||||
@@ -182,17 +179,14 @@ class PublicRoomPreview extends HookConsumerWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: messages.when(
|
child: messages.when(
|
||||||
data:
|
data: (messageList) => messageList.isEmpty
|
||||||
(messageList) =>
|
? Center(child: Text('No messages yet'.tr()))
|
||||||
messageList.isEmpty
|
: chatMessageListWidget(messageList),
|
||||||
? Center(child: Text('No messages yet'.tr()))
|
|
||||||
: 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(),
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Join button at the bottom for public rooms
|
// Join button at the bottom for public rooms
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -218,20 +218,19 @@ 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;
|
} else if (file.mimeType?.startsWith('video/') == true) {
|
||||||
} else if (file.mimeType?.startsWith('video/') == true) {
|
fileType = UniversalFileType.video;
|
||||||
fileType = UniversalFileType.video;
|
} else if (file.mimeType?.startsWith('audio/') == true) {
|
||||||
} else if (file.mimeType?.startsWith('audio/') == true) {
|
fileType = UniversalFileType.audio;
|
||||||
fileType = UniversalFileType.audio;
|
} else {
|
||||||
} else {
|
fileType = UniversalFileType.file;
|
||||||
fileType = UniversalFileType.file;
|
}
|
||||||
}
|
return UniversalFile(data: file, type: fileType);
|
||||||
return UniversalFile(data: file, type: fileType);
|
}).toList();
|
||||||
}).toList();
|
|
||||||
|
|
||||||
// Initialize progress tracking
|
// Initialize progress tracking
|
||||||
final messageId = DateTime.now().millisecondsSinceEpoch.toString();
|
final messageId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
@@ -243,19 +242,17 @@ 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] = progress ?? 0.0;
|
||||||
_fileUploadProgress[messageId]?[idx] =
|
});
|
||||||
progress ?? 0.0;
|
}
|
||||||
});
|
},
|
||||||
}
|
).future;
|
||||||
},
|
|
||||||
).future;
|
|
||||||
|
|
||||||
if (cloudFile == null) {
|
if (cloudFile == null) {
|
||||||
throw Exception('Failed to upload file: ${file.data.name}');
|
throw Exception('Failed to upload file: ${file.data.name}');
|
||||||
@@ -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,20 +356,19 @@ 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;
|
} else if (file.mimeType?.startsWith('video/') == true) {
|
||||||
} else if (file.mimeType?.startsWith('video/') == true) {
|
fileType = UniversalFileType.video;
|
||||||
fileType = UniversalFileType.video;
|
} else if (file.mimeType?.startsWith('audio/') == true) {
|
||||||
} else if (file.mimeType?.startsWith('audio/') == true) {
|
fileType = UniversalFileType.audio;
|
||||||
fileType = UniversalFileType.audio;
|
} else {
|
||||||
} else {
|
fileType = UniversalFileType.file;
|
||||||
fileType = UniversalFileType.file;
|
}
|
||||||
}
|
return UniversalFile(data: file, type: fileType);
|
||||||
return UniversalFile(data: file, type: fileType);
|
}).toList();
|
||||||
}).toList();
|
|
||||||
|
|
||||||
// Initialize progress tracking
|
// Initialize progress tracking
|
||||||
final messageId = DateTime.now().millisecondsSinceEpoch.toString();
|
final messageId = DateTime.now().millisecondsSinceEpoch.toString();
|
||||||
@@ -383,18 +379,17 @@ 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] = progress ?? 0.0;
|
||||||
_fileUploadProgress[messageId]?[idx] = progress ?? 0.0;
|
});
|
||||||
});
|
}
|
||||||
}
|
},
|
||||||
},
|
).future;
|
||||||
).future;
|
|
||||||
|
|
||||||
if (cloudFile == null) {
|
if (cloudFile == null) {
|
||||||
throw Exception('Failed to upload file: ${file.data.name}');
|
throw Exception('Failed to upload file: ${file.data.name}');
|
||||||
@@ -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,12 +486,12 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'contentToShare'.tr(),
|
'contentToShare'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.labelMedium
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.labelMedium?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
context,
|
||||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
_ContentPreview(content: widget.content),
|
_ContentPreview(content: widget.content),
|
||||||
@@ -510,12 +506,12 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'quickActions'.tr(),
|
'quickActions'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.titleSmall
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.titleSmall?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
context,
|
||||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
@@ -568,12 +564,12 @@ class _ShareSheetState extends ConsumerState<ShareSheet> {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'sendToChat'.tr(),
|
'sendToChat'.tr(),
|
||||||
style: Theme.of(
|
style: Theme.of(context).textTheme.titleSmall
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.titleSmall?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
context,
|
||||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
).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.length;
|
||||||
: progress.reduce((a, b) => a + b) /
|
|
||||||
progress.length;
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
@@ -699,39 +692,38 @@ 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(
|
strokeWidth: 2,
|
||||||
strokeWidth: 2,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
color: Theme.of(context).colorScheme.primary,
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
error: (error, stack) => Container(
|
||||||
error:
|
height: 80,
|
||||||
(error, stack) => Container(
|
decoration: BoxDecoration(
|
||||||
height: 80,
|
color: Theme.of(context).colorScheme.errorContainer,
|
||||||
decoration: BoxDecoration(
|
borderRadius: BorderRadius.circular(12),
|
||||||
color: Theme.of(context).colorScheme.errorContainer,
|
),
|
||||||
borderRadius: BorderRadius.circular(12),
|
child: Center(
|
||||||
),
|
child: Text(
|
||||||
child: Center(
|
'failedToLoadChats'.tr(),
|
||||||
child: Text(
|
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
||||||
'failedToLoadChats'.tr(),
|
color: Theme.of(context).colorScheme.onErrorContainer,
|
||||||
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
|
|
||||||
color: Theme.of(context).colorScheme.onErrorContainer,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -746,10 +738,9 @@ 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();
|
|
||||||
|
|
||||||
final isDirect = room.type == 1; // Assuming type 1 is direct chat
|
final isDirect = room.type == 1; // Assuming type 1 is direct chat
|
||||||
final displayName =
|
final displayName =
|
||||||
@@ -764,12 +755,11 @@ 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,
|
).colorScheme.surfaceContainerHighest.withOpacity(0.5),
|
||||||
).colorScheme.surfaceContainerHighest.withOpacity(0.5),
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
|
color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
|
||||||
@@ -786,36 +776,30 @@ 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: validMembers
|
||||||
filesId:
|
.map((e) => e.account.profile.picture?.id)
|
||||||
validMembers
|
.toList(),
|
||||||
.map((e) => e.account.profile.picture?.id)
|
radius: 16,
|
||||||
.toList(),
|
)
|
||||||
radius: 16,
|
: room.picture?.id == null
|
||||||
)
|
? CircleAvatar(
|
||||||
: room.picture?.id == null
|
radius: 16,
|
||||||
? CircleAvatar(
|
child: Text(room.name![0].toUpperCase()),
|
||||||
radius: 16,
|
)
|
||||||
child: Text(room.name![0].toUpperCase()),
|
: ProfilePictureWidget(fileId: room.picture?.id, radius: 16),
|
||||||
)
|
|
||||||
: ProfilePictureWidget(
|
|
||||||
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,
|
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
||||||
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@@ -847,12 +831,11 @@ 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,
|
).colorScheme.surfaceContainerHighest.withOpacity(0.5),
|
||||||
).colorScheme.surfaceContainerHighest.withOpacity(0.5),
|
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
|
color: Theme.of(context).colorScheme.outline.withOpacity(0.2),
|
||||||
@@ -864,23 +847,21 @@ 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,
|
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
||||||
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
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,
|
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
||||||
).colorScheme.onSurfaceVariant.withOpacity(0.5),
|
|
||||||
),
|
),
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
@@ -937,26 +918,25 @@ 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: [
|
const SizedBox(
|
||||||
const SizedBox(
|
width: 16,
|
||||||
width: 16,
|
height: 16,
|
||||||
height: 16,
|
child: CircularProgressIndicator(strokeWidth: 2),
|
||||||
child: CircularProgressIndicator(strokeWidth: 2),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 8),
|
|
||||||
Text(
|
|
||||||
'Loading link preview...',
|
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
||||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
const SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
'Loading link preview...',
|
||||||
|
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
||||||
|
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
error: (error, stackTrace) => _buildFallbackPreview(context),
|
error: (error, stackTrace) => _buildFallbackPreview(context),
|
||||||
data: (embed) {
|
data: (embed) {
|
||||||
if (embed == null) {
|
if (embed == null) {
|
||||||
@@ -979,27 +959,27 @@ 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,
|
errorBuilder: (context, error, stackTrace) {
|
||||||
errorBuilder: (context, error, stackTrace) {
|
return _buildFaviconFallback(
|
||||||
return _buildFaviconFallback(
|
context,
|
||||||
context,
|
embed.faviconUrl ?? '',
|
||||||
embed.faviconUrl ?? '',
|
);
|
||||||
);
|
},
|
||||||
},
|
)
|
||||||
)
|
: _buildFaviconFallback(
|
||||||
: _buildFaviconFallback(
|
context,
|
||||||
context,
|
embed.faviconUrl ?? '',
|
||||||
embed.faviconUrl ?? '',
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
// Content
|
// Content
|
||||||
@@ -1033,12 +1013,12 @@ 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
|
||||||
context,
|
?.copyWith(
|
||||||
).textTheme.bodySmall?.copyWith(
|
color: Theme.of(
|
||||||
color:
|
context,
|
||||||
Theme.of(context).colorScheme.onSurfaceVariant,
|
).colorScheme.onSurfaceVariant,
|
||||||
),
|
),
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
@@ -1231,17 +1211,15 @@ 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,17 +1230,17 @@ 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,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
@@ -1281,22 +1259,19 @@ 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,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
@@ -1329,13 +1304,12 @@ 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,
|
onClose: onClose,
|
||||||
onClose: onClose,
|
),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user