♻️ New post explore realm design

This commit is contained in:
LittleSheep 2025-03-08 18:43:58 +08:00
parent 060a97f5ec
commit a4f6e8af56
5 changed files with 130 additions and 17 deletions

View File

@ -768,5 +768,6 @@
"decrypting": "Decrypting……", "decrypting": "Decrypting……",
"decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online", "decryptingKeyNotFound": "Key not found or exchange failed, the other party may not be online",
"messageUnablePreview": "Unable preview", "messageUnablePreview": "Unable preview",
"messageUnablePreviewEncrypted": "Unable preview encrypted message" "messageUnablePreviewEncrypted": "Unable preview encrypted message",
"postViewInGlobalDescription": "Do not view the post in the specific realm."
} }

View File

@ -766,5 +766,6 @@
"decrypting": "解密中……", "decrypting": "解密中……",
"decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线", "decryptingKeyNotFound": "未找到密钥对或交换失败,对方可能不在线",
"messageUnablePreview": "无法预览消息", "messageUnablePreview": "无法预览消息",
"messageUnablePreviewEncrypted": "无法预览加密消息" "messageUnablePreviewEncrypted": "无法预览加密消息",
"postViewInGlobalDescription": "不查看特定领域的帖子。"
} }

View File

@ -137,6 +137,11 @@
"publisherRunBy": "由 {} 管理", "publisherRunBy": "由 {} 管理",
"fieldPublisherBelongToRealm": "所屬領域", "fieldPublisherBelongToRealm": "所屬領域",
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域", "fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
"writePost": "撰寫",
"postTypeStory": "動態",
"postTypeArticle": "文章",
"postTypeQuestion": "問題",
"postTypeVideo": "視頻",
"writePostTypeStory": "發動態", "writePostTypeStory": "發動態",
"writePostTypeArticle": "寫文章", "writePostTypeArticle": "寫文章",
"writePostTypeQuestion": "提問題", "writePostTypeQuestion": "提問題",
@ -761,5 +766,6 @@
"decrypting": "解密中……", "decrypting": "解密中……",
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線", "decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
"messageUnablePreview": "無法預覽消息", "messageUnablePreview": "無法預覽消息",
"messageUnablePreviewEncrypted": "無法預覽加密消息" "messageUnablePreviewEncrypted": "無法預覽加密消息",
"postViewInGlobalDescription": "不查看特定領域的帖子。"
} }

View File

@ -137,6 +137,11 @@
"publisherRunBy": "由 {} 管理", "publisherRunBy": "由 {} 管理",
"fieldPublisherBelongToRealm": "所屬領域", "fieldPublisherBelongToRealm": "所屬領域",
"fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域", "fieldPublisherBelongToRealmUnset": "未設置發佈者所屬領域",
"writePost": "撰寫",
"postTypeStory": "動態",
"postTypeArticle": "文章",
"postTypeQuestion": "問題",
"postTypeVideo": "視頻",
"writePostTypeStory": "發動態", "writePostTypeStory": "發動態",
"writePostTypeArticle": "寫文章", "writePostTypeArticle": "寫文章",
"writePostTypeQuestion": "提問題", "writePostTypeQuestion": "提問題",
@ -761,5 +766,6 @@
"decrypting": "解密中……", "decrypting": "解密中……",
"decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線", "decryptingKeyNotFound": "未找到密鑰對或交換失敗,對方可能不在線",
"messageUnablePreview": "無法預覽消息", "messageUnablePreview": "無法預覽消息",
"messageUnablePreviewEncrypted": "無法預覽加密消息" "messageUnablePreviewEncrypted": "無法預覽加密消息",
"postViewInGlobalDescription": "不查看特定領域的帖子。"
} }

View File

@ -11,6 +11,7 @@ import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/sn_realm.dart'; import 'package:surface/providers/sn_realm.dart';
import 'package:surface/types/post.dart'; import 'package:surface/types/post.dart';
import 'package:surface/types/realm.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/app_bar_leading.dart';
import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart'; import 'package:surface/widgets/navigation/app_scaffold.dart';
@ -42,10 +43,13 @@ class ExploreScreen extends StatefulWidget {
class _ExploreScreenState extends State<ExploreScreen> class _ExploreScreenState extends State<ExploreScreen>
with TickerProviderStateMixin { with TickerProviderStateMixin {
late TabController _tabController = TabController(length: 3, vsync: this); late TabController _tabController = TabController(
length: kPostChannels.length,
vsync: this,
);
final _fabKey = GlobalKey<ExpandableFabState>(); final _fabKey = GlobalKey<ExpandableFabState>();
final _listKeys = GlobalKey<_PostListWidgetState>(); final _listKey = GlobalKey<_PostListWidgetState>();
bool _showCategories = false; bool _showCategories = false;
@ -88,7 +92,7 @@ class _ExploreScreenState extends State<ExploreScreen>
if (_showCategories) { if (_showCategories) {
_tabController = TabController(length: _categories.length, vsync: this); _tabController = TabController(length: _categories.length, vsync: this);
} else { } else {
_tabController = TabController(length: 4, vsync: this); _tabController = TabController(length: kPostChannels.length, vsync: this);
} }
_tabListen(); _tabListen();
setState(() {}); setState(() {});
@ -98,24 +102,23 @@ class _ExploreScreenState extends State<ExploreScreen>
_tabController.addListener(() { _tabController.addListener(() {
if (_tabController.indexIsChanging) { if (_tabController.indexIsChanging) {
if (_showCategories) { if (_showCategories) {
_listKeys.currentState _listKey.currentState?.setCategory(_categories[_tabController.index]);
?.setCategory(_categories[_tabController.index]); _listKey.currentState?.refreshPosts();
_listKeys.currentState?.refreshPosts();
return; return;
} }
switch (_tabController.index) { switch (_tabController.index) {
case 0: case 0:
case 3: case 3:
_listKeys.currentState?.setChannel(null); _listKey.currentState?.setChannel(null);
break; break;
case 1: case 1:
_listKeys.currentState?.setChannel('friends'); _listKey.currentState?.setChannel('friends');
break; break;
case 2: case 2:
_listKeys.currentState?.setChannel('following'); _listKey.currentState?.setChannel('following');
break; break;
} }
_listKeys.currentState?.refreshPosts(); _listKey.currentState?.refreshPosts();
} }
}); });
} }
@ -135,7 +138,7 @@ class _ExploreScreenState extends State<ExploreScreen>
} }
Future<void> refreshPosts() async { Future<void> refreshPosts() async {
await _listKeys.currentState?.refreshPosts(); await _listKey.currentState?.refreshPosts();
} }
@override @override
@ -198,7 +201,45 @@ class _ExploreScreenState extends State<ExploreScreen>
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context), handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar( sliver: SliverAppBar(
leading: AutoAppBarLeading(), 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, floating: true,
snap: true, snap: true,
actions: [ actions: [
@ -294,7 +335,7 @@ class _ExploreScreenState extends State<ExploreScreen>
]; ];
}, },
body: _PostListWidget( body: _PostListWidget(
key: _listKeys, key: _listKey,
), ),
), ),
); );
@ -311,6 +352,8 @@ class _PostListWidget extends StatefulWidget {
class _PostListWidgetState extends State<_PostListWidget> { class _PostListWidgetState extends State<_PostListWidget> {
bool _isBusy = false; bool _isBusy = false;
SnRealm? get realm => _selectedRealm;
final List<SnPost> _posts = List.empty(growable: true); final List<SnPost> _posts = List.empty(growable: true);
SnRealm? _selectedRealm; SnRealm? _selectedRealm;
String? _selectedChannel; String? _selectedChannel;
@ -430,3 +473,59 @@ class _PostListWidgetState extends State<_PostListWidget> {
); );
} }
} }
class _PostListRealmPopup extends StatelessWidget {
final List<SnRealm>? 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);
},
);
},
),
),
],
);
}
}