From a4f6e8af566c5644b72801de39f4699eba8ab8a6 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sat, 8 Mar 2025 18:43:58 +0800 Subject: [PATCH] :recycle: New post explore realm design --- assets/translations/en-US.json | 3 +- assets/translations/zh-CN.json | 3 +- assets/translations/zh-HK.json | 8 ++- assets/translations/zh-TW.json | 8 ++- lib/screens/explore.dart | 125 +++++++++++++++++++++++++++++---- 5 files changed, 130 insertions(+), 17 deletions(-) diff --git a/assets/translations/en-US.json b/assets/translations/en-US.json index 115340c..87ee809 100644 --- a/assets/translations/en-US.json +++ b/assets/translations/en-US.json @@ -768,5 +768,6 @@ "decrypting": "Decrypting……", "decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online", "messageUnablePreview": "Unable preview", - "messageUnablePreviewEncrypted": "Unable preview encrypted message" + "messageUnablePreviewEncrypted": "Unable preview encrypted message", + "postViewInGlobalDescription": "Do not view the post in the specific realm." } diff --git a/assets/translations/zh-CN.json b/assets/translations/zh-CN.json index 330c29b..6690b7f 100644 --- a/assets/translations/zh-CN.json +++ b/assets/translations/zh-CN.json @@ -766,5 +766,6 @@ "decrypting": "解密中……", "decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线", "messageUnablePreview": "无法预览消息", - "messageUnablePreviewEncrypted": "无法预览加密消息" + "messageUnablePreviewEncrypted": "无法预览加密消息", + "postViewInGlobalDescription": "不查看特定领域的帖子。" } diff --git a/assets/translations/zh-HK.json b/assets/translations/zh-HK.json index 2ed18a3..46dd946 100644 --- a/assets/translations/zh-HK.json +++ b/assets/translations/zh-HK.json @@ -137,6 +137,11 @@ "publisherRunBy": "由 {} 管理", "fieldPublisherBelongToRealm": "所屬領域", "fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域", + "writePost": "撰寫", + "postTypeStory": "動態", + "postTypeArticle": "文章", + "postTypeQuestion": "問題", + "postTypeVideo": "視頻", "writePostTypeStory": "發動態", "writePostTypeArticle": "寫文章", "writePostTypeQuestion": "提問題", @@ -761,5 +766,6 @@ "decrypting": "解密中……", "decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線", "messageUnablePreview": "無法預覽消息", - "messageUnablePreviewEncrypted": "無法預覽加密消息" + "messageUnablePreviewEncrypted": "無法預覽加密消息", + "postViewInGlobalDescription": "不查看特定領域的帖子。" } diff --git a/assets/translations/zh-TW.json b/assets/translations/zh-TW.json index 1960c99..3e339a7 100644 --- a/assets/translations/zh-TW.json +++ b/assets/translations/zh-TW.json @@ -137,6 +137,11 @@ "publisherRunBy": "由 {} 管理", "fieldPublisherBelongToRealm": "所屬領域", "fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域", + "writePost": "撰寫", + "postTypeStory": "動態", + "postTypeArticle": "文章", + "postTypeQuestion": "問題", + "postTypeVideo": "視頻", "writePostTypeStory": "發動態", "writePostTypeArticle": "寫文章", "writePostTypeQuestion": "提問題", @@ -761,5 +766,6 @@ "decrypting": "解密中……", "decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線", "messageUnablePreview": "無法預覽消息", - "messageUnablePreviewEncrypted": "無法預覽加密消息" + "messageUnablePreviewEncrypted": "無法預覽加密消息", + "postViewInGlobalDescription": "不查看特定領域的帖子。" } diff --git a/lib/screens/explore.dart b/lib/screens/explore.dart index 99c60cd..b511715 100644 --- a/lib/screens/explore.dart +++ b/lib/screens/explore.dart @@ -11,6 +11,7 @@ import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_realm.dart'; import 'package:surface/types/post.dart'; import 'package:surface/types/realm.dart'; +import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/app_bar_leading.dart'; import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/navigation/app_scaffold.dart'; @@ -42,10 +43,13 @@ class ExploreScreen extends StatefulWidget { class _ExploreScreenState extends State with TickerProviderStateMixin { - late TabController _tabController = TabController(length: 3, vsync: this); + late TabController _tabController = TabController( + length: kPostChannels.length, + vsync: this, + ); final _fabKey = GlobalKey(); - final _listKeys = GlobalKey<_PostListWidgetState>(); + final _listKey = GlobalKey<_PostListWidgetState>(); bool _showCategories = false; @@ -88,7 +92,7 @@ class _ExploreScreenState extends State if (_showCategories) { _tabController = TabController(length: _categories.length, vsync: this); } else { - _tabController = TabController(length: 4, vsync: this); + _tabController = TabController(length: kPostChannels.length, vsync: this); } _tabListen(); setState(() {}); @@ -98,24 +102,23 @@ class _ExploreScreenState extends State _tabController.addListener(() { if (_tabController.indexIsChanging) { if (_showCategories) { - _listKeys.currentState - ?.setCategory(_categories[_tabController.index]); - _listKeys.currentState?.refreshPosts(); + _listKey.currentState?.setCategory(_categories[_tabController.index]); + _listKey.currentState?.refreshPosts(); return; } switch (_tabController.index) { case 0: case 3: - _listKeys.currentState?.setChannel(null); + _listKey.currentState?.setChannel(null); break; case 1: - _listKeys.currentState?.setChannel('friends'); + _listKey.currentState?.setChannel('friends'); break; case 2: - _listKeys.currentState?.setChannel('following'); + _listKey.currentState?.setChannel('following'); break; } - _listKeys.currentState?.refreshPosts(); + _listKey.currentState?.refreshPosts(); } }); } @@ -135,7 +138,7 @@ class _ExploreScreenState extends State } Future refreshPosts() async { - await _listKeys.currentState?.refreshPosts(); + await _listKey.currentState?.refreshPosts(); } @override @@ -198,7 +201,45 @@ class _ExploreScreenState extends State handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), sliver: SliverAppBar( leading: AutoAppBarLeading(), - title: Text('screenExplore').tr(), + titleSpacing: 0, + title: Row( + children: [ + IconButton( + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + visualDensity: VisualDensity.compact, + icon: _listKey.currentState?.realm != null + ? AccountImage( + content: _listKey.currentState!.realm!.avatar, + radius: 14, + ) + : const Icon(Symbols.group), + onPressed: () { + showModalBottomSheet( + context: context, + builder: (context) => _PostListRealmPopup( + realms: _realms, + onUpdate: (realm) { + _listKey.currentState?.setRealm(realm); + _listKey.currentState?.refreshPosts(); + Future.delayed(const Duration(milliseconds: 100), + () { + if (mounted) { + setState(() {}); + } + }); + }, + ), + ); + }, + ), + Expanded( + child: Center( + child: Text('screenExplore').tr(), + ), + ), + ], + ), floating: true, snap: true, actions: [ @@ -294,7 +335,7 @@ class _ExploreScreenState extends State ]; }, body: _PostListWidget( - key: _listKeys, + key: _listKey, ), ), ); @@ -311,6 +352,8 @@ class _PostListWidget extends StatefulWidget { class _PostListWidgetState extends State<_PostListWidget> { bool _isBusy = false; + SnRealm? get realm => _selectedRealm; + final List _posts = List.empty(growable: true); SnRealm? _selectedRealm; String? _selectedChannel; @@ -430,3 +473,59 @@ class _PostListWidgetState extends State<_PostListWidget> { ); } } + +class _PostListRealmPopup extends StatelessWidget { + final List? realms; + final Function(SnRealm?) onUpdate; + + const _PostListRealmPopup({ + required this.realms, + required this.onUpdate, + }); + + @override + Widget build(BuildContext context) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Icon(Symbols.face, size: 24), + const Gap(16), + Text('accountRealms', style: Theme.of(context).textTheme.titleLarge) + .tr(), + ], + ).padding(horizontal: 20, top: 16, bottom: 12), + ListTile( + leading: const Icon(Symbols.close), + title: Text('postInGlobal').tr(), + subtitle: Text('postViewInGlobalDescription').tr(), + contentPadding: const EdgeInsets.symmetric(horizontal: 24), + onTap: () { + onUpdate.call(null); + Navigator.pop(context); + }, + ), + const Divider(height: 1), + Expanded( + child: ListView.builder( + itemCount: realms?.length ?? 0, + itemBuilder: (context, idx) { + final realm = realms![idx]; + return ListTile( + title: Text(realm.name), + subtitle: Text('@${realm.alias}'), + leading: AccountImage(content: realm.avatar, radius: 18), + onTap: () { + onUpdate.call(realm); + Navigator.pop(context); + }, + ); + }, + ), + ), + ], + ); + } +}