diff --git a/lib/router.dart b/lib/router.dart index 0d8ea79..09ccd16 100644 --- a/lib/router.dart +++ b/lib/router.dart @@ -2,6 +2,7 @@ import 'package:animations/animations.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:solian/bootstrapper.dart'; +import 'package:solian/models/post.dart'; import 'package:solian/models/realm.dart'; import 'package:solian/screens/about.dart'; import 'package:solian/screens/account.dart'; @@ -108,6 +109,7 @@ abstract class AppRouter { state: state, child: PostDetailScreen( id: state.pathParameters['id']!, + post: state.extra as Post?, ), ), ), diff --git a/lib/screens/chat.dart b/lib/screens/chat.dart index 4d462e1..a64cb2c 100644 --- a/lib/screens/chat.dart +++ b/lib/screens/chat.dart @@ -19,6 +19,7 @@ import 'package:solian/widgets/app_bar_title.dart'; import 'package:solian/widgets/channel/channel_list.dart'; import 'package:solian/widgets/chat/call/chat_call_indicator.dart'; import 'package:solian/widgets/current_state_action.dart'; +import 'package:solian/widgets/loading_indicator.dart'; import 'package:solian/widgets/root_container.dart'; import 'package:solian/widgets/sidebar/empty_placeholder.dart'; @@ -280,26 +281,7 @@ class _ChatListState extends State { return Column( children: [ const ChatCallCurrentIndicator(), - if (_isBusy) - Container( - color: Theme.of(context) - .colorScheme - .surfaceContainerLow - .withOpacity(0.8), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox( - height: 16, - width: 16, - child: CircularProgressIndicator(strokeWidth: 2.5), - ), - const Gap(8), - Text('loading'.tr) - ], - ).paddingSymmetric(vertical: 8), - ), + if (_isBusy) const LoadingIndicator(), Expanded( child: TabBarView( children: [ diff --git a/lib/screens/posts/post_detail.dart b/lib/screens/posts/post_detail.dart index a98f0c1..2fc16da 100644 --- a/lib/screens/posts/post_detail.dart +++ b/lib/screens/posts/post_detail.dart @@ -5,6 +5,7 @@ import 'package:solian/models/post.dart'; import 'package:solian/providers/content/posts.dart'; import 'package:solian/providers/last_read.dart'; import 'package:solian/theme.dart'; +import 'package:solian/widgets/loading_indicator.dart'; import 'package:solian/widgets/posts/post_item.dart'; import 'package:solian/widgets/posts/post_replies.dart'; @@ -23,87 +24,91 @@ class PostDetailScreen extends StatefulWidget { } class _PostDetailScreenState extends State { - Post? item; + bool _isBusy = true; - Future _getDetail() async { - if (widget.post != null) { - setState(() { - item = widget.post; - }); - } + Post? _item; - final PostProvider provider = Get.find(); + Future _getDetail() async { + final PostProvider posts = Get.find(); try { - final resp = await provider.getPost(widget.id); - item = Post.fromJson(resp.body); + final resp = await posts.getPost(widget.id); + _item = Post.fromJson(resp.body); } catch (e) { context.showErrorDialog(e).then((_) => Navigator.pop(context)); } - Get.find().feedLastReadAt = item?.id; + Get.find().feedLastReadAt = _item?.id; - return item; + setState(() => _isBusy = false); + } + + @override + void initState() { + super.initState(); + if (widget.post != null) { + _item = widget.post; + } + _getDetail(); } @override Widget build(BuildContext context) { - return FutureBuilder( - future: _getDetail(), - builder: (context, snapshot) { - if (!snapshot.hasData || snapshot.data == null) { - return const Center( - child: CircularProgressIndicator(), - ); - } + if (_isBusy && _item == null) { + return const Center( + child: CircularProgressIndicator(), + ); + } - return CustomScrollView( - slivers: [ - SliverToBoxAdapter( - child: PostItem( - item: item!, - isClickable: false, - isOverrideEmbedClickable: true, - isFullDate: true, - isShowReply: false, - isContentSelectable: true, - padding: AppTheme.isLargeScreen(context) - ? EdgeInsets.symmetric( - horizontal: 4, - vertical: 8, - ) - : EdgeInsets.zero, - ), - ), - SliverToBoxAdapter( - child: const Divider(thickness: 0.3, height: 1).paddingOnly( - top: 8, - ), - ), - SliverToBoxAdapter( - child: Align( - alignment: Alignment.centerLeft, - child: Text( - 'postReplies'.tr, - style: Theme.of(context).textTheme.headlineSmall, - ).paddingOnly(left: 24, right: 24, top: 16), - ), - ), - PostReplyList( - item: item!, - padding: AppTheme.isLargeScreen(context) - ? EdgeInsets.symmetric( - horizontal: 4, - vertical: 8, - ) - : EdgeInsets.zero, - ), - SliverToBoxAdapter( - child: SizedBox(height: MediaQuery.of(context).padding.bottom), - ), - ], - ); - }, + return CustomScrollView( + slivers: [ + if (_isBusy) + SliverToBoxAdapter( + child: LoadingIndicator(), + ), + SliverToBoxAdapter( + child: PostItem( + item: _item!, + isClickable: false, + isOverrideEmbedClickable: true, + isFullDate: true, + isShowReply: false, + isContentSelectable: true, + padding: AppTheme.isLargeScreen(context) + ? EdgeInsets.symmetric( + horizontal: 4, + vertical: 8, + ) + : EdgeInsets.zero, + ), + ), + SliverToBoxAdapter( + child: const Divider(thickness: 0.3, height: 1).paddingOnly( + top: 8, + ), + ), + SliverToBoxAdapter( + child: Align( + alignment: Alignment.centerLeft, + child: Text( + 'postReplies'.tr, + style: Theme.of(context).textTheme.headlineSmall, + ).paddingOnly(left: 24, right: 24, top: 16), + ), + ), + PostReplyList( + item: _item!, + padding: AppTheme.isLargeScreen(context) + ? EdgeInsets.symmetric( + horizontal: 4, + vertical: 8, + ) + : EdgeInsets.zero, + ), + SliverToBoxAdapter( + child: SizedBox(height: MediaQuery.of(context).padding.bottom), + ), + ], ); } } diff --git a/lib/widgets/loading_indicator.dart b/lib/widgets/loading_indicator.dart new file mode 100644 index 0000000..7f8f910 --- /dev/null +++ b/lib/widgets/loading_indicator.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:get/get.dart'; + +class LoadingIndicator extends StatelessWidget { + const LoadingIndicator({super.key}); + + @override + Widget build(BuildContext context) { + return Container( + padding: const EdgeInsets.symmetric(vertical: 16, horizontal: 24), + color: Theme.of(context).colorScheme.surfaceContainerLow.withOpacity(0.8), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const SizedBox( + height: 16, + width: 16, + child: CircularProgressIndicator(strokeWidth: 2.5), + ), + const Gap(8), + Text('loading'.tr) + ], + ), + ); + } +} diff --git a/lib/widgets/posts/post_item.dart b/lib/widgets/posts/post_item.dart index ace08a4..ab4d749 100644 --- a/lib/widgets/posts/post_item.dart +++ b/lib/widgets/posts/post_item.dart @@ -250,6 +250,7 @@ class _PostItemState extends State { AppRouter.instance.pushNamed( 'postDetail', pathParameters: {'id': item.id.toString()}, + extra: item, ); } },