Better post list

This commit is contained in:
2024-07-06 21:14:19 +08:00
parent 66ddfea68d
commit 343b84e3e1
7 changed files with 137 additions and 147 deletions

View File

@ -40,20 +40,12 @@ abstract class AppRouter {
);
static final ShellRoute _feedRoute = ShellRoute(
builder: (context, state, child) => BasicShell(
state: state,
sidebarFirst: true,
showAppBar: false,
sidebar: const FeedScreen(),
child: child,
),
builder: (context, state, child) => child,
routes: [
GoRoute(
path: '/',
name: 'feed',
builder: (context, state) => SolianTheme.isExtraLargeScreen(context)
? const EmptyPagePlaceholder()
: const FeedScreen(),
builder: (context, state) => const FeedScreen(),
),
GoRoute(
path: '/posts/view/:alias',

View File

@ -3,6 +3,7 @@ import 'package:get/get.dart';
import 'package:solian/exts.dart';
import 'package:solian/models/post.dart';
import 'package:solian/providers/content/post.dart';
import 'package:solian/widgets/centered_container.dart';
import 'package:solian/widgets/posts/post_item.dart';
import 'package:solian/widgets/posts/post_replies.dart';
@ -47,21 +48,29 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: PostItem(
item: item!,
isClickable: true,
isFullDate: true,
isShowReply: false,
child: CenteredContainer(
child: PostItem(
item: item!,
isClickable: true,
isFullDate: true,
isShowReply: false,
),
),
),
const SliverToBoxAdapter(
child: Divider(thickness: 0.3, height: 0.3),
SliverToBoxAdapter(
child: const Divider(thickness: 0.3, height: 1)
.paddingOnly(top: 4),
),
SliverToBoxAdapter(
child: Text(
'postReplies'.tr,
style: Theme.of(context).textTheme.headlineSmall,
).paddingOnly(left: 24, right: 24, top: 16),
child: CenteredContainer(
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!),
SliverToBoxAdapter(

View File

@ -0,0 +1,43 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:go_router/go_router.dart';
import 'package:solian/router.dart';
import 'package:solian/theme.dart';
import 'package:solian/widgets/app_bar_title.dart';
import 'package:solian/widgets/prev_page.dart';
class CenteredShell extends StatelessWidget {
final bool showAppBar;
final GoRouterState state;
final Widget child;
const CenteredShell({
super.key,
required this.child,
required this.state,
this.showAppBar = true,
});
@override
Widget build(BuildContext context) {
final canPop = AppRouter.instance.canPop();
return Scaffold(
appBar: showAppBar
? AppBar(
title: AppBarTitle(state.topRoute?.name?.tr ?? 'page'.tr),
centerTitle: false,
toolbarHeight: SolianTheme.toolbarHeight(context),
leading: canPop ? const PrevPageButton() : null,
automaticallyImplyLeading: false,
)
: null,
body: Center(
child: Container(
constraints: const BoxConstraints(maxWidth: 640),
child: child,
),
),
);
}
}

View File

@ -1,89 +0,0 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:solian/router.dart';
import 'package:solian/theme.dart';
import 'package:solian/widgets/navigation/app_navigation.dart';
import 'package:solian/widgets/prev_page.dart';
import 'package:solian/widgets/navigation/app_navigation_bottom_bar.dart';
import 'package:solian/widgets/navigation/app_navigation_rail.dart';
import 'package:solian/widgets/sidebar/sidebar_placeholder.dart';
class NavShell extends StatelessWidget {
final bool showAppBar;
final bool showSidebar;
final bool showNavigation;
final bool? showBottomNavigation;
final Widget child;
final bool sidebarFirst;
final Widget? sidebar;
const NavShell({
super.key,
required this.child,
this.showAppBar = true,
this.showSidebar = true,
this.showNavigation = true,
this.showBottomNavigation,
this.sidebarFirst = false,
this.sidebar,
});
List<Widget> buildContent(BuildContext context) {
return [
Flexible(
flex: 2,
child: child,
),
if (SolianTheme.isExtraLargeScreen(context))
const VerticalDivider(thickness: 0.3, width: 1),
if (SolianTheme.isExtraLargeScreen(context))
Flexible(
flex: 1,
child: sidebar ?? const SidebarPlaceholder(),
),
];
}
@override
Widget build(BuildContext context) {
final canPop = AppRouter.instance.canPop();
final routeName =
AppRouter.instance.routerDelegate.currentConfiguration.last.route.name;
final showBottom = showBottomNavigation ??
AppNavigation.destinationPages.contains(routeName);
return Scaffold(
appBar: showAppBar
? AppBar(
title: Text(routeName ?? 'page'.tr),
centerTitle: false,
titleSpacing: canPop ? null : 24,
elevation: SolianTheme.isLargeScreen(context) ? 1 : 0,
leading: canPop ? const PrevPageButton() : null,
automaticallyImplyLeading: false,
)
: null,
bottomNavigationBar: (SolianTheme.isLargeScreen(context) ||
!(showNavigation && showBottom))
? null
: const AppNavigationBottomBar(),
body: SolianTheme.isLargeScreen(context)
? Row(
children: [
if (showNavigation) const AppNavigationRail(),
if (showNavigation)
const VerticalDivider(thickness: 0.3, width: 1),
if (showSidebar && sidebarFirst)
...buildContent(context).reversed
else if (showSidebar)
...buildContent(context)
else
Expanded(child: child),
],
)
: child,
);
}
}

View File

@ -0,0 +1,22 @@
import 'package:flutter/material.dart';
class CenteredContainer extends StatelessWidget {
final Widget child;
final double maxWidth;
const CenteredContainer({
super.key,
required this.child,
this.maxWidth = 720,
});
@override
Widget build(BuildContext context) {
return Center(
child: Container(
constraints: BoxConstraints(maxWidth: maxWidth),
child: child,
),
);
}
}

View File

@ -3,6 +3,7 @@ import 'package:get/get.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
import 'package:solian/models/post.dart';
import 'package:solian/router.dart';
import 'package:solian/widgets/centered_container.dart';
import 'package:solian/widgets/posts/post_action.dart';
import 'package:solian/widgets/posts/post_item.dart';
@ -27,29 +28,31 @@ class PostListWidget extends StatelessWidget {
builderDelegate: PagedChildBuilderDelegate<Post>(
itemBuilder: (context, item, index) {
return RepaintBoundary(
child: GestureDetector(
child: PostItem(
key: Key('p${item.alias}'),
item: item,
isShowEmbed: isShowEmbed,
isClickable: isNestedClickable,
).paddingSymmetric(vertical: 8),
onTap: () {
if (!isClickable) return;
AppRouter.instance.pushNamed(
'postDetail',
pathParameters: {'alias': item.alias},
);
},
onLongPress: () {
showModalBottomSheet(
useRootNavigator: true,
context: context,
builder: (context) => PostAction(item: item),
).then((value) {
if (value != null) controller.refresh();
});
},
child: CenteredContainer(
child: GestureDetector(
child: PostItem(
key: Key('p${item.alias}'),
item: item,
isShowEmbed: isShowEmbed,
isClickable: isNestedClickable,
).paddingSymmetric(vertical: 8),
onTap: () {
if (!isClickable) return;
AppRouter.instance.pushNamed(
'postDetail',
pathParameters: {'alias': item.alias},
);
},
onLongPress: () {
showModalBottomSheet(
useRootNavigator: true,
context: context,
builder: (context) => PostAction(item: item),
).then((value) {
if (value != null) controller.refresh();
});
},
),
),
);
},