diff --git a/lib/bootstrapper.dart b/lib/bootstrapper.dart index 038bb57..13950bb 100644 --- a/lib/bootstrapper.dart +++ b/lib/bootstrapper.dart @@ -5,6 +5,7 @@ import 'package:provider/provider.dart'; import 'package:solian/exts.dart'; import 'package:solian/providers/auth.dart'; import 'package:solian/providers/content/channel.dart'; +import 'package:solian/providers/content/realm.dart'; import 'package:solian/providers/relation.dart'; import 'package:solian/providers/theme_switcher.dart'; import 'package:solian/providers/websocket.dart'; @@ -82,6 +83,7 @@ class _BootstrapperShellState extends State { final AuthProvider auth = Get.find(); if (auth.isAuthorized.isTrue) { await Future.wait([ + Get.find().refreshAvailableRealms(), Get.find().refreshAvailableChannel(), Get.find().refreshFriendList(), ]); diff --git a/lib/controllers/post_editor_controller.dart b/lib/controllers/post_editor_controller.dart index 4bcaf5e..b345bd8 100644 --- a/lib/controllers/post_editor_controller.dart +++ b/lib/controllers/post_editor_controller.dart @@ -8,6 +8,7 @@ import 'package:solian/models/realm.dart'; import 'package:solian/widgets/attachments/attachment_editor.dart'; import 'package:solian/widgets/posts/editor/post_editor_categories_tags.dart'; import 'package:solian/widgets/posts/editor/post_editor_overview.dart'; +import 'package:solian/widgets/posts/editor/post_editor_publish_zone.dart'; import 'package:solian/widgets/posts/editor/post_editor_visibility.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -88,6 +89,15 @@ class PostEditorController extends GetxController { ); } + Future editPublishZone(BuildContext context) { + return showDialog( + context: context, + builder: (context) => PostEditorPublishZoneDialog( + controller: this, + ), + ); + } + Future editAttachment(BuildContext context) { return showModalBottomSheet( context: context, diff --git a/lib/providers/content/realm.dart b/lib/providers/content/realm.dart index 96cc5dc..9432e57 100644 --- a/lib/providers/content/realm.dart +++ b/lib/providers/content/realm.dart @@ -1,7 +1,24 @@ import 'package:get/get.dart'; +import 'package:solian/models/realm.dart'; import 'package:solian/providers/auth.dart'; class RealmProvider extends GetxController { + RxBool isLoading = false.obs; + RxList availableRealms = RxList.empty(growable: true); + + Future refreshAvailableRealms() async { + final AuthProvider auth = Get.find(); + if (auth.isAuthorized.isFalse) throw Exception('unauthorized'); + + isLoading.value = true; + final resp = await listAvailableRealm(); + isLoading.value = false; + + availableRealms.value = + resp.body.map((x) => Realm.fromJson(x)).toList().cast(); + availableRealms.refresh(); + } + Future getRealm(String alias) async { final AuthProvider auth = Get.find(); if (auth.isAuthorized.isFalse) throw Exception('unauthorized'); diff --git a/lib/screens/posts/post_editor.dart b/lib/screens/posts/post_editor.dart index 44b513d..0a37e73 100644 --- a/lib/screens/posts/post_editor.dart +++ b/lib/screens/posts/post_editor.dart @@ -87,6 +87,9 @@ class _PostPublishScreenState extends State { if (widget.edit != null) { _editorController.editTarget = widget.edit; } + if (widget.realm != null) { + _editorController.realmZone.value = widget.realm; + } } void cancelAction() { @@ -220,18 +223,6 @@ class _PostPublishScreenState extends State { children: [ if (_isBusy) const LinearProgressIndicator().animate().scaleX(), - if (_realm != null) - MaterialBanner( - leading: const Icon(Icons.group), - leadingPadding: - const EdgeInsets.only(left: 10, right: 20), - dividerColor: Colors.transparent, - content: Text( - 'postInRealmNotify' - .trParams({'realm': '#${_realm!.alias}'}), - ), - actions: notifyBannerActions, - ), Container( padding: const EdgeInsets.symmetric( horizontal: 16, @@ -410,6 +401,23 @@ class _PostPublishScreenState extends State { _editorController.editCategoriesAndTags(context); }, ), + IconButton( + icon: Obx(() { + return badges.Badge( + showBadge: + _editorController.realmZone.value != null, + position: badges.BadgePosition.topEnd( + top: -4, + end: -6, + ), + child: const Icon(Icons.workspaces), + ); + }), + color: Theme.of(context).colorScheme.primary, + onPressed: () { + _editorController.editPublishZone(context); + }, + ), MarkdownToolbar( hideImage: true, useIncludedTextField: false, diff --git a/lib/translations/en_us.dart b/lib/translations/en_us.dart index 2a8775c..d6e29f9 100644 --- a/lib/translations/en_us.dart +++ b/lib/translations/en_us.dart @@ -101,6 +101,8 @@ const i18nEnglish = { 'postRestoreFromLocal': 'Restore from local', 'postAutoSaveAt': 'Auto saved at @date', 'postCategoriesAndTags': 'Categories n\' Tags', + 'postPublishZone': 'Publish Zone', + 'postPublishZoneNone': 'None', 'postVisibility': 'Visibility', 'postVisibilityAll': 'Everyone', 'postVisibilityFriends': 'Friends', diff --git a/lib/translations/zh_cn.dart b/lib/translations/zh_cn.dart index 49cd2f8..a074f65 100644 --- a/lib/translations/zh_cn.dart +++ b/lib/translations/zh_cn.dart @@ -95,6 +95,8 @@ const i18nSimplifiedChinese = { 'postRestoreFromLocal': '内容从本地暂存回复', 'postAutoSaveAt': '已自动保存于 @date', 'postCategoriesAndTags': '分类与标签', + 'postPublishZone': '帖子发布区', + 'postPublishZoneNone': '无所属领域', 'postVisibility': '帖子可见性', 'postVisibilityAll': '所有人可见', 'postVisibilityFriends': '仅好友可见', diff --git a/lib/widgets/posts/editor/post_editor_publish_zone.dart b/lib/widgets/posts/editor/post_editor_publish_zone.dart new file mode 100644 index 0000000..3f30ed1 --- /dev/null +++ b/lib/widgets/posts/editor/post_editor_publish_zone.dart @@ -0,0 +1,70 @@ +import 'package:dropdown_button2/dropdown_button2.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; +import 'package:solian/controllers/post_editor_controller.dart'; +import 'package:solian/providers/content/realm.dart'; + +class PostEditorPublishZoneDialog extends StatelessWidget { + final PostEditorController controller; + + const PostEditorPublishZoneDialog({super.key, required this.controller}); + + @override + Widget build(BuildContext context) { + final RealmProvider realms = Get.find(); + + return AlertDialog( + title: Text('postPublishZone'.tr), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Obx(() { + return DropdownButtonFormField2( + isExpanded: true, + decoration: const InputDecoration( + border: OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(8)), + ), + ), + items: [ + DropdownMenuItem( + value: null, + child: Text( + 'postPublishZoneNone'.tr, + style: const TextStyle(fontSize: 14), + ), + ), + ...realms.availableRealms.map( + (x) => DropdownMenuItem( + value: x.id, + child: Text( + '${x.name} (${x.alias})', + style: const TextStyle(fontSize: 14), + ), + ), + ), + ], + value: controller.realmZone.value?.id, + onChanged: (int? value) { + if (value == null) { + controller.realmZone.value = null; + } else { + controller.realmZone.value = + realms.availableRealms.firstWhere((x) => x.id == value); + } + }, + buttonStyleData: const ButtonStyleData(height: 20), + menuItemStyleData: const MenuItemStyleData(height: 40), + ); + }), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text('confirm'.tr), + ), + ], + ); + } +}