Compare commits

...

8 Commits

Author SHA1 Message Date
068ddcdcdc 💄 Optimized connection indicator 2025-01-20 14:40:26 +08:00
f4e9252ca0 💄 Optimized post list 2025-01-20 14:21:41 +08:00
3b1e918117 🐛 Fix side nav cause render error 2025-01-20 01:43:11 +08:00
ed7981fdaf 🧪 Post max width 2025-01-19 17:20:24 +08:00
9698ca53e4 Swipe up to view attachment details 2025-01-19 11:44:14 +08:00
ddc1dc7daf 💄 Optimize attachment zoom page 2025-01-19 01:00:00 +08:00
1625a957f8 👔 Use material design 3 by default 2025-01-19 00:39:47 +08:00
2dc50d627e 🧱 Fix roadsign config 2025-01-16 21:51:28 +08:00
13 changed files with 559 additions and 394 deletions

View File

@@ -17,6 +17,7 @@
android:label="Solian" android:label="Solian"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:enableOnBackInvokedCallback="true"
android:requestLegacyExternalStorage="true"> android:requestLegacyExternalStorage="true">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"

View File

@@ -215,8 +215,9 @@
"sensitiveContentCollapsed": "Sensitive content has been collapsed.", "sensitiveContentCollapsed": "Sensitive content has been collapsed.",
"sensitiveContentDescription": "This content has been marked as sensitive, and may not be suitable for all viewers.", "sensitiveContentDescription": "This content has been marked as sensitive, and may not be suitable for all viewers.",
"sensitiveContentReveal": "Reveal", "sensitiveContentReveal": "Reveal",
"serverConnecting": "Connecting to server...", "serverConnecting": "Connecting...",
"serverDisconnected": "Lost connection from server", "serverDisconnected": "Connection Lost",
"serverConnected": "Connected",
"fieldChatAlias": "Channel Alias", "fieldChatAlias": "Channel Alias",
"fieldChatAliasHint": "The unique channel alias within the site, used to represent the channel in URL, leave blank to auto generate. Should be URL-Safe.", "fieldChatAliasHint": "The unique channel alias within the site, used to represent the channel in URL, leave blank to auto generate. Should be URL-Safe.",
"fieldChatName": "Name", "fieldChatName": "Name",
@@ -294,6 +295,7 @@
"addAttachmentFromCameraPhoto": "Take photo", "addAttachmentFromCameraPhoto": "Take photo",
"addAttachmentFromCameraVideo": "Take video", "addAttachmentFromCameraVideo": "Take video",
"addAttachmentFromRandomId": "Link via RID", "addAttachmentFromRandomId": "Link via RID",
"attachmentDetailInfo": "Attachment details",
"attachmentPastedImage": "Pasted Image", "attachmentPastedImage": "Pasted Image",
"attachmentInsertLink": "Insert Link", "attachmentInsertLink": "Insert Link",
"attachmentSetAsPostThumbnail": "Set as post thumbnail", "attachmentSetAsPostThumbnail": "Set as post thumbnail",

View File

@@ -213,8 +213,9 @@
"sensitiveContentCollapsed": "敏感内容已折叠。", "sensitiveContentCollapsed": "敏感内容已折叠。",
"sensitiveContentDescription": "此内容已被标记,可能不适合所有人查看。", "sensitiveContentDescription": "此内容已被标记,可能不适合所有人查看。",
"sensitiveContentReveal": "显示内容", "sensitiveContentReveal": "显示内容",
"serverConnecting": "正在连接服务器…", "serverConnecting": "正在连接…",
"serverDisconnected": "已与服务器断开连接", "serverDisconnected": "已断开连接",
"serverConnected": "已连接",
"fieldChatAlias": "频道别名", "fieldChatAlias": "频道别名",
"fieldChatAliasHint": "全站范围内唯一的频道别名,用于在 URL 中表示该频道,留空则自动生成。应遵循 URL-Safe 的原则。", "fieldChatAliasHint": "全站范围内唯一的频道别名,用于在 URL 中表示该频道,留空则自动生成。应遵循 URL-Safe 的原则。",
"fieldChatName": "名称", "fieldChatName": "名称",
@@ -292,6 +293,7 @@
"addAttachmentFromCameraPhoto": "拍摄照片", "addAttachmentFromCameraPhoto": "拍摄照片",
"addAttachmentFromCameraVideo": "拍摄视频", "addAttachmentFromCameraVideo": "拍摄视频",
"addAttachmentFromRandomId": "通过访问 ID 链接", "addAttachmentFromRandomId": "通过访问 ID 链接",
"attachmentDetailInfo": "附件详细信息",
"attachmentPastedImage": "粘贴的图片", "attachmentPastedImage": "粘贴的图片",
"attachmentInsertLink": "插入连接", "attachmentInsertLink": "插入连接",
"attachmentSetAsPostThumbnail": "设置为帖子缩略图", "attachmentSetAsPostThumbnail": "设置为帖子缩略图",

View File

@@ -1,3 +1,4 @@
import 'package:animations/animations.dart';
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:flutter_expandable_fab/flutter_expandable_fab.dart'; import 'package:flutter_expandable_fab/flutter_expandable_fab.dart';
@@ -8,6 +9,7 @@ import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/post.dart'; import 'package:surface/providers/post.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/screens/post/post_detail.dart';
import 'package:surface/types/post.dart'; import 'package:surface/types/post.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';
@@ -210,6 +212,7 @@ class _ExploreScreenState extends State<ExploreScreen> {
), ),
), ),
), ),
const SliverGap(8),
SliverInfiniteList( SliverInfiniteList(
itemCount: _posts.length, itemCount: _posts.length,
isLoading: _isBusy, isLoading: _isBusy,
@@ -217,7 +220,10 @@ class _ExploreScreenState extends State<ExploreScreen> {
hasReachedMax: _postCount != null && _posts.length >= _postCount!, hasReachedMax: _postCount != null && _posts.length >= _postCount!,
onFetchData: _fetchPosts, onFetchData: _fetchPosts,
itemBuilder: (context, idx) { itemBuilder: (context, idx) {
return GestureDetector( return Center(
child: OpenContainer(
closedBuilder: (_, __) => Container(
constraints: const BoxConstraints(maxWidth: 640),
child: PostItem( child: PostItem(
data: _posts[idx], data: _posts[idx],
maxWidth: 640, maxWidth: 640,
@@ -228,16 +234,23 @@ class _ExploreScreenState extends State<ExploreScreen> {
_refreshPosts(); _refreshPosts();
}, },
), ),
onTap: () { ),
GoRouter.of(context).pushNamed( openBuilder: (_, close) => PostDetailScreen(
'postDetail', slug: _posts[idx].id.toString(),
pathParameters: {'slug': _posts[idx].id.toString()}, preload: _posts[idx],
extra: _posts[idx], onBack: close,
),
openColor: Colors.transparent,
openElevation: 0,
closedColor: Theme.of(context).colorScheme.surface,
transitionType: ContainerTransitionType.fade,
closedShape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8)),
),
),
); );
}, },
); separatorBuilder: (_, __) => const Gap(8),
},
separatorBuilder: (context, index) => const Divider(height: 1),
), ),
], ],
), ),

View File

@@ -13,6 +13,7 @@ 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_background.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';
@@ -20,12 +21,9 @@ import 'package:surface/widgets/post/post_mini_editor.dart';
class PostDetailScreen extends StatefulWidget { class PostDetailScreen extends StatefulWidget {
final String slug; final String slug;
final SnPost? preload; final SnPost? preload;
final Function? onBack;
const PostDetailScreen({ const PostDetailScreen({super.key, required this.slug, this.preload, this.onBack});
super.key,
required this.slug,
this.preload,
});
@override @override
State<PostDetailScreen> createState() => _PostDetailScreenState(); State<PostDetailScreen> createState() => _PostDetailScreenState();
@@ -67,10 +65,15 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
final ua = context.watch<UserProvider>(); final ua = context.watch<UserProvider>();
final devicePixelRatio = MediaQuery.of(context).devicePixelRatio; final devicePixelRatio = MediaQuery.of(context).devicePixelRatio;
return Scaffold( return AppBackground(
isRoot: widget.onBack != null,
child: Scaffold(
appBar: AppBar( appBar: AppBar(
leading: BackButton( leading: BackButton(
onPressed: () { onPressed: () {
if (widget.onBack != null) {
widget.onBack!.call();
}
if (GoRouter.of(context).canPop()) { if (GoRouter.of(context).canPop()) {
GoRouter.of(context).pop(context); GoRouter.of(context).pop(context);
return; return;
@@ -185,6 +188,7 @@ class _PostDetailScreenState extends State<PostDetailScreen> {
SliverGap(math.max(MediaQuery.of(context).padding.bottom, 16)), SliverGap(math.max(MediaQuery.of(context).padding.bottom, 16)),
], ],
), ),
),
); );
} }
} }

View File

@@ -120,7 +120,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
subtitle: Text('settingsThemeMaterial3Description').tr(), subtitle: Text('settingsThemeMaterial3Description').tr(),
contentPadding: const EdgeInsets.only(left: 24, right: 17), contentPadding: const EdgeInsets.only(left: 24, right: 17),
secondary: const Icon(Symbols.new_releases), secondary: const Icon(Symbols.new_releases),
value: _prefs.getBool(kMaterialYouToggleStoreKey) ?? false, value: _prefs.getBool(kMaterialYouToggleStoreKey) ?? true,
onChanged: (value) { onChanged: (value) {
setState(() { setState(() {
_prefs.setBool( _prefs.setBool(

View File

@@ -36,7 +36,7 @@ Future<ThemeData> createAppTheme(
final hasAppBarBlurry = prefs.getBool(kAppbarTransparentStoreKey) ?? false; final hasAppBarBlurry = prefs.getBool(kAppbarTransparentStoreKey) ?? false;
return ThemeData( return ThemeData(
useMaterial3: useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? false), useMaterial3: useMaterial3 ?? (prefs.getBool(kMaterialYouToggleStoreKey) ?? true),
colorScheme: colorScheme, colorScheme: colorScheme,
brightness: brightness, brightness: brightness,
iconTheme: IconThemeData( iconTheme: IconThemeData(
@@ -52,5 +52,15 @@ Future<ThemeData> createAppTheme(
foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary, foregroundColor: hasAppBarBlurry ? colorScheme.onSurface : colorScheme.onPrimary,
), ),
scaffoldBackgroundColor: Colors.transparent, scaffoldBackgroundColor: Colors.transparent,
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.android: PredictiveBackPageTransitionsBuilder(),
TargetPlatform.iOS: ZoomPageTransitionsBuilder(),
TargetPlatform.macOS: ZoomPageTransitionsBuilder(),
TargetPlatform.fuchsia: ZoomPageTransitionsBuilder(),
TargetPlatform.linux: ZoomPageTransitionsBuilder(),
TargetPlatform.windows: ZoomPageTransitionsBuilder(),
},
),
); );
} }

View File

@@ -10,7 +10,6 @@ import 'package:surface/providers/experience.dart';
import 'package:surface/providers/sn_network.dart'; import 'package:surface/providers/sn_network.dart';
import 'package:surface/screens/account/profile_page.dart'; import 'package:surface/screens/account/profile_page.dart';
import 'package:surface/types/account.dart'; import 'package:surface/types/account.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/universal_image.dart'; import 'package:surface/widgets/universal_image.dart';

View File

@@ -129,6 +129,8 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
Color get _unFocusColor => Theme.of(context).colorScheme.onSurface.withOpacity(0.75); Color get _unFocusColor => Theme.of(context).colorScheme.onSurface.withOpacity(0.75);
bool _showDetail = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final sn = context.read<SnNetworkProvider>(); final sn = context.read<SnNetworkProvider>();
@@ -144,9 +146,11 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
onDismissed: () { onDismissed: () {
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
direction: DismissiblePageDismissDirection.down, direction: DismissiblePageDismissDirection.none,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
isFullScreen: true, isFullScreen: true,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Scaffold( child: Scaffold(
body: Stack( body: Stack(
children: [ children: [
@@ -264,7 +268,8 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
borderRadius: const BorderRadius.all(Radius.circular(16)), borderRadius: const BorderRadius.all(Radius.circular(16)),
onTap: _isDownloading onTap: _isDownloading
? null ? null
: () => _saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0), : () =>
_saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
child: Container( child: Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(6),
child: !_isDownloading child: !_isDownloading
@@ -322,7 +327,8 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
'f/${item.metadata['exif']?['Aperture']}', 'f/${item.metadata['exif']?['Aperture']}',
style: metaTextStyle, style: metaTextStyle,
).padding(right: 2), ).padding(right: 2),
if (item.metadata['exif']?['Megapixels'] != null && item.metadata['exif']?['Model'] != null) if (item.metadata['exif']?['Megapixels'] != null &&
item.metadata['exif']?['Model'] != null)
Text( Text(
'${item.metadata['exif']?['Megapixels']}MP', '${item.metadata['exif']?['Megapixels']}MP',
style: metaTextStyle, style: metaTextStyle,
@@ -357,6 +363,132 @@ class _AttachmentZoomViewState extends State<AttachmentZoomView> {
], ],
), ),
), ),
onVerticalDragUpdate: (details) {
if (_showDetail) return;
if (details.delta.dy < 0) {
_showDetail = true;
showModalBottomSheet(
context: context,
builder: (context) => _AttachmentZoomDetailPopup(
data: widget.data.elementAt(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
),
).then((_) {
_showDetail = false;
});
}
},
onTap: () {
Navigator.of(context).pop();
},
),
);
}
}
class _AttachmentZoomDetailPopup extends StatelessWidget {
final SnAttachment data;
const _AttachmentZoomDetailPopup({required this.data});
@override
Widget build(BuildContext context) {
final ud = context.read<UserDirectoryProvider>();
final account = ud.getAccountFromCache(data.accountId);
const tableGap = TableRow(
children: [
TableCell(child: SizedBox(height: 16)),
TableCell(child: SizedBox(height: 16)),
],
);
return SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Icon(Symbols.info, size: 24),
const Gap(16),
Text('attachmentDetailInfo').tr().textStyle(Theme.of(context).textTheme.titleLarge!),
],
).padding(horizontal: 20, top: 16, bottom: 12),
Expanded(
child: Table(
columnWidths: {
0: IntrinsicColumnWidth(),
1: FlexColumnWidth(),
},
children: [
TableRow(
children: [
TableCell(
child: Text('attachmentUploadBy').tr().padding(right: 16),
),
TableCell(
child: Row(
children: [
if (data.accountId > 0)
AccountImage(
content: account?.avatar,
radius: 8,
),
const Gap(8),
Text(data.accountId > 0 ? account?.nick ?? 'unknown'.tr() : 'unknown'.tr()),
const Gap(8),
Text('#${data.accountId}', style: GoogleFonts.robotoMono()).opacity(0.75),
],
),
),
],
),
tableGap,
TableRow(
children: [
TableCell(child: Text('Mimetype').padding(right: 16)),
TableCell(child: Text(data.mimetype)),
],
),
TableRow(
children: [
TableCell(child: Text('Size').padding(right: 16)),
TableCell(
child: Row(
children: [
Text(data.size.formatBytes()),
const Gap(12),
Text('${data.size} Bytes', style: GoogleFonts.robotoMono()).opacity(0.75),
],
)),
],
),
TableRow(
children: [
TableCell(child: Text('Name').padding(right: 16)),
TableCell(child: Text(data.name)),
],
),
if (data.hash.isNotEmpty)
TableRow(
children: [
TableCell(child: Text('Hash').padding(right: 16)),
TableCell(child: Text(data.hash, style: GoogleFonts.robotoMono(fontSize: 11)).opacity(0.9)),
],
),
tableGap,
...(data.metadata['exif']?.keys.map((k) => TableRow(
children: [
TableCell(child: Text(k).padding(right: 16)),
TableCell(child: Text(data.metadata['exif'][k].toString())),
],
)) ??
[]),
],
).padding(horizontal: 20, vertical: 8),
),
],
),
); );
} }
} }

View File

@@ -1,5 +1,7 @@
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:gap/gap.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:styled_widget/styled_widget.dart';
import 'package:surface/providers/userinfo.dart'; import 'package:surface/providers/userinfo.dart';
@@ -18,13 +20,9 @@ class ConnectionIndicator extends StatelessWidget {
final ua = context.read<UserProvider>(); final ua = context.read<UserProvider>();
return GestureDetector( return GestureDetector(
child: Container( child: Material(
padding: EdgeInsets.only( elevation: 2,
bottom: 8, shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
top: MediaQuery.of(context).padding.top + 8,
left: 24,
right: 24,
),
color: Theme.of(context).colorScheme.secondaryContainer, color: Theme.of(context).colorScheme.secondaryContainer,
child: ua.isAuthorized child: ua.isAuthorized
? Row( ? Row(
@@ -32,21 +30,25 @@ class ConnectionIndicator extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
if (ws.isBusy) if (ws.isBusy)
Text('serverConnecting').tr().textColor( Text('serverConnecting').tr().textColor(Theme.of(context).colorScheme.onSecondaryContainer)
Theme.of(context).colorScheme.onSecondaryContainer)
else if (!ws.isConnected) else if (!ws.isConnected)
Text('serverDisconnected').tr().textColor( Text('serverDisconnected').tr().textColor(Theme.of(context).colorScheme.onSecondaryContainer)
Theme.of(context).colorScheme.onSecondaryContainer), else
Text('serverConnected').tr().textColor(Theme.of(context).colorScheme.onSecondaryContainer),
const Gap(8),
if (ws.isBusy)
const CircularProgressIndicator(strokeWidth: 2.5)
.width(12)
.height(12)
.padding(horizontal: 4, right: 4)
else if (!ws.isConnected)
const Icon(Symbols.power_off, size: 18)
else
const Icon(Symbols.power, size: 18),
], ],
) ).padding(horizontal: 8, vertical: 4)
: const SizedBox.shrink(), : const SizedBox.shrink(),
) ).opacity((ws.isBusy || !ws.isConnected) && ua.isAuthorized ? 1 : 0, animate: true).animate(
.height(
(ws.isBusy || !ws.isConnected) && ua.isAuthorized
? MediaQuery.of(context).padding.top + 36
: 0,
animate: true)
.animate(
const Duration(milliseconds: 300), const Duration(milliseconds: 300),
Curves.easeInOut, Curves.easeInOut,
), ),

View File

@@ -18,9 +18,7 @@ class _AppRailNavigationState extends State<AppRailNavigation> {
void initState() { void initState() {
super.initState(); super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
context context.read<NavigationProvider>().autoDetectIndex(GoRouter.maybeOf(context));
.read<NavigationProvider>()
.autoDetectIndex(GoRouter.maybeOf(context));
}); });
} }
@@ -31,11 +29,11 @@ class _AppRailNavigationState extends State<AppRailNavigation> {
return ListenableBuilder( return ListenableBuilder(
listenable: nav, listenable: nav,
builder: (context, _) { builder: (context, _) {
final destinations = final destinations = nav.destinations.where((ele) => ele.isPinned).toList();
nav.destinations.where((ele) => ele.isPinned).toList();
return NavigationRail( return NavigationRail(
selectedIndex: nav.currentIndex, selectedIndex:
nav.currentIndex != null && nav.currentIndex! < nav.pinnedDestinationCount ? nav.currentIndex : null,
destinations: [ destinations: [
...destinations.where((ele) => ele.isPinned).map((ele) { ...destinations.where((ele) => ele.isPinned).map((ele) {
return NavigationRailDestination( return NavigationRailDestination(

View File

@@ -98,11 +98,15 @@ class AppRootScaffold extends StatelessWidget {
iconMouseDown: Theme.of(context).colorScheme.primary, iconMouseDown: Theme.of(context).colorScheme.primary,
); );
final safeTop = MediaQuery.of(context).padding.top;
return AppBackground( return AppBackground(
isRoot: true, isRoot: true,
child: Scaffold( child: Scaffold(
key: globalRootScaffoldKey, key: globalRootScaffoldKey,
body: Column( body: Stack(
children: [
Column(
children: [ children: [
if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS)) if (!kIsWeb && (Platform.isWindows || Platform.isLinux || Platform.isMacOS))
Container( Container(
@@ -127,29 +131,27 @@ class AppRootScaffold extends StatelessWidget {
), ),
), ),
if (!Platform.isMacOS) if (!Platform.isMacOS)
Expanded( MoveWindow(
child: WindowTitleBarBox( child: WindowTitleBarBox(
child: Row( child: Row(
children: [ mainAxisAlignment: MainAxisAlignment.end,
Expanded(child: MoveWindow()),
Row(
children: [ children: [
MinimizeWindowButton(colors: windowButtonColor), MinimizeWindowButton(colors: windowButtonColor),
MaximizeWindowButton(colors: windowButtonColor), MaximizeWindowButton(colors: windowButtonColor),
CloseWindowButton(colors: windowButtonColor), CloseWindowButton(colors: windowButtonColor),
], ],
), ),
],
),
), ),
), ),
], ],
), ),
), ),
ConnectionIndicator(),
Expanded(child: innerWidget), Expanded(child: innerWidget),
], ],
), ),
Positioned(top: safeTop > 0 ? safeTop : 16, right: 8, child: ConnectionIndicator()),
],
),
drawer: !isExpandedDrawer ? AppNavigationDrawer() : null, drawer: !isExpandedDrawer ? AppNavigationDrawer() : null,
drawerEdgeDragWidth: isPopable ? 0 : null, drawerEdgeDragWidth: isPopable ? 0 : null,
bottomNavigationBar: isShowBottomNavigation ? AppBottomNavigationBar() : null, bottomNavigationBar: isShowBottomNavigation ? AppBottomNavigationBar() : null,

View File

@@ -2,8 +2,8 @@ id = "solian"
[[locations]] [[locations]]
id = "solian" id = "solian"
host = ["sn.solsynth.dev"] hosts = ["sn.solsynth.dev"]
path = ["/"] paths = ["/"]
[[locations.destinations]] [[locations.destinations]]
id = "solian-web" id = "solian-web"
uri = "files:///workdir/solian?fallback=index.html&index=index.html" uri = "files:///workdir/solian?fallback=index.html&index=index.html"