diff --git a/lib/main.dart b/lib/main.dart index 645248f..8834759 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,9 +8,8 @@ import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:solian/exts.dart'; import 'package:solian/firebase_options.dart'; import 'package:solian/platform.dart'; -import 'package:solian/providers/account.dart'; +import 'package:solian/providers/websocket.dart'; import 'package:solian/providers/auth.dart'; -import 'package:solian/providers/chat.dart'; import 'package:solian/providers/content/attachment.dart'; import 'package:solian/providers/content/call.dart'; import 'package:solian/providers/content/channel.dart'; @@ -100,8 +99,7 @@ class SolianApp extends StatelessWidget { Get.lazyPut(() => FriendProvider()); Get.lazyPut(() => FeedProvider()); Get.lazyPut(() => AttachmentProvider()); - Get.lazyPut(() => ChatProvider()); - Get.lazyPut(() => AccountProvider()); + Get.lazyPut(() => WebSocketProvider()); Get.lazyPut(() => StatusProvider()); Get.lazyPut(() => ChannelProvider()); Get.lazyPut(() => RealmProvider()); @@ -109,13 +107,12 @@ class SolianApp extends StatelessWidget { final AuthProvider auth = Get.find(); if (await auth.isAuthorized) { - Get.find().connect(); - Get.find().connect(); + Get.find().connect(); Get.find().refreshAvailableChannel(); try { - Get.find().registerPushNotifications(); + Get.find().registerPushNotifications(); } catch (err) { context.showSnackbar( 'pushNotifyRegisterFailed'.trParams({'reason': err.toString()}), diff --git a/lib/models/articles.dart b/lib/models/articles.dart index 6d9b0d3..41e615a 100644 --- a/lib/models/articles.dart +++ b/lib/models/articles.dart @@ -1,5 +1,6 @@ import 'package:solian/models/account.dart'; import 'package:solian/models/feed.dart'; +import 'package:solian/models/post.dart'; import 'package:solian/models/realm.dart'; class Article { @@ -20,8 +21,7 @@ class Article { bool? isDraft; int authorId; Account author; - int reactionCount; - Map reactionList; + PostMetric? metric; Article({ required this.id, @@ -41,8 +41,7 @@ class Article { required this.isDraft, required this.authorId, required this.author, - required this.reactionCount, - required this.reactionList, + required this.metric, }); factory Article.fromJson(Map json) => Article( @@ -72,15 +71,8 @@ class Article { isDraft: json['is_draft'], authorId: json['author_id'], author: Account.fromJson(json['author']), - reactionCount: json['reaction_count'], - reactionList: json['reaction_list'] != null - ? json['reaction_list'] - .map((key, value) => MapEntry( - key, - int.tryParse(value.toString()) ?? - (value is double ? value.toInt() : null))) - .cast() - : {}, + metric: + json['metric'] != null ? PostMetric.fromJson(json['metric']) : null, ); Map toJson() => { @@ -101,7 +93,6 @@ class Article { 'is_draft': isDraft, 'author_id': authorId, 'author': author.toJson(), - 'reaction_count': reactionCount, - 'reaction_list': reactionList, + 'metric': metric?.toJson(), }; } diff --git a/lib/models/post.dart b/lib/models/post.dart index 0a85414..77f681c 100755 --- a/lib/models/post.dart +++ b/lib/models/post.dart @@ -23,9 +23,7 @@ class Post { bool? isDraft; int authorId; Account author; - int replyCount; - int reactionCount; - Map reactionList; + PostMetric? metric; Post({ required this.id, @@ -48,9 +46,7 @@ class Post { required this.isDraft, required this.authorId, required this.author, - required this.replyCount, - required this.reactionCount, - required this.reactionList, + required this.metric, }); factory Post.fromJson(Map json) => Post( @@ -85,16 +81,8 @@ class Post { isDraft: json['is_draft'], authorId: json['author_id'], author: Account.fromJson(json['author']), - replyCount: json['reply_count'], - reactionCount: json['reaction_count'], - reactionList: json['reaction_list'] != null - ? json['reaction_list'] - .map((key, value) => MapEntry( - key, - int.tryParse(value.toString()) ?? - (value is double ? value.toInt() : null))) - .cast() - : {}, + metric: + json['metric'] != null ? PostMetric.fromJson(json['metric']) : null, ); Map toJson() => { @@ -118,8 +106,37 @@ class Post { 'is_draft': isDraft, 'author_id': authorId, 'author': author.toJson(), - 'reply_count': replyCount, + 'metric': metric?.toJson(), + }; +} + +class PostMetric { + int reactionCount; + Map reactionList; + int replyCount; + + PostMetric({ + required this.reactionCount, + required this.reactionList, + required this.replyCount, + }); + + factory PostMetric.fromJson(Map json) => PostMetric( + reactionCount: json['reaction_count'], + replyCount: json['reply_count'], + reactionList: json['reaction_list'] != null + ? json['reaction_list'] + .map((key, value) => MapEntry( + key, + int.tryParse(value.toString()) ?? + (value is double ? value.toInt() : null))) + .cast() + : {}, + ); + + Map toJson() => { 'reaction_count': reactionCount, + 'reply_count': replyCount, 'reaction_list': reactionList, }; } diff --git a/lib/providers/account_status.dart b/lib/providers/account_status.dart index 3cccefd..a0fb030 100644 --- a/lib/providers/account_status.dart +++ b/lib/providers/account_status.dart @@ -27,7 +27,7 @@ class StatusProvider extends GetConnect { void onInit() { final AuthProvider auth = Get.find(); - httpClient.baseUrl = ServiceFinder.services['passport']; + httpClient.baseUrl = ServiceFinder.buildUrl('auth', null); httpClient.addAuthenticator(auth.requestAuthenticator); } @@ -35,13 +35,13 @@ class StatusProvider extends GetConnect { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - return await client.get('/api/users/me/status'); + return await client.get('/users/me/status'); } Future getSomeoneStatus(String name) => - get('/api/users/$name/status'); + get('/users/$name/status'); Future setStatus( String type, @@ -55,7 +55,7 @@ class StatusProvider extends GetConnect { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); final payload = { 'type': type, @@ -68,9 +68,9 @@ class StatusProvider extends GetConnect { Response resp; if (!isUpdate) { - resp = await client.post('/api/users/me/status', payload); + resp = await client.post('/users/me/status', payload); } else { - resp = await client.put('/api/users/me/status', payload); + resp = await client.put('/users/me/status', payload); } if (resp.statusCode != 200) { @@ -84,9 +84,9 @@ class StatusProvider extends GetConnect { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - final resp = await client.delete('/api/users/me/status'); + final resp = await client.delete('/users/me/status'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } diff --git a/lib/providers/auth.dart b/lib/providers/auth.dart index b48e846..e0025c2 100644 --- a/lib/providers/auth.dart +++ b/lib/providers/auth.dart @@ -8,8 +8,7 @@ import 'package:get/get.dart'; import 'package:get/get_connect/http/src/request/request.dart'; import 'package:mutex/mutex.dart'; import 'package:solian/controllers/chat_events_controller.dart'; -import 'package:solian/providers/account.dart'; -import 'package:solian/providers/chat.dart'; +import 'package:solian/providers/websocket.dart'; import 'package:solian/services.dart'; class TokenSet { @@ -48,7 +47,7 @@ class RiskyAuthenticateException implements Exception { class AuthProvider extends GetConnect { final tokenEndpoint = - Uri.parse('${ServiceFinder.services['passport']}/api/auth/token'); + Uri.parse(ServiceFinder.buildUrl('auth', '/auth/token')); static const clientId = 'solian'; static const clientSecret = '_F4%q2Eea3'; @@ -60,7 +59,7 @@ class AuthProvider extends GetConnect { @override void onInit() { - httpClient.baseUrl = ServiceFinder.services['passport']; + httpClient.baseUrl = ServiceFinder.buildUrl('auth', null); loadCredentials(); } @@ -68,7 +67,7 @@ class AuthProvider extends GetConnect { try { credentialsRefreshMutex.acquire(); if (!credentials!.isExpired) return; - final resp = await post('/api/auth/token', { + final resp = await post('/auth/token', { 'refresh_token': credentials!.refreshToken, 'grant_type': 'refresh_token', }); @@ -111,7 +110,7 @@ class AuthProvider extends GetConnect { sendUserAgent: true, ); client.httpClient.addAuthenticator(requestAuthenticator); - client.httpClient.baseUrl = ServiceFinder.services[service]; + client.httpClient.baseUrl = ServiceFinder.buildUrl(service, null); return client; } @@ -140,10 +139,10 @@ class AuthProvider extends GetConnect { ) async { _cachedUserProfileResponse = null; - final client = ServiceFinder.configureClient('passport'); + final client = ServiceFinder.configureClient('auth'); // Create ticket - final resp = await client.post('/api/auth', { + final resp = await client.post('/auth', { 'username': username, 'password': password, }); @@ -154,7 +153,7 @@ class AuthProvider extends GetConnect { } // Assign token - final tokenResp = await post('/api/auth/token', { + final tokenResp = await post('/auth/token', { 'code': resp.body['ticket']['grant_token'], 'grant_type': 'grant_token', }); @@ -173,9 +172,8 @@ class AuthProvider extends GetConnect { value: jsonEncode(credentials!.toJson()), ); - Get.find().connect(); - Get.find().notifyPrefetch(); - Get.find().connect(); + Get.find().connect(); + Get.find().notifyPrefetch(); return credentials!; } @@ -183,10 +181,9 @@ class AuthProvider extends GetConnect { void signout() { _cachedUserProfileResponse = null; - Get.find().disconnect(); - Get.find().disconnect(); - Get.find().notifications.clear(); - Get.find().notificationUnread.value = 0; + Get.find().disconnect(); + Get.find().notifications.clear(); + Get.find().notificationUnread.value = 0; final chatHistory = ChatEventController(); chatHistory.initialize().then((_) async { @@ -207,9 +204,9 @@ class AuthProvider extends GetConnect { return _cachedUserProfileResponse!; } - final client = configureClient('passport'); + final client = configureClient('auth'); - final resp = await client.get('/api/users/me'); + final resp = await client.get('/users/me'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } else { diff --git a/lib/providers/chat.dart b/lib/providers/chat.dart deleted file mode 100644 index 209801e..0000000 --- a/lib/providers/chat.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; - -import 'package:get/get.dart'; -import 'package:solian/models/packet.dart'; -import 'package:solian/providers/auth.dart'; -import 'package:solian/services.dart'; -import 'package:web_socket_channel/web_socket_channel.dart'; - -class ChatProvider extends GetxController { - RxBool isConnected = false.obs; - RxBool isConnecting = false.obs; - - WebSocketChannel? websocket; - - StreamController stream = StreamController.broadcast(); - - void connect({noRetry = false}) async { - if (isConnected.value) { - return; - } else { - disconnect(); - } - - final AuthProvider auth = Get.find(); - await auth.ensureCredentials(); - - if (auth.credentials == null) await auth.loadCredentials(); - - final uri = Uri.parse( - '${ServiceFinder.services['messaging']}/api/ws?tk=${auth.credentials!.accessToken}' - .replaceFirst('http', 'ws'), - ); - - isConnecting.value = true; - - try { - websocket = WebSocketChannel.connect(uri); - await websocket?.ready; - } catch (e) { - if (!noRetry) { - await auth.refreshCredentials(); - return connect(noRetry: true); - } - } - - listen(); - - isConnected.value = true; - isConnecting.value = false; - } - - void disconnect() { - websocket?.sink.close(WebSocketStatus.normalClosure); - websocket = null; - isConnected.value = false; - } - - void listen() { - websocket?.stream.listen( - (event) { - final packet = NetworkPackage.fromJson(jsonDecode(event)); - stream.sink.add(packet); - }, - onDone: () { - isConnected.value = false; - Future.delayed(const Duration(seconds: 1), () => connect()); - }, - onError: (err) { - isConnected.value = false; - Future.delayed(const Duration(seconds: 3), () => connect()); - }, - ); - } -} diff --git a/lib/providers/content/attachment.dart b/lib/providers/content/attachment.dart index 693b6b2..3d1c98d 100644 --- a/lib/providers/content/attachment.dart +++ b/lib/providers/content/attachment.dart @@ -58,7 +58,7 @@ class AttachmentProvider extends GetConnect { @override void onInit() { - httpClient.baseUrl = ServiceFinder.services['paperclip']; + httpClient.baseUrl = ServiceFinder.buildUrl('files', null); } final Map _cachedResponses = {}; @@ -68,7 +68,7 @@ class AttachmentProvider extends GetConnect { return _cachedResponses[id]!; } - final resp = await get('/api/attachments/$id/meta'); + final resp = await get('/attachments/$id/meta'); _cachedResponses[id] = resp; return resp; @@ -81,7 +81,7 @@ class AttachmentProvider extends GetConnect { if (!await auth.isAuthorized) throw Exception('unauthorized'); final client = auth.configureClient( - 'paperclip', + 'files', timeout: const Duration(minutes: 3), ); @@ -108,7 +108,7 @@ class AttachmentProvider extends GetConnect { if (ratio != null) 'ratio': ratio, }), }); - final resp = await client.post('/api/attachments', payload); + final resp = await client.post('/attachments', payload); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -126,9 +126,9 @@ class AttachmentProvider extends GetConnect { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('paperclip'); + final client = auth.configureClient('files'); - var resp = await client.put('/api/attachments/$id', { + var resp = await client.put('/attachments/$id', { 'metadata': { if (ratio != null) 'ratio': ratio, }, @@ -148,9 +148,9 @@ class AttachmentProvider extends GetConnect { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('paperclip'); + final client = auth.configureClient('files'); - var resp = await client.delete('/api/attachments/$id'); + var resp = await client.delete('/attachments/$id'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } diff --git a/lib/providers/content/call.dart b/lib/providers/content/call.dart index b67f097..6a87ce4 100644 --- a/lib/providers/content/call.dart +++ b/lib/providers/content/call.dart @@ -60,7 +60,7 @@ class ChatCallProvider extends GetxController { final client = auth.configureClient('messaging'); final resp = await client.post( - '/api/channels/global/${channel.value!.alias}/calls/ongoing/token', + '/channels/global/${channel.value!.alias}/calls/ongoing/token', {}, ); if (resp.statusCode == 200) { diff --git a/lib/providers/content/channel.dart b/lib/providers/content/channel.dart index d94c4a0..ba89700 100644 --- a/lib/providers/content/channel.dart +++ b/lib/providers/content/channel.dart @@ -33,7 +33,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.get('/api/channels/$realm/$alias'); + final resp = await client.get('/channels/$realm/$alias'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -48,7 +48,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.get('/api/channels/$realm/$alias/me'); + final resp = await client.get('/channels/$realm/$alias/me'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -63,7 +63,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.get('/api/channels/$realm/$alias/calls/ongoing'); + final resp = await client.get('/channels/$realm/$alias/calls/ongoing'); if (resp.statusCode == 404) { return null; } else if (resp.statusCode != 200) { @@ -79,7 +79,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.get('/api/channels/$scope'); + final resp = await client.get('/channels/$scope'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -93,7 +93,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.get('/api/channels/$realm/me/available'); + final resp = await client.get('/channels/$realm/me/available'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -107,7 +107,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.post('/api/channels/$scope', payload); + final resp = await client.post('/channels/$scope', payload); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -132,7 +132,7 @@ class ChannelProvider extends GetxController { final prof = await auth.getProfile(); final client = auth.configureClient('messaging'); - final resp = await client.post('/api/channels/$scope/dm', { + final resp = await client.post('/channels/$scope/dm', { 'alias': const Uuid().v4().replaceAll('-', '').substring(0, 12), 'name': 'DM', 'description': @@ -153,7 +153,7 @@ class ChannelProvider extends GetxController { final client = auth.configureClient('messaging'); - final resp = await client.put('/api/channels/$scope/$id', payload); + final resp = await client.put('/channels/$scope/$id', payload); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } diff --git a/lib/providers/content/feed.dart b/lib/providers/content/feed.dart index 7efd4e1..8ac6c79 100644 --- a/lib/providers/content/feed.dart +++ b/lib/providers/content/feed.dart @@ -5,7 +5,7 @@ import 'package:solian/services.dart'; class FeedProvider extends GetConnect { @override void onInit() { - httpClient.baseUrl = ServiceFinder.services['interactive']; + httpClient.baseUrl = ServiceFinder.buildUrl('interactive', null); } Future listFeed(int page, @@ -17,7 +17,7 @@ class FeedProvider extends GetConnect { if (category != null) 'category=$category', if (realm != null) 'realmId=$realm', ]; - final resp = await get('/api/feed?${queries.join('&')}'); + final resp = await get('/feed?${queries.join('&')}'); if (resp.statusCode != 200) { throw Exception(resp.body); } @@ -34,7 +34,7 @@ class FeedProvider extends GetConnect { 'offset=$page', ]; final client = auth.configureClient('interactive'); - final resp = await client.get('/api/drafts?${queries.join('&')}'); + final resp = await client.get('/drafts?${queries.join('&')}'); if (resp.statusCode != 200) { throw Exception(resp.body); } @@ -48,7 +48,7 @@ class FeedProvider extends GetConnect { 'offset=$page', if (realm != null) 'realmId=$realm', ]; - final resp = await get('/api/posts?${queries.join('&')}'); + final resp = await get('/posts?${queries.join('&')}'); if (resp.statusCode != 200) { throw Exception(resp.body); } @@ -57,7 +57,7 @@ class FeedProvider extends GetConnect { } Future listPostReplies(String alias, int page) async { - final resp = await get('/api/posts/$alias/replies?take=${10}&offset=$page'); + final resp = await get('/posts/$alias/replies?take=${10}&offset=$page'); if (resp.statusCode != 200) { throw Exception(resp.body); } @@ -66,7 +66,7 @@ class FeedProvider extends GetConnect { } Future getPost(String alias) async { - final resp = await get('/api/posts/$alias'); + final resp = await get('/posts/$alias'); if (resp.statusCode != 200) { throw Exception(resp.body); } @@ -75,7 +75,7 @@ class FeedProvider extends GetConnect { } Future getArticle(String alias) async { - final resp = await get('/api/articles/$alias'); + final resp = await get('/articles/$alias'); if (resp.statusCode != 200) { throw Exception(resp.body); } diff --git a/lib/providers/content/realm.dart b/lib/providers/content/realm.dart index 3886597..7e92b33 100644 --- a/lib/providers/content/realm.dart +++ b/lib/providers/content/realm.dart @@ -6,9 +6,9 @@ class RealmProvider extends GetxController { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - final resp = await client.get('/api/realms/$alias'); + final resp = await client.get('/realms/$alias'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -20,9 +20,9 @@ class RealmProvider extends GetxController { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) throw Exception('unauthorized'); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - final resp = await client.get('/api/realms/me/available'); + final resp = await client.get('/realms/me/available'); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } diff --git a/lib/providers/friend.dart b/lib/providers/friend.dart index 2e0fcb4..10b3dcb 100644 --- a/lib/providers/friend.dart +++ b/lib/providers/friend.dart @@ -8,17 +8,17 @@ class FriendProvider extends GetConnect { void onInit() { final AuthProvider auth = Get.find(); - httpClient.baseUrl = ServiceFinder.services['passport']; + httpClient.baseUrl = ServiceFinder.buildUrl('auth', null); httpClient.addAuthenticator(auth.requestAuthenticator); } - Future listFriendship() => get('/api/users/me/friends'); + Future listFriendship() => get('/users/me/friends'); Future listFriendshipWithStatus(int status) => - get('/api/users/me/friends?status=$status'); + get('/users/me/friends?status=$status'); Future createFriendship(String username) async { - final resp = await post('/api/users/me/friends?related=$username', {}); + final resp = await post('/users/me/friends?related=$username', {}); if (resp.statusCode != 200) { throw Exception(resp.bodyString); } @@ -31,7 +31,7 @@ class FriendProvider extends GetConnect { final prof = await auth.getProfile(); final otherside = relationship.getOtherside(prof.body['id']); - final resp = await put('/api/users/me/friends/${otherside.id}', { + final resp = await put('/users/me/friends/${otherside.id}', { 'status': status, }); if (resp.statusCode != 200) { diff --git a/lib/providers/message/adaptor.dart b/lib/providers/message/adaptor.dart index 1ea08ee..a23894e 100644 --- a/lib/providers/message/adaptor.dart +++ b/lib/providers/message/adaptor.dart @@ -23,7 +23,7 @@ Future getRemoteEvent(int id, Channel channel, String scope) async { final client = auth.configureClient('messaging'); final resp = await client.get( - '/api/channels/$scope/${channel.alias}/events/$id', + '/channels/$scope/${channel.alias}/events/$id', ); if (resp.statusCode == 404) { @@ -53,7 +53,7 @@ Future<(List, int)?> getRemoteEvents( final client = auth.configureClient('messaging'); final resp = await client.get( - '/api/channels/$scope/${channel.alias}/events?take=$take&offset=$offset', + '/channels/$scope/${channel.alias}/events?take=$take&offset=$offset', ); if (resp.statusCode != 200) { diff --git a/lib/providers/account.dart b/lib/providers/websocket.dart similarity index 92% rename from lib/providers/account.dart rename to lib/providers/websocket.dart index 476f52f..4b92432 100644 --- a/lib/providers/account.dart +++ b/lib/providers/websocket.dart @@ -16,7 +16,7 @@ import 'package:solian/services.dart'; import 'package:web_socket_channel/web_socket_channel.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; -class AccountProvider extends GetxController { +class WebSocketProvider extends GetxController { final FlutterLocalNotificationsPlugin localNotify = FlutterLocalNotificationsPlugin(); @@ -29,6 +29,8 @@ class AccountProvider extends GetxController { WebSocketChannel? websocket; + StreamController stream = StreamController.broadcast(); + @override onInit() { FirebaseMessaging.instance @@ -58,10 +60,10 @@ class AccountProvider extends GetxController { if (auth.credentials == null) await auth.loadCredentials(); - final uri = Uri.parse( - '${ServiceFinder.services['passport']}/api/ws?tk=${auth.credentials!.accessToken}' - .replaceFirst('http', 'ws'), - ); + final uri = Uri.parse(ServiceFinder.buildUrl( + 'dealer', + '/api/ws?tk=${auth.credentials!.accessToken}', + ).replaceFirst('http', 'ws')); isConnecting.value = true; @@ -91,6 +93,8 @@ class AccountProvider extends GetxController { websocket?.stream.listen( (event) { final packet = NetworkPackage.fromJson(jsonDecode(event)); + stream.sink.add(packet); + switch (packet.method) { case 'notifications.new': final notification = Notification.fromJson(packet.payload!); @@ -166,9 +170,9 @@ class AccountProvider extends GetxController { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) return; - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - final resp = await client.get('/api/notifications?skip=0&take=100'); + final resp = await client.get('/notifications?skip=0&take=100'); if (resp.statusCode == 200) { final result = PaginationResult.fromJson(resp.body); final data = result.data?.map((x) => Notification.fromJson(x)).toList(); @@ -199,9 +203,9 @@ class AccountProvider extends GetxController { token = await FirebaseMessaging.instance.getToken(); } - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - final resp = await client.post('/api/notifications/subscribe', { + final resp = await client.post('/notifications/subscribe', { 'provider': provider, 'device_token': token, 'device_id': deviceUuid, diff --git a/lib/screens/account/notification.dart b/lib/screens/account/notification.dart index a0a0ba5..98fd172 100644 --- a/lib/screens/account/notification.dart +++ b/lib/screens/account/notification.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:get/get.dart'; -import 'package:solian/providers/account.dart'; +import 'package:solian/providers/websocket.dart'; import 'package:solian/providers/auth.dart'; import 'package:solian/models/notification.dart' as notify; import 'package:url_launcher/url_launcher_string.dart'; @@ -23,7 +23,7 @@ class _NotificationScreenState extends State { setState(() => _isBusy = true); - final AccountProvider provider = Get.find(); + final WebSocketProvider provider = Get.find(); List markList = List.empty(growable: true); for (final element in provider.notifications) { @@ -32,8 +32,8 @@ class _NotificationScreenState extends State { } if (markList.isNotEmpty) { - final client = auth.configureClient('passport'); - await client.put('/api/notifications/batch/read', {'messages': markList}); + final client = auth.configureClient('auth'); + await client.put('/notifications/batch/read', {'messages': markList}); } provider.notifications.clear(); @@ -45,7 +45,7 @@ class _NotificationScreenState extends State { final AuthProvider auth = Get.find(); if (!await auth.isAuthorized) return; - final AccountProvider provider = Get.find(); + final WebSocketProvider provider = Get.find(); if (element.id <= 0) { provider.notifications.removeAt(index); @@ -54,9 +54,9 @@ class _NotificationScreenState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - await client.put('/api/notifications/${element.id}/read', {}); + await client.put('/notifications/${element.id}/read', {}); provider.notifications.removeAt(index); @@ -65,7 +65,7 @@ class _NotificationScreenState extends State { @override Widget build(BuildContext context) { - final AccountProvider provider = Get.find(); + final WebSocketProvider provider = Get.find(); return SizedBox( height: MediaQuery.of(context).size.height * 0.85, @@ -175,7 +175,7 @@ class NotificationButton extends StatelessWidget { @override Widget build(BuildContext context) { - final AccountProvider provider = Get.find(); + final WebSocketProvider provider = Get.find(); final button = IconButton( icon: const Icon(Icons.notifications), diff --git a/lib/screens/account/personalize.dart b/lib/screens/account/personalize.dart index e822dd4..d17c0ee 100644 --- a/lib/screens/account/personalize.dart +++ b/lib/screens/account/personalize.dart @@ -100,10 +100,10 @@ class _PersonalizeScreenState extends State { return; } - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); final resp = await client.put( - '/api/users/me/$position', + '/users/me/$position', {'attachment': attachResp.body['id']}, ); if (resp.statusCode == 200) { @@ -122,11 +122,11 @@ class _PersonalizeScreenState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); _birthday?.toIso8601String(); final resp = await client.put( - '/api/users/me', + '/users/me', { 'nick': _nicknameController.value.text, 'description': _descriptionController.value.text, @@ -189,7 +189,7 @@ class _PersonalizeScreenState extends State { color: Theme.of(context).colorScheme.surfaceContainerHigh, child: _banner != null ? Image.network( - '${ServiceFinder.services['paperclip']}/api/attachments/$_banner', + ServiceFinder.buildUrl('files', '/attachments/$_banner'), fit: BoxFit.cover, loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { diff --git a/lib/screens/articles/article_editor.dart b/lib/screens/articles/article_editor.dart index dd655a3..8c836dc 100644 --- a/lib/screens/articles/article_editor.dart +++ b/lib/screens/articles/article_editor.dart @@ -84,9 +84,9 @@ class _ArticlePublishScreenState extends State { Response resp; if (widget.edit != null) { - resp = await client.put('/api/articles/${widget.edit!.id}', payload); + resp = await client.put('/articles/${widget.edit!.id}', payload); } else { - resp = await client.post('/api/articles', payload); + resp = await client.post('/articles', payload); } if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); diff --git a/lib/screens/auth/signin.dart b/lib/screens/auth/signin.dart index 8cda733..13adaf2 100644 --- a/lib/screens/auth/signin.dart +++ b/lib/screens/auth/signin.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:protocol_handler/protocol_handler.dart'; import 'package:solian/exts.dart'; -import 'package:solian/providers/account.dart'; +import 'package:solian/providers/websocket.dart'; import 'package:solian/providers/auth.dart'; import 'package:solian/services.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -30,15 +30,15 @@ class _SignInPopupState extends State with ProtocolListener { setState(() => _isBusy = true); - final client = ServiceFinder.configureClient('passport'); - final lookupResp = await client.get('/api/users/lookup?probe=$username'); + final client = ServiceFinder.configureClient('auth'); + final lookupResp = await client.get('/users/lookup?probe=$username'); if (lookupResp.statusCode != 200) { context.showErrorDialog(lookupResp.bodyString); setState(() => _isBusy = false); return; } - final resp = await client.post('/api/users/me/password-reset', { + final resp = await client.post('/users/me/password-reset', { 'user_id': lookupResp.body['id'], }); if (resp.statusCode != 200) { @@ -75,7 +75,7 @@ class _SignInPopupState extends State with ProtocolListener { onPressed: () { const redirect = 'solink://auth?status=done'; launchUrlString( - '${ServiceFinder.services['passport']}/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}', + ServiceFinder.buildUrl('passport', '/mfa?redirect_uri=$redirect&ticketId=${e.ticketId}'), mode: LaunchMode.inAppWebView, ); Navigator.pop(context); @@ -93,7 +93,7 @@ class _SignInPopupState extends State with ProtocolListener { setState(() => _isBusy = false); } - Get.find().registerPushNotifications(); + Get.find().registerPushNotifications(); Navigator.pop(context, true); } diff --git a/lib/screens/auth/signup.dart b/lib/screens/auth/signup.dart index 718f442..e5ae574 100644 --- a/lib/screens/auth/signup.dart +++ b/lib/screens/auth/signup.dart @@ -26,9 +26,9 @@ class _SignUpPopupState extends State { nickname.isEmpty || password.isEmpty) return; - final client = ServiceFinder.configureClient('passport'); + final client = ServiceFinder.configureClient('auth'); - final resp = await client.post('/api/users', { + final resp = await client.post('/users', { 'name': username, 'nick': nickname, 'email': email, diff --git a/lib/screens/channel/channel_chat.dart b/lib/screens/channel/channel_chat.dart index e6c6d29..ad0fa58 100644 --- a/lib/screens/channel/channel_chat.dart +++ b/lib/screens/channel/channel_chat.dart @@ -11,9 +11,9 @@ import 'package:solian/models/channel.dart'; import 'package:solian/models/event.dart'; import 'package:solian/models/packet.dart'; import 'package:solian/providers/auth.dart'; -import 'package:solian/providers/chat.dart'; import 'package:solian/providers/content/call.dart'; import 'package:solian/providers/content/channel.dart'; +import 'package:solian/providers/websocket.dart'; import 'package:solian/router.dart'; import 'package:solian/screens/channel/channel_detail.dart'; import 'package:solian/theme.dart'; @@ -107,7 +107,7 @@ class _ChannelChatScreenState extends State { } void listenMessages() { - final ChatProvider provider = Get.find(); + final WebSocketProvider provider = Get.find(); _subscription = provider.stream.stream.listen((event) { switch (event.method) { case 'events.new': diff --git a/lib/screens/channel/channel_detail.dart b/lib/screens/channel/channel_detail.dart index c409261..2d1a224 100644 --- a/lib/screens/channel/channel_detail.dart +++ b/lib/screens/channel/channel_detail.dart @@ -82,7 +82,7 @@ class _ChannelDetailScreenState extends State { final client = auth.configureClient('messaging'); final resp = await client.put( - '/api/channels/${widget.realm}/${widget.channel.alias}/members/me', { + '/channels/${widget.realm}/${widget.channel.alias}/members/me', { 'nick': null, 'notify_level': _notifyLevel, }); diff --git a/lib/screens/posts/post_editor.dart b/lib/screens/posts/post_editor.dart index ceb323a..6a923c4 100644 --- a/lib/screens/posts/post_editor.dart +++ b/lib/screens/posts/post_editor.dart @@ -90,9 +90,9 @@ class _PostPublishScreenState extends State { Response resp; if (widget.edit != null) { - resp = await client.put('/api/posts/${widget.edit!.id}', payload); + resp = await client.put('/posts/${widget.edit!.id}', payload); } else { - resp = await client.post('/api/posts', payload); + resp = await client.post('/posts', payload); } if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); diff --git a/lib/screens/realms/realm_organize.dart b/lib/screens/realms/realm_organize.dart index 21832a1..68a3fbf 100644 --- a/lib/screens/realms/realm_organize.dart +++ b/lib/screens/realms/realm_organize.dart @@ -43,7 +43,7 @@ class _RealmOrganizeScreenState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); final payload = { 'alias': _aliasController.value.text.toLowerCase(), @@ -55,9 +55,9 @@ class _RealmOrganizeScreenState extends State { Response resp; if (widget.edit != null) { - resp = await client.put('/api/realms/${widget.edit!.id}', payload); + resp = await client.put('/realms/${widget.edit!.id}', payload); } else { - resp = await client.post('/api/realms', payload); + resp = await client.post('/realms', payload); } if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); diff --git a/lib/services.dart b/lib/services.dart index d62eb51..92a94fa 100644 --- a/lib/services.dart +++ b/lib/services.dart @@ -3,23 +3,29 @@ import 'package:get/get.dart'; abstract class ServiceFinder { static const bool devFlag = false; - static Map services = { - 'paperclip': - devFlag ? 'http://localhost:8443' : 'https://usercontent.solsynth.dev', - 'passport': devFlag ? 'http://localhost:8444' : 'https://id.solsynth.dev', - 'interactive': - devFlag ? 'http://localhost:8445' : 'https://co.solsynth.dev', - 'messaging': devFlag ? 'http://localhost:8447' : 'https://im.solsynth.dev', - }; + static const String dealerUrl = + devFlag ? 'http://localhost:8442' : 'https://api.sn.solsynth.dev'; + static const String passportUrl = + devFlag ? 'http://localhost:8444' : 'https://id.solsynth.dev'; - static GetConnect configureClient(String service, + static String buildUrl(String serviceName, String? append) { + append ??= ''; + if (serviceName == 'dealer') { + return '$dealerUrl$append'; + } else if (serviceName == 'passport') { + return '$passportUrl$append'; + } + return '$dealerUrl/srv/$serviceName$append'; + } + + static GetConnect configureClient(String serviceName, {timeout = const Duration(seconds: 5)}) { final client = GetConnect( timeout: timeout, userAgent: 'Solian/1.1', sendUserAgent: true, ); - client.httpClient.baseUrl = ServiceFinder.services[service]; + client.httpClient.baseUrl = buildUrl(serviceName, null); return client; } diff --git a/lib/widgets/account/account_avatar.dart b/lib/widgets/account/account_avatar.dart index 26a9913..ca7b249 100644 --- a/lib/widgets/account/account_avatar.dart +++ b/lib/widgets/account/account_avatar.dart @@ -24,12 +24,12 @@ class AccountAvatar extends StatelessWidget { if (content is String) { direct = content.startsWith('http'); if (!isEmpty) isEmpty = content.isEmpty; - if (!isEmpty) isEmpty = content.endsWith('/api/attachments/0'); + if (!isEmpty) isEmpty = content.endsWith('/attachments/0'); } final url = direct ? content - : '${ServiceFinder.services['paperclip']}/api/attachments/$content'; + : ServiceFinder.buildUrl('files', '/attachments/$content'); return CircleAvatar( key: Key('a$content'), @@ -68,12 +68,12 @@ class AccountProfileImage extends StatelessWidget { if (content is String) { direct = content.startsWith('http'); if (!isEmpty) isEmpty = content.isEmpty; - if (!isEmpty) isEmpty = content.endsWith('/api/attachments/0'); + if (!isEmpty) isEmpty = content.endsWith('/attachments/0'); } final url = direct ? content - : '${ServiceFinder.services['paperclip']}/api/attachments/$content'; + : ServiceFinder.buildUrl('files', '/attachments/$content'); if (PlatformInfo.canCacheImage) { return CachedNetworkImage( diff --git a/lib/widgets/account/account_profile_popup.dart b/lib/widgets/account/account_profile_popup.dart index f899935..826447c 100644 --- a/lib/widgets/account/account_profile_popup.dart +++ b/lib/widgets/account/account_profile_popup.dart @@ -24,9 +24,9 @@ class _AccountProfilePopupState extends State { setState(() => _isBusy = true); final client = GetConnect(); - client.httpClient.baseUrl = ServiceFinder.services['passport']; + client.httpClient.baseUrl = ServiceFinder.buildUrl('auth', null); - final resp = await client.get('/api/users/${widget.account.name}'); + final resp = await client.get('/users/${widget.account.name}'); if (resp.statusCode == 200) { _userinfo = Account.fromJson(resp.body); setState(() => _isBusy = false); diff --git a/lib/widgets/articles/article_action.dart b/lib/widgets/articles/article_action.dart index 28e5d3b..2ee5701 100644 --- a/lib/widgets/articles/article_action.dart +++ b/lib/widgets/articles/article_action.dart @@ -123,7 +123,7 @@ class _ArticleDeletionDialogState extends State { final client = auth.configureClient('interactive'); setState(() => _isBusy = true); - final resp = await client.delete('/api/articles/${widget.item.id}'); + final resp = await client.delete('/articles/${widget.item.id}'); setState(() => _isBusy = false); if (resp.statusCode != 200) { diff --git a/lib/widgets/articles/article_item.dart b/lib/widgets/articles/article_item.dart index 2d00a35..f3551f6 100644 --- a/lib/widgets/articles/article_item.dart +++ b/lib/widgets/articles/article_item.dart @@ -192,8 +192,8 @@ class _ArticleItemState extends State { item: widget.item, onReact: (symbol, changes) { setState(() { - item.reactionList[symbol] = - (item.reactionList[symbol] ?? 0) + changes; + item.metric!.reactionList[symbol] = + (item.metric!.reactionList[symbol] ?? 0) + changes; }); }, ).paddingOnly( diff --git a/lib/widgets/articles/article_quick_action.dart b/lib/widgets/articles/article_quick_action.dart index f5bc60f..68c633c 100644 --- a/lib/widgets/articles/article_quick_action.dart +++ b/lib/widgets/articles/article_quick_action.dart @@ -30,7 +30,7 @@ class _ArticleQuickActionState extends State { useRootNavigator: true, context: context, builder: (context) => PostReactionPopup( - reactionList: widget.item.reactionList, + reactionList: widget.item.metric!.reactionList, onReact: (key, value) { doWidgetReact(key, value.attitude); }, @@ -50,7 +50,7 @@ class _ArticleQuickActionState extends State { setState(() => _isSubmitting = true); - final resp = await client.post('/api/articles/${widget.item.alias}/react', { + final resp = await client.post('/articles/${widget.item.alias}/react', { 'symbol': symbol, 'attitude': attitude, }); @@ -71,7 +71,7 @@ class _ArticleQuickActionState extends State { void initState() { super.initState(); - if (!widget.isReactable && widget.item.reactionList.isEmpty) { + if (!widget.isReactable && widget.item.metric!.reactionList.isEmpty) { WidgetsBinding.instance.addPostFrameCallback((_) { widget.onReact('thumb_up', 0); }); @@ -94,7 +94,7 @@ class _ArticleQuickActionState extends State { shrinkWrap: true, scrollDirection: Axis.horizontal, children: [ - ...widget.item.reactionList.entries.map((x) { + ...widget.item.metric!.reactionList.entries.map((x) { final info = reactions[x.key]; return Padding( padding: const EdgeInsets.only(right: 8), diff --git a/lib/widgets/attachments/attachment_item.dart b/lib/widgets/attachments/attachment_item.dart index 8cd9bfb..0011e26 100644 --- a/lib/widgets/attachments/attachment_item.dart +++ b/lib/widgets/attachments/attachment_item.dart @@ -82,7 +82,8 @@ class _AttachmentItemState extends State { ), onPressed: () { launchUrlString( - '${ServiceFinder.services['paperclip']}/api/attachments/${widget.item.id}', + ServiceFinder.buildUrl( + 'files', '/attachments/${widget.item.id}'), ); }, ), @@ -117,7 +118,7 @@ class _AttachmentItemImage extends StatelessWidget { @override Widget build(BuildContext context) { return Hero( - tag: Key('a${item.uuid}p${parentId}'), + tag: Key('a${item.uuid}p$parentId'), child: Stack( fit: StackFit.expand, children: [ @@ -125,7 +126,7 @@ class _AttachmentItemImage extends StatelessWidget { CachedNetworkImage( fit: fit, imageUrl: - '${ServiceFinder.services['paperclip']}/api/attachments/${item.id}', + ServiceFinder.buildUrl('files', '/attachments/${item.id}'), progressIndicatorBuilder: (context, url, downloadProgress) => Center( child: CircularProgressIndicator( @@ -135,7 +136,7 @@ class _AttachmentItemImage extends StatelessWidget { ) else Image.network( - '${ServiceFinder.services['paperclip']}/api/attachments/${item.id}', + ServiceFinder.buildUrl('files', '/attachments/${item.id}'), fit: fit, loadingBuilder: (BuildContext context, Widget child, ImageChunkEvent? loadingProgress) { @@ -205,7 +206,7 @@ class _AttachmentItemVideoState extends State<_AttachmentItemVideo> { super.initState(); _player.open( Media( - '${ServiceFinder.services['paperclip']}/api/attachments/${widget.item.id}', + ServiceFinder.buildUrl('files', '/attachments/${widget.item.id}'), ), play: false, ); diff --git a/lib/widgets/channel/channel_deletion.dart b/lib/widgets/channel/channel_deletion.dart index 98860b1..d0a85f0 100644 --- a/lib/widgets/channel/channel_deletion.dart +++ b/lib/widgets/channel/channel_deletion.dart @@ -32,7 +32,7 @@ class _ChannelDeletionDialogState extends State { final client = auth.configureClient('messaging'); final resp = await client - .delete('/api/channels/${widget.realm}/${widget.channel.id}'); + .delete('/channels/${widget.realm}/${widget.channel.id}'); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); } else if (Navigator.canPop(context)) { @@ -51,7 +51,7 @@ class _ChannelDeletionDialogState extends State { final client = auth.configureClient('messaging'); final resp = await client.delete( - '/api/channels/${widget.realm}/${widget.channel.alias}/members/me', + '/channels/${widget.realm}/${widget.channel.alias}/members/me', ); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); diff --git a/lib/widgets/channel/channel_list.dart b/lib/widgets/channel/channel_list.dart index be9952f..af8b442 100644 --- a/lib/widgets/channel/channel_list.dart +++ b/lib/widgets/channel/channel_list.dart @@ -118,11 +118,7 @@ class _ChannelListWidgetState extends State { ); } else { return ListTile( - minTileHeight: item.realmId == null - ? 48 - : widget.isDense - ? 24 - : null, + minTileHeight: widget.isDense ? 48 : null, leading: CircleAvatar( backgroundColor: item.realmId == null ? Colors.indigo : Colors.transparent, diff --git a/lib/widgets/channel/channel_member.dart b/lib/widgets/channel/channel_member.dart index 237229b..81d7b82 100644 --- a/lib/widgets/channel/channel_member.dart +++ b/lib/widgets/channel/channel_member.dart @@ -43,7 +43,7 @@ class _ChannelMemberListPopupState extends State { final client = ServiceFinder.configureClient('messaging'); final resp = await client - .get('/api/channels/${widget.realm}/${widget.channel.alias}/members'); + .get('/channels/${widget.realm}/${widget.channel.alias}/members'); if (resp.statusCode == 200) { setState(() { _members = resp.body @@ -79,7 +79,7 @@ class _ChannelMemberListPopupState extends State { final client = auth.configureClient('messaging'); final resp = await client.post( - '/api/channels/${widget.realm}/${widget.channel.alias}/members', + '/channels/${widget.realm}/${widget.channel.alias}/members', {'target': username}, ); if (resp.statusCode == 200) { @@ -100,7 +100,7 @@ class _ChannelMemberListPopupState extends State { final client = auth.configureClient('messaging'); final resp = await client.request( - '/api/channels/${widget.realm}/${widget.channel.alias}/members', + '/channels/${widget.realm}/${widget.channel.alias}/members', 'delete', body: {'target': item.account.name}, ); diff --git a/lib/widgets/chat/call/chat_call_action.dart b/lib/widgets/chat/call/chat_call_action.dart index 704651b..f9e870d 100644 --- a/lib/widgets/chat/call/chat_call_action.dart +++ b/lib/widgets/chat/call/chat_call_action.dart @@ -41,7 +41,7 @@ class _ChatCallButtonState extends State { ? widget.realm?.alias : 'global'; final resp = await client.post( - '/api/channels/$scope/${widget.channel.alias}/calls', + '/channels/$scope/${widget.channel.alias}/calls', {}, ); if (resp.statusCode == 200) { @@ -65,7 +65,7 @@ class _ChatCallButtonState extends State { ? widget.realm?.alias : 'global'; final resp = await client - .delete('/api/channels/$scope/${widget.channel.alias}/calls/ongoing'); + .delete('/channels/$scope/${widget.channel.alias}/calls/ongoing'); if (resp.statusCode == 200) { if (widget.onEnded != null) widget.onEnded!(); } else { diff --git a/lib/widgets/chat/chat_event_deletion.dart b/lib/widgets/chat/chat_event_deletion.dart index a17641d..bb38e92 100644 --- a/lib/widgets/chat/chat_event_deletion.dart +++ b/lib/widgets/chat/chat_event_deletion.dart @@ -38,7 +38,7 @@ class _ChatEventDeletionDialogState extends State { ? widget.realm?.alias : 'global'; final resp = await client.delete( - '/api/channels/$scope/${widget.channel.alias}/messages/${widget.item.id}', + '/channels/$scope/${widget.channel.alias}/messages/${widget.item.id}', ); if (resp.statusCode == 200) { Navigator.pop(context, resp.body); diff --git a/lib/widgets/chat/chat_message_input.dart b/lib/widgets/chat/chat_message_input.dart index d6a3018..bee48bd 100644 --- a/lib/widgets/chat/chat_message_input.dart +++ b/lib/widgets/chat/chat_message_input.dart @@ -114,12 +114,12 @@ class _ChatMessageInputState extends State { Response resp; if (_editTo != null) { resp = await client.put( - '/api/channels/${widget.realm}/${widget.channel.alias}/messages/${_editTo!.id}', + '/channels/${widget.realm}/${widget.channel.alias}/messages/${_editTo!.id}', payload, ); } else { resp = await client.post( - '/api/channels/${widget.realm}/${widget.channel.alias}/messages', + '/channels/${widget.realm}/${widget.channel.alias}/messages', payload, ); } diff --git a/lib/widgets/current_state_action.dart b/lib/widgets/current_state_action.dart index dc86cb6..1f65469 100644 --- a/lib/widgets/current_state_action.dart +++ b/lib/widgets/current_state_action.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_animate/flutter_animate.dart'; import 'package:get/get.dart'; -import 'package:solian/providers/account.dart'; +import 'package:solian/providers/websocket.dart'; import 'package:solian/providers/auth.dart'; -import 'package:solian/providers/chat.dart'; class BackgroundStateWidget extends StatelessWidget { const BackgroundStateWidget({super.key}); @@ -11,14 +10,11 @@ class BackgroundStateWidget extends StatelessWidget { @override Widget build(BuildContext context) { final AuthProvider auth = Get.find(); - final AccountProvider account = Get.find(); - final ChatProvider chat = Get.find(); + final WebSocketProvider ws = Get.find(); return Obx(() { - final disconnected = - chat.isConnected.isFalse || account.isConnected.isFalse; - final connecting = - chat.isConnecting.isTrue || account.isConnecting.isTrue; + final disconnected = ws.isConnected.isFalse; + final connecting = ws.isConnecting.isTrue; return Row(children: [ if (disconnected && !connecting) @@ -30,10 +26,8 @@ class BackgroundStateWidget extends StatelessWidget { } return IconButton( tooltip: [ - if (account.isConnected.isFalse) - 'Lost Connection with Passport Server...', - if (chat.isConnected.isFalse) - 'Lost Connection with Messaging Server...', + if (ws.isConnected.isFalse) + 'Lost Connection with Solar Network...', ].join('\n'), icon: const Icon(Icons.wifi_off) .animate(onPlay: (c) => c.repeat()) @@ -41,8 +35,7 @@ class BackgroundStateWidget extends StatelessWidget { .then() .fadeOut(duration: 800.ms), onPressed: () { - if (account.isConnected.isFalse) account.connect(); - if (chat.isConnected.isFalse) chat.connect(); + if (ws.isConnected.isFalse) ws.connect(); }, ); }, @@ -56,10 +49,8 @@ class BackgroundStateWidget extends StatelessWidget { } return IconButton( tooltip: [ - if (account.isConnecting.isTrue) - 'Waiting Passport Server Response...', - if (chat.isConnecting.isTrue) - 'Waiting Messaging Server Response...', + if (ws.isConnecting.isTrue) + 'Waiting Solar Network Connection...', ].join('\n'), icon: const Icon(Icons.sync) .animate(onPlay: (c) => c.repeat()) diff --git a/lib/widgets/posts/post_action.dart b/lib/widgets/posts/post_action.dart index c07e3eb..5de8a45 100644 --- a/lib/widgets/posts/post_action.dart +++ b/lib/widgets/posts/post_action.dart @@ -158,7 +158,7 @@ class _PostDeletionDialogState extends State { final client = auth.configureClient('interactive'); setState(() => _isBusy = true); - final resp = await client.delete('/api/posts/${widget.item.id}'); + final resp = await client.delete('/posts/${widget.item.id}'); setState(() => _isBusy = false); if (resp.statusCode != 200) { diff --git a/lib/widgets/posts/post_item.dart b/lib/widgets/posts/post_item.dart index 16e1646..be7e1fb 100644 --- a/lib/widgets/posts/post_item.dart +++ b/lib/widgets/posts/post_item.dart @@ -304,8 +304,8 @@ class _PostItemState extends State { item: widget.item, onReact: (symbol, changes) { setState(() { - item.reactionList[symbol] = - (item.reactionList[symbol] ?? 0) + changes; + item.metric!.reactionList[symbol] = + (item.metric!.reactionList[symbol] ?? 0) + changes; }); }, ).paddingOnly( diff --git a/lib/widgets/posts/post_quick_action.dart b/lib/widgets/posts/post_quick_action.dart index a9e57de..b236e50 100644 --- a/lib/widgets/posts/post_quick_action.dart +++ b/lib/widgets/posts/post_quick_action.dart @@ -33,7 +33,7 @@ class _PostQuickActionState extends State { useRootNavigator: true, context: context, builder: (context) => PostReactionPopup( - reactionList: widget.item.reactionList, + reactionList: widget.item.metric!.reactionList, onReact: (key, value) { doWidgetReact(key, value.attitude); }, @@ -53,7 +53,7 @@ class _PostQuickActionState extends State { setState(() => _isSubmitting = true); - final resp = await client.post('/api/posts/${widget.item.alias}/react', { + final resp = await client.post('/posts/${widget.item.alias}/react', { 'symbol': symbol, 'attitude': attitude, }); @@ -74,7 +74,7 @@ class _PostQuickActionState extends State { void initState() { super.initState(); - if (!widget.isReactable && widget.item.reactionList.isEmpty) { + if (!widget.isReactable && widget.item.metric!.reactionList.isEmpty) { WidgetsBinding.instance.addPostFrameCallback((_) { widget.onReact('thumb_up', 0); }); @@ -95,7 +95,7 @@ class _PostQuickActionState extends State { if (widget.isReactable && widget.isShowReply) ActionChip( avatar: const Icon(Icons.comment), - label: Text(widget.item.replyCount.toString()), + label: Text(widget.item.metric!.replyCount.toString()), visualDensity: density, onPressed: () { showModalBottomSheet( @@ -119,7 +119,7 @@ class _PostQuickActionState extends State { shrinkWrap: true, scrollDirection: Axis.horizontal, children: [ - ...widget.item.reactionList.entries.map((x) { + ...widget.item.metric!.reactionList.entries.map((x) { final info = reactions[x.key]; return Padding( padding: const EdgeInsets.only(right: 8), diff --git a/lib/widgets/realms/realm_deletion.dart b/lib/widgets/realms/realm_deletion.dart index 146fdf5..9022928 100644 --- a/lib/widgets/realms/realm_deletion.dart +++ b/lib/widgets/realms/realm_deletion.dart @@ -27,9 +27,9 @@ class _RealmDeletionDialogState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); - final resp = await client.delete('/api/realms/${widget.realm.id}'); + final resp = await client.delete('/realms/${widget.realm.id}'); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); } else if (Navigator.canPop(context)) { @@ -45,10 +45,10 @@ class _RealmDeletionDialogState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); final resp = - await client.delete('/api/realms/${widget.realm.id}/members/me'); + await client.delete('/realms/${widget.realm.id}/members/me'); if (resp.statusCode != 200) { context.showErrorDialog(resp.bodyString); } else if (Navigator.canPop(context)) { diff --git a/lib/widgets/realms/realm_member.dart b/lib/widgets/realms/realm_member.dart index c2f7f92..068fe07 100644 --- a/lib/widgets/realms/realm_member.dart +++ b/lib/widgets/realms/realm_member.dart @@ -38,9 +38,9 @@ class _RealmMemberListPopupState extends State { void getMembers() async { setState(() => _isBusy = true); - final client = ServiceFinder.configureClient('passport'); + final client = ServiceFinder.configureClient('auth'); - final resp = await client.get('/api/realms/${widget.realm.alias}/members'); + final resp = await client.get('/realms/${widget.realm.alias}/members'); if (resp.statusCode == 200) { setState(() { _members = resp.body @@ -73,10 +73,10 @@ class _RealmMemberListPopupState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); final resp = await client.post( - '/api/realms/${widget.realm.alias}/members', + '/realms/${widget.realm.alias}/members', {'target': username}, ); if (resp.statusCode == 200) { @@ -94,10 +94,10 @@ class _RealmMemberListPopupState extends State { setState(() => _isBusy = true); - final client = auth.configureClient('passport'); + final client = auth.configureClient('auth'); final resp = await client.request( - '/api/realms/${widget.realm.alias}/members', + '/realms/${widget.realm.alias}/members', 'delete', body: {'target': item.account.name}, );