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')], supportedLocales: [Locale('en', 'US'), Locale('zh', 'CN')],
fallbackLocale: Locale('en', 'US'), fallbackLocale: Locale('en', 'US'),
useFallbackTranslations: true, useFallbackTranslations: true,
useOnlyLangCode: true,
assetLoader: JsonAssetLoader(), assetLoader: JsonAssetLoader(),
child: MultiProvider( child: MultiProvider(
providers: [ providers: [

View File

@@ -16,13 +16,12 @@ import 'package:surface/screens/settings.dart';
import 'package:surface/types/post.dart'; import 'package:surface/types/post.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart'; import 'package:surface/widgets/navigation/app_scaffold.dart';
final appRouter = GoRouter( final _appRoutes = [
routes: [
ShellRoute( ShellRoute(
builder: (context, state, child) => AppScaffold( builder: (context, state, child) => AppScaffold(
body: child, body: child,
showBottomNavigation: true, showBottomNavigation: true,
showDrawer: true, showAppBar: false,
), ),
routes: [ routes: [
GoRoute( GoRoute(
@@ -53,9 +52,7 @@ final appRouter = GoRouter(
], ],
), ),
ShellRoute( ShellRoute(
builder: (context, state, child) => AppScaffold( builder: (context, state, child) => child,
body: child,
),
routes: [ routes: [
GoRoute( GoRoute(
path: '/post/write/:mode', path: '/post/write/:mode',
@@ -84,11 +81,7 @@ final appRouter = GoRouter(
], ],
), ),
ShellRoute( ShellRoute(
builder: (context, state, child) => AppScaffold( builder: (context, state, child) => AppScaffold(body: child),
body: child,
autoImplyAppBar: true,
showDrawer: true,
),
routes: [ routes: [
GoRoute( GoRoute(
path: '/auth/login', path: '/auth/login',
@@ -125,10 +118,7 @@ final appRouter = GoRouter(
], ],
), ),
ShellRoute( ShellRoute(
builder: (context, state, child) => AppScaffold( builder: (context, state, child) => AppScaffold(body: child),
body: child,
autoImplyAppBar: true,
),
routes: [ routes: [
GoRoute( GoRoute(
path: '/settings', path: '/settings',
@@ -137,5 +127,13 @@ final appRouter = GoRouter(
), ),
], ],
), ),
];
final appRouter = GoRouter(
routes: [
ShellRoute(
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/providers/userinfo.dart';
import 'package:surface/widgets/account/account_image.dart'; import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
class AccountScreen extends StatelessWidget { class AccountScreen extends StatelessWidget {
const AccountScreen({super.key}); const AccountScreen({super.key});
@@ -17,7 +16,7 @@ class AccountScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ua = context.watch<UserProvider>(); final ua = context.watch<UserProvider>();
return AppScaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text("screenAccount").tr(), title: Text("screenAccount").tr(),
actions: [ 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/account/account_image.dart';
import 'package:surface/widgets/dialog.dart'; import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/loading_indicator.dart'; import 'package:surface/widgets/loading_indicator.dart';
import 'package:surface/widgets/navigation/app_scaffold.dart';
import 'package:surface/widgets/universal_image.dart'; import 'package:surface/widgets/universal_image.dart';
class AccountPublisherEditScreen extends StatefulWidget { class AccountPublisherEditScreen extends StatefulWidget {
@@ -189,7 +188,7 @@ class _AccountPublisherEditScreenState
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>(); final sn = context.read<SnNetworkProvider>();
return AppScaffold( return Scaffold(
body: SingleChildScrollView( body: SingleChildScrollView(
child: Column( child: Column(
children: [ children: [

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,3 @@
import 'dart:math' as math;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:go_router/go_router.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'; import 'package:surface/providers/navigation.dart';
class AppNavigationDrawer extends StatefulWidget { class AppNavigationDrawer extends StatefulWidget {
const AppNavigationDrawer({super.key}); final double? elevation;
const AppNavigationDrawer({super.key, this.elevation});
@override @override
State<AppNavigationDrawer> createState() => _AppNavigationDrawerState(); State<AppNavigationDrawer> createState() => _AppNavigationDrawerState();
@@ -43,6 +42,7 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
]; ];
return NavigationDrawer( return NavigationDrawer(
elevation: widget.elevation,
backgroundColor: backgroundColor, backgroundColor: backgroundColor,
selectedIndex: nav.currentIndex, selectedIndex: nav.currentIndex,
children: [ children: [
@@ -51,12 +51,12 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text('Solar Network').bold(), 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)), Theme.of(context).colorScheme.onSurface.withOpacity(0.5)),
], ],
).padding( ).padding(
horizontal: 32, horizontal: 32,
top: math.max(MediaQuery.of(context).padding.top, 16), top: MediaQuery.of(context).padding.top > 16 ? 8 : 16,
bottom: 16, bottom: 16,
), ),
...destinations.where((ele) => ele.isPinned).map((ele) { ...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_background.dart';
import 'package:surface/widgets/navigation/app_bottom_navigation.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_drawer_navigation.dart';
import 'package:surface/widgets/navigation/app_rail_navigation.dart';
class AppScaffold extends StatelessWidget { class AppScaffold extends StatelessWidget {
final PreferredSizeWidget? appBar;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final Widget? floatingActionButton;
final String? title; final String? title;
final Widget? body; final Widget? body;
final bool autoImplyAppBar; final bool showAppBar;
final bool showBottomNavigation; final bool showBottomNavigation;
final bool showDrawer;
const AppScaffold({ const AppScaffold({
super.key, super.key,
this.appBar,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.title, this.title,
this.body, this.body,
this.autoImplyAppBar = false, this.showAppBar = true,
this.showBottomNavigation = false, this.showBottomNavigation = false,
this.showDrawer = false,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isShowDrawer = showDrawer
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
: false;
final isShowBottomNavigation = (showBottomNavigation) final isShowBottomNavigation = (showBottomNavigation)
? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE) ? ResponsiveBreakpoints.of(context).smallerOrEqualTo(MOBILE)
: false; : false;
final state = GoRouter.maybeOf(context); final state = GoRouter.maybeOf(context);
final autoTitle = state != null
? 'screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}'
: 'screen';
final innerWidget = AppBackground( return Scaffold(
child: Scaffold( appBar: showAppBar
appBar: appBar ??
(autoImplyAppBar
? AppBar( ? AppBar(
title: title != null title: Text(title ?? autoTitle.tr()),
? Text(title!)
: state != null
? Text(
('screen${state.routerDelegate.currentConfiguration.last.route.name?.capitalize()}')
.tr(),
) )
: null) : null,
: null),
body: body, body: body,
floatingActionButtonLocation: floatingActionButtonLocation,
floatingActionButton: floatingActionButton,
drawer: isShowDrawer ? AppNavigationDrawer() : null,
bottomNavigationBar: bottomNavigationBar:
isShowBottomNavigation ? AppBottomNavigationBar() : null, isShowBottomNavigation ? AppBottomNavigationBar() : null,
),
); );
}
if (showDrawer) { }
return Row(
children: [ class AppRootScaffold extends StatelessWidget {
AppNavigationDrawer(), final Widget body;
VerticalDivider(width: 1, color: Theme.of(context).dividerColor), const AppRootScaffold({super.key, required this.body});
Expanded(child: innerWidget),
], @override
); Widget build(BuildContext context) {
} final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
return innerWidget; 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,
),
);
} }
} }

View File

@@ -7,6 +7,7 @@ import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/sn_attachment.dart'; import 'package:surface/providers/sn_attachment.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/userinfo.dart';
import 'package:surface/types/post.dart'; import 'package:surface/types/post.dart';
import 'package:surface/widgets/post/post_item.dart'; import 'package:surface/widgets/post/post_item.dart';
import 'package:surface/widgets/post/post_mini_editor.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 { class PostCommentSliverList extends StatefulWidget {
final int parentPostId; final int parentPostId;
const PostCommentSliverList({super.key, required this.parentPostId}); final double? maxWidth;
const PostCommentSliverList({
super.key,
required this.parentPostId,
this.maxWidth,
});
@override @override
State<PostCommentSliverList> createState() => PostCommentSliverListState(); State<PostCommentSliverList> createState() => PostCommentSliverListState();
@@ -88,7 +94,12 @@ class PostCommentSliverListState extends State<PostCommentSliverList> {
onFetchData: _fetchPosts, onFetchData: _fetchPosts,
itemBuilder: (context, idx) { itemBuilder: (context, idx) {
return GestureDetector( return GestureDetector(
child: Container(
constraints: BoxConstraints(
maxWidth: widget.maxWidth ?? double.infinity,
),
child: PostItem(data: _posts[idx]), child: PostItem(data: _posts[idx]),
).center(),
onTap: () { onTap: () {
GoRouter.of(context).pushNamed( GoRouter.of(context).pushNamed(
'postDetail', 'postDetail',
@@ -121,6 +132,7 @@ class _PostCommentListPopupState extends State<PostCommentListPopup> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final ua = context.watch<UserProvider>();
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
return Column( return Column(
@@ -139,6 +151,7 @@ class _PostCommentListPopupState extends State<PostCommentListPopup> {
Expanded( Expanded(
child: CustomScrollView( child: CustomScrollView(
slivers: [ slivers: [
if (ua.isAuthorized)
SliverToBoxAdapter( SliverToBoxAdapter(
child: Container( child: Container(
height: 240, height: 240,

View File

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

View File

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

View File

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

View File

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

View File

@@ -418,10 +418,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: file_selector_linux name: file_selector_linux
sha256: "712ce7fab537ba532c8febdb1a8f167b32441e74acd68c3ccb2e36dcb52c4ab2" sha256: b2b91daf8a68ecfa4a01b778a6f52edef9b14ecd506e771488ea0f2e0784198b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.3" version: "0.9.3+1"
file_selector_macos: file_selector_macos:
dependency: transitive dependency: transitive
description: description:
@@ -532,10 +532,50 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: flutter_secure_storage name: flutter_secure_storage
sha256: "9f3dd2ac3b6875b0fde5b04734789c3ef35ba3965c18e99dd564a7a2f8056df6" sha256: "165164745e6afb5c0e3e3fcc72a012fb9e58496fb26ffb92cf22e16a821e85d0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted 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: flutter_shaders:
dependency: transitive dependency: transitive
description: description:
@@ -598,10 +638,10 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
name: go_router name: go_router
sha256: ce89c5a993ca5eea74535f798478502c30a625ecb10a1de4d7fef5cd1bcac2a4 sha256: "8ae664a70174163b9f65ea68dd8673e29db8f9095de7b5cd00e167c621f4fef5"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.4.1" version: "14.6.0"
google_fonts: google_fonts:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -766,10 +806,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: js name: js
sha256: c1b2e9b5ea78c45e1a0788d29606ba27dc5f71f019f32ca5140f61ef071838cf sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.1" version: "0.6.7"
json_annotation: json_annotation:
dependency: "direct main" dependency: "direct main"
description: description:
@@ -1347,10 +1387,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: url_launcher_linux name: url_launcher_linux
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.2.0" version: "3.2.1"
url_launcher_macos: url_launcher_macos:
dependency: transitive dependency: transitive
description: 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 # 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 # 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. # 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: environment:
sdk: ^3.5.4 sdk: ^3.5.4
@@ -58,7 +58,7 @@ dependencies:
google_fonts: ^6.2.1 google_fonts: ^6.2.1
path: ^1.9.0 path: ^1.9.0
relative_time: ^5.0.0 relative_time: ^5.0.0
flutter_secure_storage: ^4.2.1 flutter_secure_storage: ^9.2.2
image_picker: ^1.1.2 image_picker: ^1.1.2
cross_file: ^0.3.4+2 cross_file: ^0.3.4+2
file_picker: ^8.1.3 file_picker: ^8.1.3

View File

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

View File

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