opt.: split single list into multiples on desktop (#524)

This commit is contained in:
lollipopkit🏳️‍⚧️
2024-08-11 20:53:25 +08:00
parent 42cc2416a1
commit 568b97606a
12 changed files with 295 additions and 271 deletions

View File

@@ -30,18 +30,22 @@ class BackupPage extends StatelessWidget {
}
Widget _buildBody(BuildContext context) {
return ListView(
padding: const EdgeInsets.all(13),
return MultiList(
widthDivider: 2,
children: [
_buildTip(),
CenterGreyTitle(libL10n.sync),
if (isMacOS || isIOS) _buildIcloud(context),
_buildWebdav(context),
_buildFile(context),
_buildClipboard(context),
CenterGreyTitle(libL10n.import),
_buildBulkImportServers(context),
_buildImportSnippet(context),
[
CenterGreyTitle(libL10n.sync),
_buildTip(),
if (isMacOS || isIOS) _buildIcloud(context),
_buildWebdav(context),
_buildFile(context),
_buildClipboard(context),
],
[
CenterGreyTitle(libL10n.import),
_buildBulkImportServers(context),
_buildImportSnippet(context),
],
],
);
}

View File

@@ -9,7 +9,6 @@ import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/res/rebuild.dart';
import 'package:server_box/data/res/store.dart';
import 'package:server_box/data/res/url.dart';
import 'package:server_box/view/page/setting/platform/platform_pub.dart';
import '../../../core/route.dart';
import '../../../data/model/app/net_view.dart';
@@ -54,27 +53,28 @@ class _SettingPageState extends State<SettingPage> {
),
],
),
body: ListView(
padding: const EdgeInsets.symmetric(horizontal: 17),
body: MultiList(
widthDivider: 2.3,
thumbVisibility: true,
children: [
const CenterGreyTitle('App'),
_buildApp(),
CenterGreyTitle(l10n.server),
_buildServer(),
CenterGreyTitle(l10n.container),
_buildContainer(),
const CenterGreyTitle('SSH'),
_buildSSH(),
const CenterGreyTitle('SFTP'),
_buildSFTP(),
CenterGreyTitle(l10n.editor),
_buildEditor(),
[const CenterGreyTitle('App'), _buildApp()],
[CenterGreyTitle(l10n.server), _buildServer()],
[
const CenterGreyTitle('SSH'),
_buildSSH(),
const CenterGreyTitle('SFTP'),
_buildSFTP()
],
[
CenterGreyTitle(l10n.container),
_buildContainer(),
CenterGreyTitle(l10n.editor),
_buildEditor(),
],
/// Fullscreen Mode is designed for old mobile phone which can be
/// used as a status screen.
if (isMobile) CenterGreyTitle(l10n.fullScreen),
if (isMobile) _buildFullScreen(),
const SizedBox(height: 37),
if (isMobile) [CenterGreyTitle(l10n.fullScreen), _buildFullScreen()],
],
),
);
@@ -948,6 +948,7 @@ class _SettingPageState extends State<SettingPage> {
return ExpandTile(
leading: const Icon(MingCute.more_3_fill),
title: Text(l10n.more),
initiallyExpanded: isDesktop,
children: [
_buildRememberPwdInMem(),
_buildTextScaler(),
@@ -1010,13 +1011,13 @@ class _SettingPageState extends State<SettingPage> {
return ExpandTile(
leading: const Icon(MingCute.more_3_fill),
title: Text(l10n.more),
initiallyExpanded: isDesktop,
children: [
_buildBeta(),
if (isMobile) _buildWakeLock(),
_buildCollapseUI(),
_buildCupertinoRoute(),
if (isDesktop) _buildHideTitleBar(),
if (isDesktop) PlatformPublicSettings.buildSaveWindowSize(),
],
);
}

View File

@@ -1,8 +1,6 @@
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/material.dart';
import 'package:server_box/core/extension/context/locale.dart';
import 'package:server_box/data/res/store.dart';
import 'package:window_manager/window_manager.dart';
abstract final class PlatformPublicSettings {
static Widget buildBioAuth() {
@@ -46,49 +44,4 @@ abstract final class PlatformPublicSettings {
},
);
}
static Widget buildSaveWindowSize() {
final isBusy = false.vn;
// Only show [FadeIn] when previous state is busy.
var lastIsBusy = false;
final prop = Stores.setting.windowSize;
return ListTile(
title: Text(l10n.rememberWindowSize),
/// Copied from `fl_build/view/store_switch`
trailing: ValBuilder(
listenable: isBusy,
builder: (busy) {
return ValBuilder(
listenable: prop.listenable(),
builder: (value) {
if (busy) {
lastIsBusy = true;
return UIs.centerSizedLoadingSmall.paddingOnly(right: 17);
}
final switcher = Switch(
value: value.isNotEmpty,
onChanged: (value) async {
isBusy.value = true;
final size = await windowManager.getSize();
isBusy.value = false;
prop.put(size.toIntStr());
},
);
if (lastIsBusy) {
final ret = FadeIn(child: switcher);
lastIsBusy = false;
return ret;
}
return switcher;
},
);
},
),
);
}
}

View File

@@ -221,7 +221,7 @@ final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 5),
itemCount: names.length,
itemBuilder: (_, idx) => _buillItem(idx),
itemBuilder: (_, idx) => _buildItem(idx),
separatorBuilder: (_, __) => Padding(
padding: const EdgeInsets.symmetric(vertical: 17),
child: Container(
@@ -234,7 +234,10 @@ final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
);
}
Widget _buillItem(int idx) {
static const kWideWidth = 90.0;
static const kNarrowWidth = 60.0;
Widget _buildItem(int idx) {
final name = names[idx];
final selected = idxVN.value == idx;
final color = selected ? null : Colors.grey;
@@ -255,31 +258,28 @@ final class _TabBar extends StatelessWidget implements PreferredSizeWidget {
textAlign: TextAlign.center,
textWidthBasis: TextWidthBasis.parent,
);
final Widget btn;
if (selected) {
btn = Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Btn.icon(
icon: Icon(MingCute.close_circle_fill, color: color, size: 17),
onTap: () => onClose(name),
padding: null,
),
SizedBox(width: kNarrowWidth - 10, child: text),
],
);
} else {
btn = Center(child: text);
}
child = AnimatedContainer(
width: selected ? 90 : 57,
width: selected ? kWideWidth : kNarrowWidth,
duration: Durations.medium3,
padding: selected ? const EdgeInsets.symmetric(horizontal: 7) : null,
curve: Curves.fastEaseInToSlowEaseOut,
child: switch (selected) {
true => Row(
children: [
if (selected)
FadeIn(
child: Btn.icon(
icon: Icon(
MingCute.close_circle_fill,
color: color,
size: 17,
),
onTap: () => onClose(name),
),
),
const Spacer(),
SizedBox(width: 50, child: text),
],
),
false => Center(child: text),
},
child: btn,
);
}