diff --git a/lib/i18n/app_en.arb b/lib/i18n/app_en.arb index 9cd0cf1..e7a0c28 100644 --- a/lib/i18n/app_en.arb +++ b/lib/i18n/app_en.arb @@ -28,6 +28,7 @@ "birthday": "Birthday", "password": "Password", "next": "Next", + "join": "Join", "edit": "Edit", "apply": "Apply", "delete": "Delete", @@ -95,6 +96,9 @@ "chatDetail": "Chat Details", "chatMember": "Member", "chatNotifySetting": "Notify Settings", + "chatChannelUnavailable": "Channel Unavailable", + "chatChannelUnavailableCaptionWithRealm": "You didn't join the channel, but looks like you able to join to, would you want to have a try?", + "chatChannelUnavailableCaption": "You didn't join the channel, so you cannot access the information of this channel.", "chatChannelUsage": "Channel", "chatChannelUsageCaption": "Channel is place to talk with people, one or a lot.", "chatChannelOrganize": "Organize a channel", diff --git a/lib/i18n/app_zh.arb b/lib/i18n/app_zh.arb index 7525bd3..faa71ff 100644 --- a/lib/i18n/app_zh.arb +++ b/lib/i18n/app_zh.arb @@ -2,6 +2,7 @@ "appName": "Solar Network", "explore": "探索", "chat": "聊天", + "realm": "领域", "account": "账号", "riskDetection": "风险监测", "signIn": "登录", @@ -27,6 +28,7 @@ "birthday": "生日", "password": "密码", "next": "下一步", + "join": "加入", "edit": "编辑", "delete": "删除", "action": "操作", @@ -74,10 +76,27 @@ "postEditNotify": "你正在修改一个已经发布了的帖子。", "reactionAdded": "你的反应已被添加。", "reactionRemoved": "你的反应已被移除。", + "realmNew": "新领域", + "realmNewCreate": "创建新领域", + "realmNewJoin": "加入现有领域", + "realmUsage": "领域", + "realmUsageCaption": "领域是一个地方给你来组织帖子、文章、聊天频道的,好好利用领域打造一个绝妙的专属于你的社区吧!", + "realmEstablish": "部署领域", + "realmEditNotify": "你正在修改一个现有领域……", + "realmAliasLabel": "领域别名", + "realmNameLabel": "领域名称", + "realmDescriptionLabel": "领域简介", + "realmPublicLabel": "公共领域", + "realmCommunityLabel": "社区领域(任何人均可加入)", + "realmMember": "成员", + "realmManage": "领域管理", "chatNew": "新聊天", "chatDetail": "聊天详情", "chatMember": "成员", "chatNotifySetting": "通知设定", + "chatChannelUnavailable": "频道不可用", + "chatChannelUnavailableCaptionWithRealm": "你没加入该频道,但是看起来你能加入本频道,你想加入吗?", + "chatChannelUnavailableCaption": "你没加入该频道,所以你无法读取本频道的信息。", "chatNewCreate": "新建频道", "chatNewJoin": "加入已有频道", "chatChannelUsage": "频道", diff --git a/lib/models/channel.dart b/lib/models/channel.dart index b3df743..f4b0290 100644 --- a/lib/models/channel.dart +++ b/lib/models/channel.dart @@ -15,6 +15,8 @@ class Channel { int accountId; int? realmId; + bool isAvailable = false; + Channel({ required this.id, required this.createdAt, diff --git a/lib/providers/chat.dart b/lib/providers/chat.dart index 893c25c..23b9694 100644 --- a/lib/providers/chat.dart +++ b/lib/providers/chat.dart @@ -44,14 +44,13 @@ class ChatProvider extends ChangeNotifier { return channel; } - Future fetchChannel(String alias, String realm) async { - final Client client = Client(); - - var uri = getRequestUri('messaging', '/api/channels/$realm/$alias'); - var res = await client.get(uri); - if (res.statusCode == 200) { + Future fetchChannel(AuthProvider auth, String alias, String realm) async { + var uri = getRequestUri('messaging', '/api/channels/$realm/$alias/availability'); + var res = await auth.client!.get(uri); + if (res.statusCode == 200 || res.statusCode == 403) { final result = jsonDecode(utf8.decode(res.bodyBytes)); focusChannel = Channel.fromJson(result); + focusChannel?.isAvailable = res.statusCode == 200; notifyListeners(); return focusChannel!; } else { diff --git a/lib/screens/chat/chat.dart b/lib/screens/chat/chat.dart index 3f93b71..ffe5b8b 100644 --- a/lib/screens/chat/chat.dart +++ b/lib/screens/chat/chat.dart @@ -16,6 +16,7 @@ import 'package:solian/widgets/chat/chat_maintainer.dart'; import 'package:solian/widgets/chat/message.dart'; import 'package:solian/widgets/chat/message_action.dart'; import 'package:solian/widgets/chat/message_editor.dart'; +import 'package:solian/widgets/exts.dart'; import 'package:solian/widgets/scaffold.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -27,6 +28,7 @@ class ChatScreen extends StatelessWidget { @override Widget build(BuildContext context) { + final auth = context.read(); final chat = context.watch(); return IndentScaffold( @@ -39,12 +41,12 @@ class ChatScreen extends StatelessWidget { call: chat.ongoingCall, channel: chat.focusChannel!, realm: realm, - onUpdate: () => chat.fetchChannel(chat.focusChannel!.alias, realm), + onUpdate: () => chat.fetchChannel(auth, chat.focusChannel!.alias, realm), ), ChannelManageAction( channel: chat.focusChannel!, realm: realm, - onUpdate: () => chat.fetchChannel(chat.focusChannel!.alias, realm), + onUpdate: () => chat.fetchChannel(auth, chat.focusChannel!.alias, realm), ), ] : [], @@ -96,11 +98,34 @@ class _ChatWidgetState extends State { final nextPageKey = pageKey + items.length; _pagingController.appendPage(items, nextPageKey); } + } else if (res.statusCode == 403) { + _pagingController.appendLastPage([]); } else { _pagingController.error = utf8.decode(res.bodyBytes); } } + Future joinChannel() async { + final auth = context.read(); + if (!await auth.isAuthorized()) return; + + var uri = getRequestUri( + 'messaging', + '/api/channels/${widget.realm}/${widget.alias}/members/me', + ); + + var res = await auth.client!.post(uri); + if (res.statusCode == 200) { + setState(() {}); + _pagingController.refresh(); + } else { + var message = utf8.decode(res.bodyBytes); + context.showErrorDialog(message).then((_) { + SolianRouter.router.pop(); + }); + } + } + bool getMessageMergeable(Message? a, Message? b) { if (a?.replyTo != null) return false; if (a == null || b == null) return false; @@ -145,15 +170,55 @@ class _ChatWidgetState extends State { ); } + void showUnavailableDialog() { + final content = widget.realm == 'global' + ? AppLocalizations.of(context)!.chatChannelUnavailableCaption + : AppLocalizations.of(context)!.chatChannelUnavailableCaptionWithRealm; + + showDialog( + context: context, + barrierDismissible: false, + builder: (context) => AlertDialog( + title: Text(AppLocalizations.of(context)!.chatChannelUnavailable), + content: Text(content), + actions: [ + TextButton( + child: Text(AppLocalizations.of(context)!.cancel), + onPressed: () { + Navigator.of(context).pop(); + SolianRouter.router.pop(); + }, + ), + ...(widget.realm != 'global' + ? [ + TextButton( + child: Text(AppLocalizations.of(context)!.join), + onPressed: () { + Navigator.of(context).pop(); + joinChannel(); + }, + ), + ] + : []) + ], + ), + ); + } + @override void initState() { _pagingController.addPageRequestListener((pageKey) => fetchMessages(pageKey, context)); super.initState(); - Future.delayed(Duration.zero, () { + Future.delayed(Duration.zero, () async { + final auth = context.read(); _chat.fetchOngoingCall(widget.alias, widget.realm); - _chat.fetchChannel(widget.alias, widget.realm); + _chat.fetchChannel(auth, widget.alias, widget.realm).then((result) { + if (result.isAvailable == false) { + showUnavailableDialog(); + } + }); }); } diff --git a/lib/widgets/posts/post_deletion.dart b/lib/widgets/posts/post_deletion.dart index b24f22f..8012e0e 100644 --- a/lib/widgets/posts/post_deletion.dart +++ b/lib/widgets/posts/post_deletion.dart @@ -29,8 +29,7 @@ class _ItemDeletionDialogState extends State { final auth = context.read(); if (!await auth.isAuthorized()) return; - final uri = - getRequestUri('interactive', '/api/p/moments/${widget.item.id}'); + final uri = getRequestUri('interactive', '/api/p/${widget.item.modelType}s/${widget.item.id}'); setState(() => _isSubmitting = true); final res = await auth.client!.delete(uri);