Compare commits

...

6 Commits

Author SHA1 Message Date
2e68d227a0 ⬆️ Upgrade deps 2024-11-14 23:25:02 +08:00
b8245b00b6 💄 Post item maxWidth 2024-11-14 22:49:17 +08:00
462e818078 💄 Optimize attachment list 2024-11-14 22:42:06 +08:00
e4582b7d25 ♻️ Optimized responsive navigation 2024-11-14 22:21:13 +08:00
00eef6e45a 🐛 Fix app drawer show on mobile 2024-11-14 13:02:42 +08:00
9498d428cd 🐛 Use only lang code on localization to fix not found bug 2024-11-14 00:40:58 +08:00
26 changed files with 414 additions and 270 deletions

View File

@@ -35,6 +35,7 @@ class SolianApp extends StatelessWidget {
supportedLocales: [Locale('en', 'US'), Locale('zh', 'CN')],
fallbackLocale: Locale('en', 'US'),
useFallbackTranslations: true,
useOnlyLangCode: true,
assetLoader: JsonAssetLoader(),
child: MultiProvider(
providers: [

View File

@@ -16,126 +16,124 @@ import 'package:surface/screens/settings.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
final _appRoutes = [
ShellRoute(
builder: (context, state, child) => AppScaffold(
body: child,
showBottomNavigation: true,
showAppBar: false,
),
routes: [
GoRoute(
path: '/',
name: 'home',
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: '/posts',
name: 'explore',
builder: (context, state) => const ExploreScreen(),
),
GoRoute(
path: '/account',
name: 'account',
builder: (context, state) => const AccountScreen(),
),
GoRoute(
path: '/chat',
name: 'chat',
builder: (context, state) => const ChatScreen(),
),
GoRoute(
path: '/album',
name: 'album',
builder: (context, state) => const AlbumScreen(),
),
],
),
ShellRoute(
builder: (context, state, child) => child,
routes: [
GoRoute(
path: '/post/write/:mode',
name: 'postEditor',
builder: (context, state) => PostEditorScreen(
mode: state.pathParameters['mode']!,
postEditId: int.tryParse(
state.uri.queryParameters['editing'] ?? '',
),
postReplyId: int.tryParse(
state.uri.queryParameters['replying'] ?? '',
),
postRepostId: int.tryParse(
state.uri.queryParameters['reposting'] ?? '',
),
),
),
GoRoute(
path: '/post/:slug',
name: 'postDetail',
builder: (context, state) => PostDetailScreen(
slug: state.pathParameters['slug']!,
preload: state.extra as SnPost?,
),
)
],
),
ShellRoute(
builder: (context, state, child) => AppScaffold(body: child),
routes: [
GoRoute(
path: '/auth/login',
name: 'authLogin',
builder: (context, state) => const LoginScreen(),
),
GoRoute(
path: '/auth/register',
name: 'authRegister',
builder: (context, state) => const RegisterScreen(),
),
GoRoute(
path: '/account/profile/edit',
name: 'accountProfileEdit',
builder: (context, state) => const ProfileEditScreen(),
),
GoRoute(
path: '/account/publishers',
name: 'accountPublishers',
builder: (context, state) => const PublisherScreen(),
),
GoRoute(
path: '/account/publishers/new',
name: 'accountPublisherNew',
builder: (context, state) => const AccountPublisherNewScreen(),
),
GoRoute(
path: '/account/publishers/edit/:name',
name: 'accountPublisherEdit',
builder: (context, state) => AccountPublisherEditScreen(
name: state.pathParameters['name']!,
),
),
],
),
ShellRoute(
builder: (context, state, child) => AppScaffold(body: child),
routes: [
GoRoute(
path: '/settings',
name: 'settings',
builder: (context, state) => const SettingsScreen(),
),
],
),
];
final appRouter = GoRouter(
routes: [
ShellRoute(
builder: (context, state, child) => AppScaffold(
body: child,
showBottomNavigation: true,
showDrawer: true,
),
routes: [
GoRoute(
path: '/',
name: 'home',
builder: (context, state) => const HomeScreen(),
),
GoRoute(
path: '/posts',
name: 'explore',
builder: (context, state) => const ExploreScreen(),
),
GoRoute(
path: '/account',
name: 'account',
builder: (context, state) => const AccountScreen(),
),
GoRoute(
path: '/chat',
name: 'chat',
builder: (context, state) => const ChatScreen(),
),
GoRoute(
path: '/album',
name: 'album',
builder: (context, state) => const AlbumScreen(),
),
],
),
ShellRoute(
builder: (context, state, child) => AppScaffold(
body: child,
),
routes: [
GoRoute(
path: '/post/write/:mode',
name: 'postEditor',
builder: (context, state) => PostEditorScreen(
mode: state.pathParameters['mode']!,
postEditId: int.tryParse(
state.uri.queryParameters['editing'] ?? '',
),
postReplyId: int.tryParse(
state.uri.queryParameters['replying'] ?? '',
),
postRepostId: int.tryParse(
state.uri.queryParameters['reposting'] ?? '',
),
),
),
GoRoute(
path: '/post/:slug',
name: 'postDetail',
builder: (context, state) => PostDetailScreen(
slug: state.pathParameters['slug']!,
preload: state.extra as SnPost?,
),
)
],
),
ShellRoute(
builder: (context, state, child) => AppScaffold(
body: child,
autoImplyAppBar: true,
showDrawer: true,
),
routes: [
GoRoute(
path: '/auth/login',
name: 'authLogin',
builder: (context, state) => const LoginScreen(),
),
GoRoute(
path: '/auth/register',
name: 'authRegister',
builder: (context, state) => const RegisterScreen(),
),
GoRoute(
path: '/account/profile/edit',
name: 'accountProfileEdit',
builder: (context, state) => const ProfileEditScreen(),
),
GoRoute(
path: '/account/publishers',
name: 'accountPublishers',
builder: (context, state) => const PublisherScreen(),
),
GoRoute(
path: '/account/publishers/new',
name: 'accountPublisherNew',
builder: (context, state) => const AccountPublisherNewScreen(),
),
GoRoute(
path: '/account/publishers/edit/:name',
name: 'accountPublisherEdit',
builder: (context, state) => AccountPublisherEditScreen(
name: state.pathParameters['name']!,
),
),
],
),
ShellRoute(
builder: (context, state, child) => AppScaffold(
body: child,
autoImplyAppBar: true,
),
routes: [
GoRoute(
path: '/settings',
name: 'settings',
builder: (context, state) => const SettingsScreen(),
),
],
builder: (context, state, child) => AppRootScaffold(body: child),
routes: _appRoutes,
),
],
);

View File

@@ -8,7 +8,6 @@ import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
class AccountScreen extends StatelessWidget {
const AccountScreen({super.key});
@@ -17,7 +16,7 @@ class AccountScreen extends StatelessWidget {
Widget build(BuildContext context) {
final ua = context.watch<UserProvider>();
return AppScaffold(
return Scaffold(
appBar: AppBar(
title: Text("screenAccount").tr(),
actions: [

View File

@@ -18,7 +18,6 @@ import 'package:surface/types/post.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/loading_indicator.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:surface/widgets/universal_image.dart';
class AccountPublisherEditScreen extends StatefulWidget {
@@ -189,7 +188,7 @@ class _AccountPublisherEditScreenState
Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>();
return AppScaffold(
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [

View File

@@ -8,7 +8,6 @@ import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
class AccountPublisherNewScreen extends StatefulWidget {
const AccountPublisherNewScreen({super.key});
@@ -23,7 +22,7 @@ class _AccountPublisherNewScreenState extends State<AccountPublisherNewScreen> {
@override
Widget build(BuildContext context) {
return AppScaffold(
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [

View File

@@ -1,5 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
@@ -11,7 +10,6 @@ import 'package:surface/types/post.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/loading_indicator.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
class PublisherScreen extends StatefulWidget {
const PublisherScreen({super.key});
@@ -55,7 +53,7 @@ class _PublisherScreenState extends State<PublisherScreen> {
@override
Widget build(BuildContext context) {
return AppScaffold(
return Scaffold(
body: Column(
children: [
ListTile(

View File

@@ -5,10 +5,10 @@ import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/sn_attachment.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:surface/widgets/post/post_item.dart';
import 'package:very_good_infinite_list/very_good_infinite_list.dart';
@@ -74,7 +74,7 @@ class _ExploreScreenState extends State<ExploreScreen> {
@override
Widget build(BuildContext context) {
return AppScaffold(
return Scaffold(
floatingActionButtonLocation: ExpandableFab.location,
floatingActionButton: ExpandableFab(
key: _fabKey,
@@ -173,7 +173,10 @@ class _ExploreScreenState extends State<ExploreScreen> {
onFetchData: _fetchPosts,
itemBuilder: (context, idx) {
return GestureDetector(
child: PostItem(data: _posts[idx]),
child: Container(
constraints: const BoxConstraints(maxWidth: 640),
child: PostItem(data: _posts[idx]),
).center(),
onTap: () {
GoRouter.of(context).pushNamed(
'postDetail',

View File

@@ -1,7 +1,6 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
@@ -14,7 +13,7 @@ class HomeScreen extends StatefulWidget {
class _HomeScreenState extends State<HomeScreen> {
@override
Widget build(BuildContext context) {
return AppScaffold(
return Scaffold(
appBar: AppBar(
title: Text("screenHome").tr(),
),

View File

@@ -9,10 +9,10 @@ import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/sn_attachment.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/loading_indicator.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:surface/widgets/post/post_comment_list.dart';
import 'package:surface/widgets/post/post_item.dart';
import 'package:surface/widgets/post/post_mini_editor.dart';
@@ -72,9 +72,10 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
@override
Widget build(BuildContext context) {
final ua = context.watch<UserProvider>();
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
return AppScaffold(
return Scaffold(
appBar: AppBar(
leading: BackButton(
onPressed: () {
@@ -108,10 +109,13 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
),
if (_data != null)
SliverToBoxAdapter(
child: PostItem(
data: _data!,
showComments: false,
),
child: Container(
constraints: const BoxConstraints(maxWidth: 640),
child: PostItem(
data: _data!,
showComments: false,
),
).center(),
),
const SliverToBoxAdapter(child: Divider(height: 1)),
if (_data != null)
@@ -127,7 +131,7 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
],
).padding(horizontal: 20, vertical: 12),
),
if (_data != null)
if (_data != null && ua.isAuthorized)
SliverToBoxAdapter(
child: Container(
height: 240,
@@ -158,6 +162,7 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
PostCommentSliverList(
key: _childListKey,
parentPostId: _data!.id,
maxWidth: 640,
),
SliverGap(math.max(MediaQuery.of(context).padding.bottom, 16)),
],

View File

@@ -15,7 +15,6 @@ import 'package:surface/providers/sn_network.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/loading_indicator.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:surface/widgets/post/post_item.dart';
import 'package:surface/widgets/post/post_media_pending_list.dart';
import 'package:surface/widgets/post/post_meta_editor.dart';
@@ -111,7 +110,7 @@ class _PostEditorScreenState extends State<PostEditorScreen> {
return ListenableBuilder(
listenable: _writeController,
builder: (context, _) {
return AppScaffold(
return Scaffold(
appBar: AppBar(
leading: BackButton(
onPressed: () {

View File

@@ -15,7 +15,6 @@ import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/theme.dart';
import 'package:surface/theme.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
class SettingsScreen extends StatefulWidget {
const SettingsScreen({super.key});
@@ -58,7 +57,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>();
return AppScaffold(
return Scaffold(
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -1,5 +1,3 @@
import 'dart:math' as math;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:gap/gap.dart';
@@ -11,14 +9,15 @@ class AttachmentList extends StatelessWidget {
final List<SnAttachment> data;
final bool? bordered;
final double? maxHeight;
final EdgeInsets? listPadding;
const AttachmentList({
super.key,
required this.data,
this.bordered,
this.maxHeight,
this.listPadding,
});
static const double kMaxItemWidth = 520;
static const BorderRadius kDefaultRadius =
BorderRadius.all(Radius.circular(8));
@@ -27,27 +26,31 @@ class AttachmentList extends StatelessWidget {
final borderSide = (bordered ?? false)
? BorderSide(width: 1, color: Theme.of(context).dividerColor)
: BorderSide.none;
final backgroundColor = Theme.of(context).colorScheme.surfaceContainer;
final constraints = BoxConstraints(
minWidth: 80,
maxHeight: maxHeight ?? double.infinity,
);
if (data.isEmpty) return const SizedBox.shrink();
if (data.length == 1) {
if (ResponsiveBreakpoints.of(context).largerThan(MOBILE)) {
return Container(
constraints: BoxConstraints(
maxHeight: maxHeight ?? double.infinity,
maxWidth: math.min(
MediaQuery.of(context).size.width - 20,
kMaxItemWidth,
),
),
decoration: BoxDecoration(
border: Border(top: borderSide, bottom: borderSide),
borderRadius: kDefaultRadius,
),
child: AspectRatio(
aspectRatio: data[0].metadata['ratio']?.toDouble() ?? 1,
child: ClipRRect(
return Padding(
// Single child list-like displaying
padding: listPadding ?? EdgeInsets.zero,
child: Container(
constraints: constraints,
decoration: BoxDecoration(
color: backgroundColor,
border: Border(top: borderSide, bottom: borderSide),
borderRadius: kDefaultRadius,
child: AttachmentItem(data: data[0], isExpandable: true),
),
child: AspectRatio(
aspectRatio: data[0].metadata['ratio']?.toDouble() ?? 1,
child: ClipRRect(
borderRadius: kDefaultRadius,
child: AttachmentItem(data: data[0], isExpandable: true),
),
),
),
);
@@ -55,6 +58,7 @@ class AttachmentList extends StatelessWidget {
return Container(
decoration: BoxDecoration(
color: backgroundColor,
border: Border(top: borderSide, bottom: borderSide),
),
child: AspectRatio(
@@ -72,29 +76,36 @@ class AttachmentList extends StatelessWidget {
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, idx) {
return Container(
constraints: BoxConstraints(
maxHeight: maxHeight ?? double.infinity,
maxWidth: math.min(
MediaQuery.of(context).size.width - 20,
kMaxItemWidth,
return Stack(
children: [
Container(
constraints: constraints,
decoration: BoxDecoration(
color: backgroundColor,
border: Border(top: borderSide, bottom: borderSide),
borderRadius: kDefaultRadius,
),
child: AspectRatio(
aspectRatio: data[idx].metadata['ratio']?.toDouble() ?? 1,
child: ClipRRect(
borderRadius: kDefaultRadius,
child:
AttachmentItem(data: data[idx], isExpandable: true),
),
),
),
),
decoration: BoxDecoration(
border: Border(top: borderSide, bottom: borderSide),
borderRadius: kDefaultRadius,
),
child: AspectRatio(
aspectRatio: data[idx].metadata['ratio']?.toDouble() ?? 1,
child: ClipRRect(
borderRadius: kDefaultRadius,
child: AttachmentItem(data: data[idx], isExpandable: true),
Positioned(
right: 12,
bottom: 12,
child: Chip(
label: Text('${idx + 1}/${data.length}'),
),
),
),
],
);
},
separatorBuilder: (context, index) => const Gap(8),
padding: const EdgeInsets.symmetric(horizontal: 12),
padding: listPadding,
physics: const BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
),

View File

@@ -1,5 +1,3 @@
import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
@@ -9,7 +7,8 @@ import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/navigation.dart';
class AppNavigationDrawer extends StatefulWidget {
const AppNavigationDrawer({super.key});
final double? elevation;
const AppNavigationDrawer({super.key, this.elevation});
@override
State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
@@ -43,6 +42,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
];
return NavigationDrawer(
elevation: widget.elevation,
backgroundColor: backgroundColor,
selectedIndex: nav.currentIndex,
children: [
@@ -51,12 +51,12 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Solar Network').bold(),
Text('Solar Network 2.0α').fontSize(12).textColor(
Text('Canary Preview 2.0α').fontSize(12).textColor(
Theme.of(context).colorScheme.onSurface.withOpacity(0.5)),
],
).padding(
horizontal: 32,
top: math.max(MediaQuery.of(context).padding.top, 16),
top: MediaQuery.of(context).padding.top > 16 ? 8 : 16,
bottom: 16,
),
...destinations.where((ele) => ele.isPinned).map((ele) {

View File

@@ -0,0 +1,68 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/navigation.dart';
class AppRailNavigation extends StatefulWidget {
const AppRailNavigation({super.key});
@override
State<AppRailNavigation> createState() => _AppRailNavigationState();
}
class _AppRailNavigationState extends State<AppRailNavigation> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
context
.read<NavigationProvider>()
.autoDetectIndex(GoRouter.maybeOf(context));
});
}
@override
Widget build(BuildContext context) {
final nav = context.watch<NavigationProvider>();
return ListenableBuilder(
listenable: nav,
builder: (context, _) {
final destinations =
nav.destinations.where((ele) => ele.isPinned).toList();
return NavigationRail(
selectedIndex: nav.currentIndex,
destinations: [
...destinations.where((ele) => ele.isPinned).map((ele) {
return NavigationRailDestination(
icon: ele.icon,
label: Text(ele.label).tr(),
);
}),
],
trailing: Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: StyledWidget(
IconButton(
icon: const Icon(Symbols.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
},
),
).padding(bottom: 16),
),
),
onDestinationSelected: (idx) {
nav.setIndex(idx);
GoRouter.of(context).goNamed(destinations[idx].screen);
},
);
},
);
}
}

View File

@@ -6,72 +6,83 @@ import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_background.dart';
import 'package:surface/widgets/navigation/app_bottom_navigation.dart';
import 'package:surface/widgets/navigation/app_drawer_navigation.dart';
import 'package:surface/widgets/navigation/app_rail_navigation.dart';
class AppScaffold extends StatelessWidget {
final PreferredSizeWidget? appBar;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final Widget? floatingActionButton;
final String? title;
final Widget? body;
final bool autoImplyAppBar;
final bool showAppBar;
final bool showBottomNavigation;
final bool showDrawer;
const AppScaffold({
super.key,
this.appBar,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.title,
this.body,
this.autoImplyAppBar = false,
this.showAppBar = true,
this.showBottomNavigation = false,
this.showDrawer = false,
});
@override
Widget build(BuildContext context) {
final isShowDrawer = showDrawer
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
: false;
final isShowBottomNavigation = (showBottomNavigation)
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
: false;
final state = GoRouter.maybeOf(context);
final autoTitle = state != null
? 'screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}'
: 'screen';
final innerWidget = AppBackground(
child: Scaffold(
appBar: appBar ??
(autoImplyAppBar
? AppBar(
title: title != null
? Text(title!)
: state != null
? Text(
('screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}')
.tr(),
)
: null)
: null),
body: body,
floatingActionButtonLocation: floatingActionButtonLocation,
floatingActionButton: floatingActionButton,
drawer: isShowDrawer ? AppNavigationDrawer() : null,
bottomNavigationBar:
isShowBottomNavigation ? AppBottomNavigationBar() : null,
),
return Scaffold(
appBar: showAppBar
? AppBar(
title: Text(title ?? autoTitle.tr()),
)
: null,
body: body,
bottomNavigationBar:
isShowBottomNavigation ? AppBottomNavigationBar() : null,
);
}
}
class AppRootScaffold extends StatelessWidget {
final Widget body;
const AppRootScaffold({super.key, required this.body});
@override
Widget build(BuildContext context) {
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
final isCollapseDrawer =
ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE);
final isExpandDrawer = ResponsiveBreakpoints.of(context).largerThan(TABLET);
final innerWidget = isCollapseDrawer
? body
: Row(
children: [
Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / devicePixelRatio,
),
),
),
child: isExpandDrawer
? AppNavigationDrawer(elevation: 0)
: AppRailNavigation(),
),
Expanded(child: body),
],
);
return AppBackground(
child: Scaffold(
body: innerWidget,
drawer: !isExpandDrawer ? AppNavigationDrawer() : null,
),
);
if (showDrawer) {
return Row(
children: [
AppNavigationDrawer(),
VerticalDivider(width: 1, color: Theme.of(context).dividerColor),
Expanded(child: innerWidget),
],
);
}
return innerWidget;
}
}

View File

@@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/sn_attachment.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/types/post.dart';
import 'package:surface/widgets/post/post_item.dart';
import 'package:surface/widgets/post/post_mini_editor.dart';
@@ -14,7 +15,12 @@ import 'package:very_good_infinite_list/very_good_infinite_list.dart';
class PostCommentSliverList extends StatefulWidget {
final int parentPostId;
const PostCommentSliverList({super.key, required this.parentPostId});
final double? maxWidth;
const PostCommentSliverList({
super.key,
required this.parentPostId,
this.maxWidth,
});
@override
State<PostCommentSliverList> createState() => PostCommentSliverListState();
@@ -88,7 +94,12 @@ class PostCommentSliverListState extends State<PostCommentSliverList> {
onFetchData: _fetchPosts,
itemBuilder: (context, idx) {
return GestureDetector(
child: PostItem(data: _posts[idx]),
child: Container(
constraints: BoxConstraints(
maxWidth: widget.maxWidth ?? double.infinity,
),
child: PostItem(data: _posts[idx]),
).center(),
onTap: () {
GoRouter.of(context).pushNamed(
'postDetail',
@@ -121,6 +132,7 @@ class _PostCommentListPopupState extends State<PostCommentListPopup> {
@override
Widget build(BuildContext context) {
final ua = context.watch<UserProvider>();
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
return Column(
@@ -139,25 +151,26 @@ class _PostCommentListPopupState extends State<PostCommentListPopup> {
Expanded(
child: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
height: 240,
decoration: BoxDecoration(
border: Border.symmetric(
horizontal: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / devicePixelRatio,
if (ua.isAuthorized)
SliverToBoxAdapter(
child: Container(
height: 240,
decoration: BoxDecoration(
border: Border.symmetric(
horizontal: BorderSide(
color: Theme.of(context).dividerColor,
width: 1 / devicePixelRatio,
),
),
),
),
child: PostMiniEditor(
postReplyId: widget.postId,
onPost: () {
_childListKey.currentState!.refresh();
},
child: PostMiniEditor(
postReplyId: widget.postId,
onPost: () {
_childListKey.currentState!.refresh();
},
),
),
),
),
PostCommentSliverList(
key: _childListKey,
parentPostId: widget.postId,

View File

@@ -4,7 +4,6 @@ import 'package:go_router/go_router.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:provider/provider.dart';
import 'package:relative_time/relative_time.dart';
import 'package:responsive_framework/responsive_framework.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/types/post.dart';
@@ -34,10 +33,6 @@ class PostItem extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isListAttachments =
ResponsiveBreakpoints.of(context).largerThan(MOBILE) ||
(data.preload?.attachments?.length ?? 0) > 1;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -52,7 +47,8 @@ class PostItem extends StatelessWidget {
data: data.preload!.attachments!,
bordered: true,
maxHeight: 520,
).padding(horizontal: isListAttachments ? 12 : 0),
listPadding: const EdgeInsets.symmetric(horizontal: 12),
),
_PostBottomAction(
data: data,
showComments: showComments,

View File

@@ -7,16 +7,16 @@
#include "generated_plugin_registrant.h"
#include <file_selector_linux/file_selector_plugin.h>
#include <flutter_secure_storage/flutter_secure_storage_plugin.h>
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <url_launcher_linux/url_launcher_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) file_selector_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin");
file_selector_plugin_register_with_registrar(file_selector_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStoragePlugin");
flutter_secure_storage_plugin_register_with_registrar(flutter_secure_storage_registrar);
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);

View File

@@ -4,7 +4,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
file_selector_linux
flutter_secure_storage
flutter_secure_storage_linux
url_launcher_linux
)

View File

@@ -7,6 +7,7 @@ import Foundation
import connectivity_plus
import file_selector_macos
import flutter_secure_storage_macos
import path_provider_foundation
import shared_preferences_foundation
import sqflite_darwin
@@ -15,6 +16,7 @@ import url_launcher_macos
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin"))
FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))

View File

@@ -418,10 +418,10 @@ packages:
dependency: transitive
description:
name: file_selector_linux
sha256: "712ce7fab537ba532c8febdb1a8f167b32441e74acd68c3ccb2e36dcb52c4ab2"
sha256: b2b91daf8a68ecfa4a01b778a6f52edef9b14ecd506e771488ea0f2e0784198b
url: "https://pub.dev"
source: hosted
version: "0.9.3"
version: "0.9.3+1"
file_selector_macos:
dependency: transitive
description:
@@ -532,10 +532,50 @@ packages:
dependency: "direct main"
description:
name: flutter_secure_storage
sha256: "9f3dd2ac3b6875b0fde5b04734789c3ef35ba3965c18e99dd564a7a2f8056df6"
sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
url: "https://pub.dev"
source: hosted
version: "4.2.1"
version: "9.2.2"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: "4d91bfc23047422cbcd73ac684bc169859ee766482517c22172c86596bf1464b"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: "1693ab11121a5f925bbea0be725abfcfbbcf36c1e29e571f84a0c0f436147a81"
url: "https://pub.dev"
source: hosted
version: "3.1.2"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
url: "https://pub.dev"
source: hosted
version: "1.1.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
url: "https://pub.dev"
source: hosted
version: "1.2.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
url: "https://pub.dev"
source: hosted
version: "3.1.2"
flutter_shaders:
dependency: transitive
description:
@@ -598,10 +638,10 @@ packages:
dependency: "direct main"
description:
name: go_router
sha256: ce89c5a993ca5eea74535f798478502c30a625ecb10a1de4d7fef5cd1bcac2a4
sha256: "8ae664a70174163b9f65ea68dd8673e29db8f9095de7b5cd00e167c621f4fef5"
url: "https://pub.dev"
source: hosted
version: "14.4.1"
version: "14.6.0"
google_fonts:
dependency: "direct main"
description:
@@ -766,10 +806,10 @@ packages:
dependency: transitive
description:
name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf
sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev"
source: hosted
version: "0.7.1"
version: "0.6.7"
json_annotation:
dependency: "direct main"
description:
@@ -1347,10 +1387,10 @@ packages:
dependency: transitive
description:
name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "3.2.1"
url_launcher_macos:
dependency: transitive
description:

View File

@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 2.0.0+2
version: 2.0.0+3
environment:
sdk: ^3.5.4
@@ -58,7 +58,7 @@ dependencies:
google_fonts: ^6.2.1
path: ^1.9.0
relative_time: ^5.0.0
flutter_secure_storage: ^4.2.1
flutter_secure_storage: ^9.2.2
image_picker: ^1.1.2
cross_file: ^0.3.4+2
file_picker: ^8.1.3

View File

@@ -8,6 +8,7 @@
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <file_selector_windows/file_selector_windows.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
void RegisterPlugins(flutter::PluginRegistry* registry) {
@@ -15,6 +16,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
FileSelectorWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FileSelectorWindows"));
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
}

View File

@@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
file_selector_windows
flutter_secure_storage_windows
url_launcher_windows
)