From f7761f607f4bc0b9d569e00608cb1690f4741a43 Mon Sep 17 00:00:00 2001 From: Liplum Date: Wed, 27 Mar 2024 15:38:06 +0800 Subject: [PATCH 01/15] [qrcode] refactor --- lib/qrcode/protocol.dart | 88 +--------------------------- lib/settings/page/proxy.dart | 2 +- lib/settings/qrcode/proxy.dart | 59 +++++++++++++++++++ lib/timetable/page/p13n/palette.dart | 2 +- lib/timetable/qrcode/palette.dart | 34 +++++++++++ 5 files changed, 98 insertions(+), 87 deletions(-) create mode 100644 lib/settings/qrcode/proxy.dart create mode 100644 lib/timetable/qrcode/palette.dart diff --git a/lib/qrcode/protocol.dart b/lib/qrcode/protocol.dart index 0abb55759..8b5348b82 100644 --- a/lib/qrcode/protocol.dart +++ b/lib/qrcode/protocol.dart @@ -1,11 +1,10 @@ import 'package:flutter/cupertino.dart'; import 'package:sit/r.dart'; -import 'package:sit/settings/page/proxy.dart'; -import 'package:sit/timetable/entity/platte.dart'; -import 'package:sit/timetable/page/p13n/palette.dart'; +import 'package:sit/settings/qrcode/proxy.dart'; +import 'package:sit/timetable/qrcode/palette.dart'; /// convert any data to a URI with [R.scheme]. -sealed class DeepLinkHandlerProtocol { +abstract class DeepLinkHandlerProtocol { const DeepLinkHandlerProtocol(); bool match(Uri encoded); @@ -20,84 +19,3 @@ sealed class DeepLinkHandlerProtocol { const TimetablePaletteDeepLink(), ]; } - -class ProxyDeepLink extends DeepLinkHandlerProtocol { - static const host = "proxy"; - static const path = "/set"; - - const ProxyDeepLink(); - - Uri encode({ - required String? http, - required String? https, - required String? all, - }) => - Uri(scheme: R.scheme, host: host, path: path, queryParameters: { - if (http != null) "http": http, - // shorthand for https if http proxy is identical to https proxy - if (https != null) "https": http == https ? "@http" : https, - if (all != null) "all": all, - }); - - ({Uri? http, Uri? https, Uri? all}) decode(Uri qrCodeData) { - final param = qrCodeData.queryParameters; - final http = param["http"]; - var https = param["https"]; - final all = param["all"]; - // shorthand for https if http proxy is identical to https proxy - if (https == "@http") { - https = http; - } - return ( - http: http == null ? null : Uri.tryParse(http), - https: https == null ? null : Uri.tryParse(https), - all: all == null ? null : Uri.tryParse(all), - ); - } - - @override - bool match(Uri encoded) { - return encoded.host == host && encoded.path == path; - } - - @override - Future onHandle({ - required BuildContext context, - required Uri qrCodeData, - }) async { - final (:http, :https, :all) = decode(qrCodeData); - await onProxyFromQrCode( - context: context, - http: http, - https: https, - all: all, - ); - } -} - -class TimetablePaletteDeepLink implements DeepLinkHandlerProtocol { - static const path = "timetable-palette"; - - const TimetablePaletteDeepLink(); - - Uri encode(TimetablePalette palette) => Uri(scheme: R.scheme, path: path, query: palette.encodeBase64()); - - TimetablePalette decode(Uri qrCodeData) => TimetablePalette.decodeFromBase64(qrCodeData.query); - - @override - bool match(Uri encoded) { - return encoded.path == path; - } - - @override - Future onHandle({ - required BuildContext context, - required Uri qrCodeData, - }) async { - final palette = decode(qrCodeData); - await onTimetablePaletteFromQrCode( - context: context, - palette: palette, - ); - } -} diff --git a/lib/settings/page/proxy.dart b/lib/settings/page/proxy.dart index cf39df6d9..c5dfa9da3 100644 --- a/lib/settings/page/proxy.dart +++ b/lib/settings/page/proxy.dart @@ -10,11 +10,11 @@ import 'package:sit/design/adaptive/foundation.dart'; import 'package:sit/design/widgets/list_tile.dart'; import 'package:sit/network/checker.dart'; import 'package:sit/qrcode/page/view.dart'; -import 'package:sit/qrcode/protocol.dart'; import 'package:sit/settings/settings.dart'; import 'package:rettulf/rettulf.dart'; import 'package:sit/settings/dev.dart'; import '../i18n.dart'; +import '../qrcode/proxy.dart'; class ProxySettingsPage extends StatefulWidget { const ProxySettingsPage({ diff --git a/lib/settings/qrcode/proxy.dart b/lib/settings/qrcode/proxy.dart new file mode 100644 index 000000000..846cdc533 --- /dev/null +++ b/lib/settings/qrcode/proxy.dart @@ -0,0 +1,59 @@ + +import 'package:flutter/widgets.dart'; +import 'package:sit/qrcode/protocol.dart'; +import 'package:sit/r.dart'; +import 'package:sit/settings/page/proxy.dart'; + +class ProxyDeepLink extends DeepLinkHandlerProtocol { + static const host = "proxy"; + static const path = "/set"; + + const ProxyDeepLink(); + + Uri encode({ + required String? http, + required String? https, + required String? all, + }) => + Uri(scheme: R.scheme, host: host, path: path, queryParameters: { + if (http != null) "http": http, + // shorthand for https if http proxy is identical to https proxy + if (https != null) "https": http == https ? "@http" : https, + if (all != null) "all": all, + }); + + ({Uri? http, Uri? https, Uri? all}) decode(Uri qrCodeData) { + final param = qrCodeData.queryParameters; + final http = param["http"]; + var https = param["https"]; + final all = param["all"]; + // shorthand for https if http proxy is identical to https proxy + if (https == "@http") { + https = http; + } + return ( + http: http == null ? null : Uri.tryParse(http), + https: https == null ? null : Uri.tryParse(https), + all: all == null ? null : Uri.tryParse(all), + ); + } + + @override + bool match(Uri encoded) { + return encoded.host == host && encoded.path == path; + } + + @override + Future onHandle({ + required BuildContext context, + required Uri qrCodeData, + }) async { + final (:http, :https, :all) = decode(qrCodeData); + await onProxyFromQrCode( + context: context, + http: http, + https: https, + all: all, + ); + } +} diff --git a/lib/timetable/page/p13n/palette.dart b/lib/timetable/page/p13n/palette.dart index be9758451..b6c01e9de 100644 --- a/lib/timetable/page/p13n/palette.dart +++ b/lib/timetable/page/p13n/palette.dart @@ -12,7 +12,6 @@ import 'package:sit/design/widgets/card.dart'; import 'package:sit/design/widgets/entry_card.dart'; import 'package:sit/l10n/extension.dart'; import 'package:sit/qrcode/page/view.dart'; -import 'package:sit/qrcode/protocol.dart'; import 'package:sit/timetable/entity/platte.dart'; import 'package:sit/timetable/entity/timetable.dart'; import 'package:sit/timetable/init.dart'; @@ -22,6 +21,7 @@ import 'package:sit/utils/format.dart'; import 'package:text_scroll/text_scroll.dart'; import '../../i18n.dart'; +import '../../qrcode/palette.dart'; import '../../widgets/style.dart'; import '../../widgets/timetable/weekly.dart'; import 'palette_editor.dart'; diff --git a/lib/timetable/qrcode/palette.dart b/lib/timetable/qrcode/palette.dart new file mode 100644 index 000000000..9470ec8a3 --- /dev/null +++ b/lib/timetable/qrcode/palette.dart @@ -0,0 +1,34 @@ + +import 'package:flutter/widgets.dart'; +import 'package:sit/qrcode/protocol.dart'; +import 'package:sit/r.dart'; + +import '../entity/platte.dart'; +import '../page/p13n/palette.dart'; + +class TimetablePaletteDeepLink implements DeepLinkHandlerProtocol { + static const path = "timetable-palette"; + + const TimetablePaletteDeepLink(); + + Uri encode(TimetablePalette palette) => Uri(scheme: R.scheme, path: path, query: palette.encodeBase64()); + + TimetablePalette decode(Uri qrCodeData) => TimetablePalette.decodeFromBase64(qrCodeData.query); + + @override + bool match(Uri encoded) { + return encoded.path == path; + } + + @override + Future onHandle({ + required BuildContext context, + required Uri qrCodeData, + }) async { + final palette = decode(qrCodeData); + await onTimetablePaletteFromQrCode( + context: context, + palette: palette, + ); + } +} From e3c5ef90a900e1d689a771df1d4bbd0473040970 Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 01:36:08 +0800 Subject: [PATCH 02/15] PlatformIcons(context) --- lib/design/adaptive/editor.dart | 5 +++-- lib/design/adaptive/multiplatform.dart | 5 +++++ lib/design/widgets/entry_card.dart | 2 +- lib/design/widgets/expansion_tile.dart | 3 ++- lib/design/widgets/navigation.dart | 3 ++- lib/game/2048/game.dart | 3 ++- lib/game/minesweeper/game.dart | 5 ++--- lib/life/electricity/index.dart | 6 ++---- lib/life/expense_records/page/records.dart | 4 ++-- lib/school/yellow_pages/widgets/search.dart | 3 ++- lib/school/ywb/widgets/application.dart | 5 +++-- lib/timetable/page/p13n/background.dart | 5 +++-- lib/widgets/modal_image_view.dart | 4 ++-- 13 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/design/adaptive/editor.dart b/lib/design/adaptive/editor.dart index 3b4ab6970..8e6f9c826 100644 --- a/lib/design/adaptive/editor.dart +++ b/lib/design/adaptive/editor.dart @@ -3,6 +3,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/l10n/common.dart'; import 'package:rettulf/rettulf.dart'; @@ -329,7 +330,7 @@ class _IntEditorState extends State { return Row( children: [ PlatformTextButton( - child: const Icon(Icons.remove), + child: Icon(ctx.icons.remove), onPressed: () { setState(() { value--; @@ -353,7 +354,7 @@ class _IntEditorState extends State { }, ).sized(w: 100), PlatformTextButton( - child: const Icon(Icons.add), + child: Icon(ctx.icons.add), onPressed: () { setState(() { value++; diff --git a/lib/design/adaptive/multiplatform.dart b/lib/design/adaptive/multiplatform.dart index a8a3ef87e..dd5e0aec1 100644 --- a/lib/design/adaptive/multiplatform.dart +++ b/lib/design/adaptive/multiplatform.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:sit/r.dart'; import 'package:universal_platform/universal_platform.dart'; @@ -17,3 +18,7 @@ extension ShareX on BuildContext { return sharePositionOrigin; } } + +extension BuildContextPlatformIconsX on BuildContext { + PlatformIcons get icons => PlatformIcons(this); +} diff --git a/lib/design/widgets/entry_card.dart b/lib/design/widgets/entry_card.dart index b882342ee..baf7478fb 100644 --- a/lib/design/widgets/entry_card.dart +++ b/lib/design/widgets/entry_card.dart @@ -108,7 +108,7 @@ class EntryCard extends StatelessWidget { all.add( selected ? FilledButton.icon( - icon: const Icon(Icons.check), + icon: Icon(context.icons.checkMark), onPressed: null, label: selectAction.selectedLabel.text(), ) diff --git a/lib/design/widgets/expansion_tile.dart b/lib/design/widgets/expansion_tile.dart index 70e5dc6ba..527517ff7 100644 --- a/lib/design/widgets/expansion_tile.dart +++ b/lib/design/widgets/expansion_tile.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; // thanks to "https://github.com/simplewidgets/rounded_expansion_tile" const _kDefaultDuration = Duration(milliseconds: 300); @@ -178,7 +179,7 @@ class AnimatedExpansionTileState extends State with Ticke // Build trailing widget based on the user input. Widget? _trailingIcon() { - final trailing = widget.trailing ?? const Icon(Icons.keyboard_arrow_down); + final trailing = widget.trailing ?? Icon(context.icons.downArrow); if (_rotateTrailing!) { return RotationTransition(turns: Tween(begin: 0.0, end: 0.5).animate(_iconController), child: trailing); } else { diff --git a/lib/design/widgets/navigation.dart b/lib/design/widgets/navigation.dart index 470653c55..6237834b1 100644 --- a/lib/design/widgets/navigation.dart +++ b/lib/design/widgets/navigation.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; class PageNavigationTile extends StatelessWidget { final Widget? title; @@ -21,7 +22,7 @@ class PageNavigationTile extends StatelessWidget { title: title, subtitle: subtitle, leading: leading, - trailing: const Icon(Icons.navigate_next_rounded), + trailing: Icon(context.icons.rightChevron), onTap: () { context.push(path); }, diff --git a/lib/game/2048/game.dart b/lib/game/2048/game.dart index 0378e37ba..b8d2e186c 100644 --- a/lib/game/2048/game.dart +++ b/lib/game/2048/game.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_swipe_detector/flutter_swipe_detector.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'entity/board.dart'; import 'save.dart'; @@ -122,7 +123,7 @@ class _GameState extends ConsumerState with TickerProviderStateMixin, onPressed: () { ref.read(boardManager.notifier).newGame(); }, - icon: const Icon(Icons.refresh), + icon: Icon(context.icons.refresh), ) ], ), diff --git a/lib/game/minesweeper/game.dart b/lib/game/minesweeper/game.dart index 0736d1f41..a2251a5fe 100644 --- a/lib/game/minesweeper/game.dart +++ b/lib/game/minesweeper/game.dart @@ -2,6 +2,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter/material.dart'; import 'package:logger/logger.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/game/minesweeper/save.dart'; import 'model/board.dart'; import 'model/cell.dart'; @@ -121,9 +122,7 @@ class _MinesweeperState extends ConsumerState with WidgetsBindi onPressed: () { resetGame(); }, - icon: const Icon( - Icons.refresh, - ), + icon: Icon(context.icons.refresh), ) ], ), diff --git a/lib/life/electricity/index.dart b/lib/life/electricity/index.dart index c2ff2ea37..438b21355 100644 --- a/lib/life/electricity/index.dart +++ b/lib/life/electricity/index.dart @@ -2,13 +2,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart' hide isCupertino; import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/app.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/l10n/extension.dart'; import 'package:sit/settings/settings.dart'; -import 'package:sit/r.dart'; import 'package:sit/utils/async_event.dart'; import 'package:rettulf/rettulf.dart'; import 'package:share_plus/share_plus.dart'; @@ -162,14 +160,14 @@ class _ElectricityBalanceAppCardState extends State { return Menu( children: [ MenuAction( - image: MenuImage.icon(PlatformIcons(context).share), + image: MenuImage.icon(context.icons.share), title: i18n.share, callback: () async { await shareBalance(balance: balance, selectedRoom: selectedRoom, context: ctx); }, ), MenuAction( - image: MenuImage.icon(PlatformIcons(context).delete), + image: MenuImage.icon(context.icons.delete), title: i18n.delete, attributes: const MenuActionAttributes(destructive: true), activator: const SingleActivator(LogicalKeyboardKey.delete), diff --git a/lib/life/expense_records/page/records.dart b/lib/life/expense_records/page/records.dart index 88e4a20a7..f23edc02f 100644 --- a/lib/life/expense_records/page/records.dart +++ b/lib/life/expense_records/page/records.dart @@ -1,8 +1,8 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:sit/credentials/widgets/oa_scope.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/common.dart'; import 'package:sit/life/expense_records/storage/local.dart'; import 'package:rettulf/rettulf.dart'; @@ -89,7 +89,7 @@ class _ExpenseRecordsPageState extends State { actions: [ IconButton( tooltip: i18n.delete, - icon: Icon(PlatformIcons(context).delete), + icon: Icon(context.icons.delete), onPressed: () async { ExpenseRecordsInit.storage.clearIndex(); await HapticFeedback.heavyImpact(); diff --git a/lib/school/yellow_pages/widgets/search.dart b/lib/school/yellow_pages/widgets/search.dart index fcedc4b4a..cdf4e9941 100644 --- a/lib/school/yellow_pages/widgets/search.dart +++ b/lib/school/yellow_pages/widgets/search.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import '../entity/contact.dart'; import 'list.dart'; @@ -12,7 +13,7 @@ class YellowPageSearchDelegate extends SearchDelegate { List? buildActions(BuildContext context) { return [ IconButton( - icon: const Icon(Icons.clear), + icon: Icon(context.icons.clear), onPressed: () => query = "", ), ]; diff --git a/lib/school/ywb/widgets/application.dart b/lib/school/ywb/widgets/application.dart index 3cde3c4f6..00ca34852 100644 --- a/lib/school/ywb/widgets/application.dart +++ b/lib/school/ywb/widgets/application.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/expansion_tile.dart'; import 'package:sit/l10n/extension.dart'; import 'package:rettulf/rettulf.dart'; @@ -37,8 +38,8 @@ class YwbApplicationTrackTile extends StatelessWidget { return ListTile( isThreeLine: true, leading: track.isActionOk - ? const Icon(Icons.check, color: Colors.green) - : const Icon(Icons.error_outline, color: Colors.redAccent), + ? Icon(context.icons.checkMark, color: Colors.green) + : Icon(context.icons.error, color: Colors.redAccent), title: track.step.text(), subtitle: [ context.formatYmdhmNum(track.timestamp).text(), diff --git a/lib/timetable/page/p13n/background.dart b/lib/timetable/page/p13n/background.dart index 73440ab16..9b85afeca 100644 --- a/lib/timetable/page/p13n/background.dart +++ b/lib/timetable/page/p13n/background.dart @@ -7,6 +7,7 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:go_router/go_router.dart'; import 'package:image_picker/image_picker.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/card.dart'; import 'package:sit/design/widgets/common.dart'; import 'package:sit/files.dart'; @@ -157,7 +158,7 @@ class _TimetableBackgroundEditorState extends State w return [ FilledButton.icon( onPressed: pickImage, - icon: Icon(PlatformIcons(context).edit), + icon: Icon(context.icons.edit), label: i18n.choose.text(), ), OutlinedButton.icon( @@ -169,7 +170,7 @@ class _TimetableBackgroundEditorState extends State w renderImageFile = null; }); }, - icon: Icon(PlatformIcons(context).delete), + icon: Icon(context.icons.delete), label: i18n.delete.text(), ), ].row(maa: MainAxisAlignment.spaceEvenly); diff --git a/lib/widgets/modal_image_view.dart b/lib/widgets/modal_image_view.dart index 5a049a12e..793ca8054 100644 --- a/lib/widgets/modal_image_view.dart +++ b/lib/widgets/modal_image_view.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; class ModalImageViewer extends StatelessWidget { const ModalImageViewer({ @@ -76,7 +76,7 @@ class FullScreenViewer extends StatelessWidget { alignment: Alignment.topRight, child: IconButton( icon: Icon( - PlatformIcons(context).clear, + context.icons.clear, ), onPressed: () { Navigator.of(context).pop(); From 016daaf0c8d8a0674915a6b45dec707fd14a0bf0 Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:01:19 +0800 Subject: [PATCH 03/15] PlatformIcons --- lib/design/adaptive/multiplatform.dart | 5 +++++ lib/design/widgets/entry_card.dart | 4 ++-- lib/life/electricity/index.dart | 4 ++-- lib/login/page/index.dart | 4 ++-- lib/me/edu_email/page/login.dart | 5 +++-- lib/me/index.dart | 2 +- lib/qrcode/page/scanner.dart | 11 ++--------- lib/school/class2nd/page/activity.dart | 3 ++- lib/school/class2nd/page/attended.dart | 3 ++- lib/school/class2nd/widgets/search.dart | 3 ++- lib/school/library/index.dart | 6 +++--- lib/school/library/page/details.dart | 5 +++-- lib/school/library/page/login.dart | 5 +++-- lib/school/widgets/campus.dart | 3 ++- lib/school/yellow_pages/page/index.dart | 3 ++- lib/school/ywb/index.dart | 3 ++- lib/school/ywb/page/details.dart | 3 ++- lib/school/ywb/page/service.dart | 3 ++- 18 files changed, 42 insertions(+), 33 deletions(-) diff --git a/lib/design/adaptive/multiplatform.dart b/lib/design/adaptive/multiplatform.dart index dd5e0aec1..751adb6ed 100644 --- a/lib/design/adaptive/multiplatform.dart +++ b/lib/design/adaptive/multiplatform.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:sit/r.dart'; import 'package:universal_platform/universal_platform.dart'; @@ -22,3 +23,7 @@ extension ShareX on BuildContext { extension BuildContextPlatformIconsX on BuildContext { PlatformIcons get icons => PlatformIcons(this); } + +extension PlatformIconsX on PlatformIcons { + IconData get lock => isMaterial(context) ? Icons.lock : CupertinoIcons.lock; +} diff --git a/lib/design/widgets/entry_card.dart b/lib/design/widgets/entry_card.dart index baf7478fb..b850569aa 100644 --- a/lib/design/widgets/entry_card.dart +++ b/lib/design/widgets/entry_card.dart @@ -227,8 +227,8 @@ class EntryCard extends StatelessWidget { padding: EdgeInsets.zero, onPressed: selected ? null : selectAction.action, child: selected - ? Icon(CupertinoIcons.check_mark, color: context.colorScheme.primary) - : const Icon(CupertinoIcons.square), + ? Icon(context.icons.checkMark, color: context.colorScheme.primary) + : Icon(context.icons.checkBoxBlankOutlineRounded), ), ], ), diff --git a/lib/life/electricity/index.dart b/lib/life/electricity/index.dart index 438b21355..e47b57410 100644 --- a/lib/life/electricity/index.dart +++ b/lib/life/electricity/index.dart @@ -123,7 +123,7 @@ class _ElectricityBalanceAppCardState extends State { } }, label: i18n.searchRoom.text(), - icon: const Icon(Icons.search), + icon: Icon(context.icons.search), ), ], rightActions: [ @@ -133,7 +133,7 @@ class _ElectricityBalanceAppCardState extends State { onPressed: () async { await shareBalance(balance: balance, selectedRoom: selectedRoom, context: context); }, - icon: const Icon(Icons.share_outlined), + icon: Icon(context.icons.share), ), ], ); diff --git a/lib/login/page/index.dart b/lib/login/page/index.dart index fb4310ab2..f3292b25d 100644 --- a/lib/login/page/index.dart +++ b/lib/login/page/index.dart @@ -246,9 +246,9 @@ class _LoginPageState extends State { decoration: InputDecoration( labelText: i18n.credentials.oaPwd, hintText: i18n.oaPwdHint, - icon: const Icon(Icons.lock), + icon: Icon(context.icons.lock), suffixIcon: IconButton( - icon: Icon(isPasswordClear ? Icons.visibility : Icons.visibility_off), + icon: Icon(isPasswordClear ? context.icons.eyeSolid : context.icons.eyeSlashSolid), onPressed: () { setState(() { isPasswordClear = !isPasswordClear; diff --git a/lib/me/edu_email/page/login.dart b/lib/me/edu_email/page/login.dart index 37684e56f..9e79ad9fd 100644 --- a/lib/me/edu_email/page/login.dart +++ b/lib/me/edu_email/page/login.dart @@ -5,6 +5,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import 'package:sit/credentials/entity/credential.dart'; import 'package:sit/credentials/init.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/login/utils.dart'; import 'package:sit/login/widgets/forgot_pwd.dart'; import 'package:sit/r.dart'; @@ -114,10 +115,10 @@ class _EduEmailLoginPageState extends State { }, decoration: InputDecoration( labelText: i18n.login.credentials.pwd, - icon: const Icon(Icons.lock), + icon: Icon(context.icons.lock), hintText: i18n.login.passwordHint, suffixIcon: IconButton( - icon: Icon(isPasswordClear ? Icons.visibility : Icons.visibility_off), + icon: Icon(isPasswordClear ? context.icons.eyeSolid : context.icons.eyeSlashSolid), onPressed: () { setState(() { isPasswordClear = !isPasswordClear; diff --git a/lib/me/index.dart b/lib/me/index.dart index 0ab24a3e7..d4bb52232 100644 --- a/lib/me/index.dart +++ b/lib/me/index.dart @@ -39,7 +39,7 @@ class _MePageState extends State { actions: [ buildScannerAction(), IconButton( - icon: isCupertino ? const Icon(CupertinoIcons.settings) : const Icon(Icons.settings), + icon: Icon(context.icons.settings), onPressed: () { context.push("/settings"); }, diff --git a/lib/qrcode/page/scanner.dart b/lib/qrcode/page/scanner.dart index 5fcbbc7a6..85a6e1428 100644 --- a/lib/qrcode/page/scanner.dart +++ b/lib/qrcode/page/scanner.dart @@ -5,6 +5,7 @@ import 'package:image_picker/image_picker.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import '../i18n.dart'; import '../widgets/overlay.dart'; @@ -108,15 +109,7 @@ class _ScannerPageState extends State with SingleTickerProviderStat Widget buildSwitchButton() { return IconButton( iconSize: _iconSize, - icon: controller.cameraFacingState >> - (context, state) { - switch (state) { - case CameraFacing.front: - return const Icon(Icons.camera_front); - case CameraFacing.back: - return const Icon(Icons.camera_rear); - } - }, + icon: Icon(context.icons.switchCamera), onPressed: () => controller.switchCamera(), ); } diff --git a/lib/school/class2nd/page/activity.dart b/lib/school/class2nd/page/activity.dart index 35e4fb7fb..ef4b16e4e 100644 --- a/lib/school/class2nd/page/activity.dart +++ b/lib/school/class2nd/page/activity.dart @@ -2,6 +2,7 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/common.dart'; import 'package:sit/utils/collection.dart'; import 'package:sit/utils/error.dart'; @@ -54,7 +55,7 @@ class _ActivityListPageState extends State { forceElevated: innerBoxIsScrolled, actions: [ IconButton( - icon: const Icon(Icons.search), + icon: Icon(context.icons.search), onPressed: () => showSearch(context: context, delegate: ActivitySearchDelegate()), ), ], diff --git a/lib/school/class2nd/page/attended.dart b/lib/school/class2nd/page/attended.dart index c8ca9f503..09bbf7277 100644 --- a/lib/school/class2nd/page/attended.dart +++ b/lib/school/class2nd/page/attended.dart @@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart'; import 'package:sit/credentials/widgets/oa_scope.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/animation/progress.dart'; import 'package:sit/design/widgets/card.dart'; import 'package:sit/design/widgets/common.dart'; @@ -112,7 +113,7 @@ class _AttendedActivityPageState extends State { delegate: AttendedActivitySearchDelegate(attended ?? []), ); }, - icon: const Icon(Icons.search), + icon: Icon(context.icons.search), ), ], bottom: isFetching diff --git a/lib/school/class2nd/widgets/search.dart b/lib/school/class2nd/widgets/search.dart index 5979241cf..9cce0c796 100644 --- a/lib/school/class2nd/widgets/search.dart +++ b/lib/school/class2nd/widgets/search.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/common.dart'; import '../entity/activity.dart'; @@ -12,7 +13,7 @@ class ActivitySearchDelegate extends SearchDelegate { @override List? buildActions(BuildContext context) { return [ - IconButton(onPressed: () => query = '', icon: const Icon(Icons.clear)), + IconButton(onPressed: () => query = '', icon: Icon(context.icons.clear)), ]; } diff --git a/lib/school/library/index.dart b/lib/school/library/index.dart index fec444ff5..ef845801e 100644 --- a/lib/school/library/index.dart +++ b/lib/school/library/index.dart @@ -55,7 +55,7 @@ class _LibraryAppCardState extends State { onPressed: () async { await showSearch(context: context, delegate: LibrarySearchDelegate()); }, - icon: const Icon(Icons.search), + icon: Icon(context.icons.search), label: i18n.action.searchBooks.text(), ), if (credentials == null) @@ -70,7 +70,7 @@ class _LibraryAppCardState extends State { onPressed: () async { await context.push("/library/borrowing"); }, - icon: const Icon(Icons.person), + icon: Icon(context.icons.person), label: i18n.action.borrowing.text(), ) ], @@ -91,7 +91,7 @@ class _LibraryAppCardState extends State { return Menu( children: [ MenuAction( - image: MenuImage.icon(CupertinoIcons.refresh), + image: MenuImage.icon(context.icons.refresh), title: i18n.borrowing.renew, callback: () async { await renewBorrowedBook(ctx, book.barcode); diff --git a/lib/school/library/page/details.dart b/lib/school/library/page/details.dart index 63533b64c..b5396b56e 100644 --- a/lib/school/library/page/details.dart +++ b/lib/school/library/page/details.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/list_tile.dart'; import 'package:sit/school/library/aggregated.dart'; import 'package:sit/school/library/page/details.model.dart'; @@ -115,7 +116,7 @@ class _BookDetailsPageState extends State { trailing: onSearchTap == null ? null : IconButton( - icon: const Icon(Icons.youtube_searched_for), + icon: Icon(context.icons.search), onPressed: () { onSearchTap.call(SearchMethod.title, book.title); }, @@ -127,7 +128,7 @@ class _BookDetailsPageState extends State { trailing: onSearchTap == null ? null : IconButton( - icon: const Icon(Icons.youtube_searched_for), + icon: Icon(context.icons.search), onPressed: () { onSearchTap.call(SearchMethod.author, book.author); }, diff --git a/lib/school/library/page/login.dart b/lib/school/library/page/login.dart index 3e1a2b225..7e75b6df7 100644 --- a/lib/school/library/page/login.dart +++ b/lib/school/library/page/login.dart @@ -4,6 +4,7 @@ import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; import 'package:sit/credentials/entity/credential.dart'; import 'package:sit/credentials/init.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/login/utils.dart'; import 'package:sit/login/widgets/forgot_pwd.dart'; import 'package:rettulf/rettulf.dart'; @@ -106,9 +107,9 @@ class _LibraryLoginPageState extends State { decoration: InputDecoration( labelText: i18n.login.credentials.pwd, hintText: i18n.login.passwordHint, - icon: const Icon(Icons.lock), + icon: Icon(context.icons.lock), suffixIcon: IconButton( - icon: Icon(isPasswordClear ? Icons.visibility : Icons.visibility_off), + icon: Icon(isPasswordClear ? context.icons.eyeSolid: context.icons.eyeSlashSolid), onPressed: () { setState(() { isPasswordClear = !isPasswordClear; diff --git a/lib/school/widgets/campus.dart b/lib/school/widgets/campus.dart index e934ff418..62caa6d08 100644 --- a/lib/school/widgets/campus.dart +++ b/lib/school/widgets/campus.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/entity/campus.dart'; import 'package:sit/settings/settings.dart'; import 'package:rettulf/rettulf.dart'; @@ -13,7 +14,7 @@ class CampusSelector extends StatelessWidget { builder: (ctx, setState) => SegmentedButton( segments: Campus.values .map((e) => ButtonSegment( - icon: const Icon(Icons.place_outlined), + icon: Icon(context.icons.location), value: e, label: e.l10nName().text(), )) diff --git a/lib/school/yellow_pages/page/index.dart b/lib/school/yellow_pages/page/index.dart index 4935463eb..171fd1c1d 100644 --- a/lib/school/yellow_pages/page/index.dart +++ b/lib/school/yellow_pages/page/index.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/r.dart'; import 'package:sit/school/yellow_pages/init.dart'; import 'package:sit/school/yellow_pages/storage/contact.dart'; @@ -28,7 +29,7 @@ class _YellowPagesListPageState extends State { if (result == null) return; YellowPagesInit.storage.addInteractHistory(result); }, - icon: const Icon(Icons.search), + icon: Icon(context.icons.search), ), ], ), diff --git a/lib/school/ywb/index.dart b/lib/school/ywb/index.dart index 8e3b6110e..ede446be2 100644 --- a/lib/school/ywb/index.dart +++ b/lib/school/ywb/index.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/app.dart'; import 'package:sit/school/ywb/entity/application.dart'; import 'package:sit/school/ywb/init.dart'; @@ -55,7 +56,7 @@ class _YwbAppCardState extends State { context.push("/ywb/mine"); }, label: i18n.action.applications.text(), - icon: const Icon(Icons.mail_outlined), + icon: Icon(context.icons.mail), ) ], ); diff --git a/lib/school/ywb/page/details.dart b/lib/school/ywb/page/details.dart index 89f15d4b1..e7946108d 100644 --- a/lib/school/ywb/page/details.dart +++ b/lib/school/ywb/page/details.dart @@ -1,5 +1,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/fab.dart'; import 'package:sit/utils/error.dart'; import 'package:sit/utils/guard_launch.dart'; @@ -89,7 +90,7 @@ class _YwbServiceDetailsPageState extends State { floatingActionButton: AutoHideFAB.extended( controller: controller, onPressed: () => openInApp(), - icon: const Icon(Icons.east), + icon: Icon(context.icons.rightChevron), label: i18n.details.apply.text(), ), bottomNavigationBar: isFetching diff --git a/lib/school/ywb/page/service.dart b/lib/school/ywb/page/service.dart index 25aacb4c9..d504c1c9b 100644 --- a/lib/school/ywb/page/service.dart +++ b/lib/school/ywb/page/service.dart @@ -1,6 +1,7 @@ import 'package:collection/collection.dart'; import 'package:fit_system_screenshot/fit_system_screenshot.dart'; import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/common.dart'; import 'package:rettulf/rettulf.dart'; import 'package:sit/utils/error.dart'; @@ -88,7 +89,7 @@ class _YwbServiceListPageState extends State { Tooltip( triggerMode: TooltipTriggerMode.tap, message: i18n.info, - child: const Icon(Icons.info_outline).padAll(8), + child: Icon(context.icons.info).padAll(8), ), ], bottom: isLoading From f78e642d9059a0ea0050875a38564578c92e5913 Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:04:12 +0800 Subject: [PATCH 04/15] SwipeToDismissAction.icon --- lib/design/adaptive/swipe.dart | 6 ++---- lib/life/electricity/widget/search.dart | 4 ++-- lib/timetable/page/editor.dart | 7 +++---- lib/timetable/page/p13n/palette_editor.dart | 4 ++-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/design/adaptive/swipe.dart b/lib/design/adaptive/swipe.dart index c67f095e3..3994dfbca 100644 --- a/lib/design/adaptive/swipe.dart +++ b/lib/design/adaptive/swipe.dart @@ -8,13 +8,11 @@ import 'multiplatform.dart'; class SwipeToDismissAction { final VoidCallback action; final Icon? icon; - final Icon? cupertinoIcon; final String? label; SwipeToDismissAction({ required this.action, this.icon, - this.cupertinoIcon, this.label, }); } @@ -46,7 +44,7 @@ class SwipeToDismiss extends StatelessWidget { : [ SwipeAction( title: right.label, - icon: isCupertino ? right.cupertinoIcon : right.icon, + icon: right.icon, style: context.textTheme.titleSmall ?? const TextStyle(), performsFirstActionWithFullSwipe: true, onTap: (CompletionHandler handler) async { @@ -61,7 +59,7 @@ class SwipeToDismiss extends StatelessWidget { : [ SwipeAction( title: left.label, - icon: isCupertino ? left.cupertinoIcon : left.icon, + icon: left.icon, style: context.textTheme.titleSmall ?? const TextStyle(), performsFirstActionWithFullSwipe: true, onTap: (CompletionHandler handler) async { diff --git a/lib/life/electricity/widget/search.dart b/lib/life/electricity/widget/search.dart index a05db527c..123da44ac 100644 --- a/lib/life/electricity/widget/search.dart +++ b/lib/life/electricity/widget/search.dart @@ -1,5 +1,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/adaptive/swipe.dart'; import 'package:sit/life/electricity/entity/room.dart'; import 'package:sit/widgets/search.dart'; @@ -50,8 +51,7 @@ Future searchRoom({ final room = DormitoryRoom.fromFullString(full); return SwipeToDismiss( right: SwipeToDismissAction( - icon: const Icon(Icons.delete), - cupertinoIcon: const Icon(CupertinoIcons.delete), + icon: Icon(ctx.icons.delete), action: () { final newList = List.of($searchHistory.value); newList.removeAt(i); diff --git a/lib/timetable/page/editor.dart b/lib/timetable/page/editor.dart index d7188fb45..5cb88a7e8 100644 --- a/lib/timetable/page/editor.dart +++ b/lib/timetable/page/editor.dart @@ -8,6 +8,7 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:go_router/go_router.dart'; import 'package:sit/design/adaptive/editor.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/adaptive/swipe.dart'; import 'package:sit/design/widgets/expansion_tile.dart'; import 'package:sit/l10n/extension.dart'; @@ -352,8 +353,7 @@ class TimetableEditableCourseCard extends StatelessWidget { right: onCourseRemoved == null ? null : SwipeToDismissAction( - icon: const Icon(Icons.delete), - cupertinoIcon: const Icon(CupertinoIcons.delete), + icon: Icon(context.icons.delete), action: () async { onCourseRemoved(course); }, @@ -729,8 +729,7 @@ class RepeatingItemEditor extends StatelessWidget { right: onDeleted == null ? null : SwipeToDismissAction( - icon: const Icon(Icons.delete), - cupertinoIcon: const Icon(CupertinoIcons.delete), + icon: Icon(context.icons.delete), action: () async { onDeleted(); }, diff --git a/lib/timetable/page/p13n/palette_editor.dart b/lib/timetable/page/p13n/palette_editor.dart index 13bc1b074..e6b9eeef1 100644 --- a/lib/timetable/page/p13n/palette_editor.dart +++ b/lib/timetable/page/p13n/palette_editor.dart @@ -6,6 +6,7 @@ import 'package:flutter_platform_widgets/flutter_platform_widgets.dart' hide isC import 'package:rettulf/rettulf.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/adaptive/swipe.dart'; import 'package:sit/design/widgets/card.dart'; import 'package:sit/l10n/extension.dart'; @@ -196,8 +197,7 @@ class _TimetablePaletteEditorPageState extends State return SwipeToDismiss( childKey: ObjectKey(current), right: SwipeToDismissAction( - icon: const Icon(Icons.delete), - cupertinoIcon: const Icon(CupertinoIcons.delete), + icon: Icon(ctx.icons.delete), action: () async { setState(() { colors.removeAt(index); From bb443afd6710da0539ac61432dfa28f98188e252 Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:12:13 +0800 Subject: [PATCH 05/15] EntryCard.icon & PullDownItem.icon --- lib/design/adaptive/menu.dart | 10 +++------- lib/design/adaptive/multiplatform.dart | 6 ++++++ lib/design/widgets/entry_card.dart | 16 +++++----------- lib/settings/page/storage.dart | 4 ++-- lib/timetable/page/mine.dart | 15 +++++++-------- lib/timetable/page/p13n/palette.dart | 12 ++++++------ 6 files changed, 29 insertions(+), 34 deletions(-) diff --git a/lib/design/adaptive/menu.dart b/lib/design/adaptive/menu.dart index b245797bc..8adf724da 100644 --- a/lib/design/adaptive/menu.dart +++ b/lib/design/adaptive/menu.dart @@ -29,30 +29,26 @@ class PullDownItem implements PullDownEntry { final String title; final VoidCallback? onTap; final IconData? icon; - final IconData? cupertinoIcon; final bool destructive; const PullDownItem({ required this.title, this.onTap, this.icon, - this.cupertinoIcon, this.destructive = false, }); const PullDownItem.edit({ required this.title, this.onTap, - this.icon = Icons.edit, - this.cupertinoIcon = CupertinoIcons.pencil, + this.icon, this.destructive = false, }); const PullDownItem.delete({ required this.title, this.onTap, - this.icon = Icons.delete, - this.cupertinoIcon = CupertinoIcons.delete, + this.icon, }) : destructive = true; @override @@ -61,7 +57,7 @@ class PullDownItem implements PullDownEntry { onTap: onTap, title: title, isDestructive: destructive, - icon: cupertinoIcon ?? icon, + icon: icon, ); } diff --git a/lib/design/adaptive/multiplatform.dart b/lib/design/adaptive/multiplatform.dart index 751adb6ed..24b2c6080 100644 --- a/lib/design/adaptive/multiplatform.dart +++ b/lib/design/adaptive/multiplatform.dart @@ -26,4 +26,10 @@ extension BuildContextPlatformIconsX on BuildContext { extension PlatformIconsX on PlatformIcons { IconData get lock => isMaterial(context) ? Icons.lock : CupertinoIcons.lock; + + IconData get copy => isMaterial(context) ? Icons.copy : CupertinoIcons.plus_square_on_square; + + IconData get calendar => isMaterial(context) ? Icons.calendar_month : CupertinoIcons.calendar; + + IconData get qrcode => isMaterial(context) ? Icons.qr_code : CupertinoIcons.qrcode; } diff --git a/lib/design/widgets/entry_card.dart b/lib/design/widgets/entry_card.dart index b850569aa..f2179a686 100644 --- a/lib/design/widgets/entry_card.dart +++ b/lib/design/widgets/entry_card.dart @@ -18,7 +18,6 @@ enum EntryActionType { class EntryAction { final IconData? icon; - final IconData? cupertinoIcon; final bool main; final String label; final EntryActionType type; @@ -31,7 +30,6 @@ class EntryAction { this.main = false, this.icon, this.oneShot = false, - this.cupertinoIcon, required this.action, this.activator, this.type = EntryActionType.other, @@ -40,8 +38,7 @@ class EntryAction { const EntryAction.edit({ required this.label, this.main = false, - this.icon = Icons.edit, - this.cupertinoIcon = CupertinoIcons.pencil, + this.icon, required this.action, this.activator, }) : oneShot = true, @@ -50,8 +47,7 @@ class EntryAction { const EntryAction.delete({ required this.label, this.main = false, - this.icon = Icons.delete, - this.cupertinoIcon = CupertinoIcons.delete, + this.icon, required this.action, this.activator = const SingleActivator(LogicalKeyboardKey.delete), }) : oneShot = true, @@ -262,7 +258,7 @@ class EntryCard extends StatelessWidget { } for (final action in actions) { final callback = action.action; - final icon = action.cupertinoIcon ?? action.icon; + final icon = action.icon; all.add(MenuAction( image: icon == null ? null : MenuImage.icon(icon), title: action.label, @@ -271,7 +267,7 @@ class EntryCard extends StatelessWidget { )); } if (deleteAction != null) { - final icon = deleteAction.cupertinoIcon; + final icon = deleteAction.icon; all.add(MenuAction( image: icon == null ? null : MenuImage.icon(icon), title: deleteAction.label, @@ -307,8 +303,7 @@ class EntryCard extends StatelessWidget { EntryAction( label: selectAction.selectLabel, oneShot: true, - icon: Icons.check, - cupertinoIcon: CupertinoIcons.check_mark, + icon: context.icons.checkMark, action: selectAction.action, ), ); @@ -329,7 +324,6 @@ class EntryCard extends StatelessWidget { ...actions.map( (action) => PullDownItem( icon: action.icon, - cupertinoIcon: action.cupertinoIcon, title: action.label, onTap: () async { if (action.oneShot) { diff --git a/lib/settings/page/storage.dart b/lib/settings/page/storage.dart index 7180357c2..07788a740 100644 --- a/lib/settings/page/storage.dart +++ b/lib/settings/page/storage.dart @@ -5,6 +5,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:go_router/go_router.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/utils/hive.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:sit/design/adaptive/menu.dart'; @@ -272,8 +273,7 @@ class _BoxItemState extends State { return PullDownMenuButton( itemBuilder: (ctx) => [ PullDownItem.delete( - icon: Icons.cleaning_services_outlined, - cupertinoIcon: CupertinoIcons.clear, + icon: ctx.icons.clear, title: i18n.clear, onTap: () async { final confirm = await context.showRequest( diff --git a/lib/timetable/page/mine.dart b/lib/timetable/page/mine.dart index 14605c3f3..ab4e97a86 100644 --- a/lib/timetable/page/mine.dart +++ b/lib/timetable/page/mine.dart @@ -5,6 +5,7 @@ import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:sit/design/adaptive/foundation.dart'; import 'package:sit/design/adaptive/menu.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/common.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/design/widgets/entry_card.dart'; @@ -225,6 +226,7 @@ class TimetableCard extends StatelessWidget { ), deleteAction: (ctx) => EntryAction.delete( label: i18n.delete, + icon: context.icons.delete, action: () async { final confirm = await ctx.showRequest( title: i18n.mine.deleteRequest, @@ -246,9 +248,8 @@ class TimetableCard extends StatelessWidget { EntryAction( main: true, label: i18n.preview, - icon: Icons.preview, + icon: isCupertino ? CupertinoIcons.eye : Icons.preview, activator: const SingleActivator(LogicalKeyboardKey.keyP), - cupertinoIcon: CupertinoIcons.eye, action: () async { if (!ctx.mounted) return; await context.show$Sheet$( @@ -262,6 +263,7 @@ class TimetableCard extends StatelessWidget { ), EntryAction.edit( label: i18n.edit, + icon: context.icons.edit, activator: const SingleActivator(LogicalKeyboardKey.keyE), action: () async { final newTimetable = await ctx.push("/timetable/edit/$id"); @@ -272,8 +274,7 @@ class TimetableCard extends StatelessWidget { ), EntryAction( label: i18n.share, - icon: Icons.output_outlined, - cupertinoIcon: CupertinoIcons.share, + icon: context.icons.share, type: EntryActionType.share, action: () async { await exportTimetableFileAndShare(timetable, context: ctx); @@ -281,17 +282,15 @@ class TimetableCard extends StatelessWidget { ), EntryAction( label: i18n.mine.exportCalendar, - icon: Icons.calendar_month, - cupertinoIcon: CupertinoIcons.calendar_badge_plus, + icon: context.icons.calendar, action: () async { await onExportCalendar(ctx, timetable); }, ), EntryAction( label: i18n.duplicate, - icon: Icons.copy, oneShot: true, - cupertinoIcon: CupertinoIcons.plus_square_on_square, + icon: context.icons.copy, activator: const SingleActivator(LogicalKeyboardKey.keyD), action: () async { final duplicate = timetable.copyWith( diff --git a/lib/timetable/page/p13n/palette.dart b/lib/timetable/page/p13n/palette.dart index b6c01e9de..dca37162f 100644 --- a/lib/timetable/page/p13n/palette.dart +++ b/lib/timetable/page/p13n/palette.dart @@ -8,6 +8,7 @@ import 'package:go_router/go_router.dart'; import 'package:rettulf/rettulf.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/card.dart'; import 'package:sit/design/widgets/entry_card.dart'; import 'package:sit/l10n/extension.dart'; @@ -205,6 +206,7 @@ class PaletteCard extends StatelessWidget { ? null : (ctx) => EntryAction.delete( label: i18n.delete, + icon: context.icons.delete, action: () async { final confirm = await ctx.showRequest( title: i18n.p13n.palette.deleteRequest, @@ -223,6 +225,7 @@ class PaletteCard extends StatelessWidget { EntryAction.edit( main: true, label: i18n.edit, + icon: context.icons.edit, activator: const SingleActivator(LogicalKeyboardKey.keyE), action: () async { final newPalette = await context.push("/timetable/palette/edit/$id"); @@ -234,8 +237,7 @@ class PaletteCard extends StatelessWidget { if (timetable != null && palette.colors.isNotEmpty) EntryAction( label: i18n.preview, - icon: Icons.preview, - cupertinoIcon: CupertinoIcons.eye, + icon: isCupertino ? CupertinoIcons.eye : Icons.preview, activator: const SingleActivator(LogicalKeyboardKey.keyP), action: () async { await context.show$Sheet$( @@ -250,9 +252,8 @@ class PaletteCard extends StatelessWidget { ), EntryAction( label: i18n.duplicate, - icon: Icons.copy, + icon: context.icons.copy, oneShot: true, - cupertinoIcon: CupertinoIcons.plus_square_on_square, activator: const SingleActivator(LogicalKeyboardKey.keyD), action: () async { final duplicate = palette.copyWith( @@ -268,8 +269,7 @@ class PaletteCard extends StatelessWidget { if (!kIsWeb) EntryAction( label: i18n.p13n.palette.shareQrCode, - icon: Icons.qr_code, - cupertinoIcon: CupertinoIcons.qrcode, + icon: context.icons.qrcode, action: () async { final qrCodeData = const TimetablePaletteDeepLink().encode(palette); await ctx.show$Sheet$( From 1e92b5c2a411b1d8247549ed6f0b8b12f546edce Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:13:27 +0800 Subject: [PATCH 06/15] [settings] ThemeMode.isThreeLine --- lib/settings/page/index.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/settings/page/index.dart b/lib/settings/page/index.dart index 10cf9cd13..d61fb6235 100644 --- a/lib/settings/page/index.dart +++ b/lib/settings/page/index.dart @@ -165,6 +165,7 @@ class _SettingsPageState extends State { ThemeMode.light => const Icon(Icons.light_mode), ThemeMode.system => const Icon(Icons.brightness_auto), }, + isThreeLine: true, title: i18n.themeModeTitle.text(), subtitle: ThemeMode.values .map((mode) => ChoiceChip( From c85d6f933ddb486a7d47ef447b690911c359357b Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:14:50 +0800 Subject: [PATCH 07/15] [settings] check mark in language settings --- lib/settings/page/language.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/settings/page/language.dart b/lib/settings/page/language.dart index 31c1ca53d..0ad359936 100644 --- a/lib/settings/page/language.dart +++ b/lib/settings/page/language.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:go_router/go_router.dart'; import 'package:locale_names/locale_names.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/r.dart'; import 'package:rettulf/rettulf.dart'; import '../i18n.dart'; @@ -41,9 +42,11 @@ class _LanguagePageState extends State { itemCount: R.supportedLocales.length, itemBuilder: (ctx, i) { final locale = R.supportedLocales[i]; + final isSelected = selected == locale; return ListTile( - selected: selected == locale, + selected: isSelected, title: locale.nativeDisplayLanguageScript.text(), + trailing: isSelected ? Icon(ctx.icons.checkMark) : null, onTap: () { setState(() { selected = locale; From 5836d0e66a974738b52534fd17e7aaaf08c211dc Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:21:47 +0800 Subject: [PATCH 08/15] [settings] disabled color in theme color settings --- lib/settings/page/theme_color.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/settings/page/theme_color.dart b/lib/settings/page/theme_color.dart index 2b8fa9131..066f2e5e6 100644 --- a/lib/settings/page/theme_color.dart +++ b/lib/settings/page/theme_color.dart @@ -103,7 +103,7 @@ class _ThemeColorPageState extends State { subtitle: "#${themeColor.hexAlpha}".text(), onTap: selectNewThemeColor, trailing: FilledCard( - color: themeColor, + color: fromSystem ? context.theme.disabledColor : themeColor, clip: Clip.hardEdge, child: const SizedBox( width: 32, From e984dd61932ff53b9230e5acb36eaff4b0a6ae3d Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 02:35:29 +0800 Subject: [PATCH 09/15] [library] empty borrowing/history list --- assets/l10n/en.yaml | 2 ++ assets/l10n/zh-Hans.yaml | 2 ++ assets/l10n/zh-Hant.yaml | 2 ++ lib/school/library/i18n.dart | 4 ++++ lib/school/library/page/borrowing.dart | 27 +++++++++++++++++--------- lib/school/library/page/history.dart | 21 ++++++++++++++------ 6 files changed, 43 insertions(+), 15 deletions(-) diff --git a/assets/l10n/en.yaml b/assets/l10n/en.yaml index 7f269e92e..424b0f724 100644 --- a/assets/l10n/en.yaml +++ b/assets/l10n/en.yaml @@ -530,11 +530,13 @@ library: title: Borrowing history: History renew: Renew + noBorrowing: No borrowing books history: title: History operation: borrowing: Borrowing returning: Returning + noHistory: No borrowing history searchMethod: any: Any title: Title diff --git a/assets/l10n/zh-Hans.yaml b/assets/l10n/zh-Hans.yaml index 6a5ff6201..2bb140a9a 100644 --- a/assets/l10n/zh-Hans.yaml +++ b/assets/l10n/zh-Hans.yaml @@ -530,11 +530,13 @@ library: title: 你的借阅 history: 历史 renew: 续借 + noBorrowing: 你没有借阅中的书籍 history: title: 历史 operation: borrowing: 借书 returning: 还书 + noHistory: 你没有借阅记录 searchMethod: any: 任意 title: 标题 diff --git a/assets/l10n/zh-Hant.yaml b/assets/l10n/zh-Hant.yaml index f2a9d6795..eea5208b7 100644 --- a/assets/l10n/zh-Hant.yaml +++ b/assets/l10n/zh-Hant.yaml @@ -530,11 +530,13 @@ library: title: 你的借閱 history: 歷史 renew: 續借 + noBorrowing: 你沒有借閱中的書籍 history: title: 歷史 operation: borrowing: 借書 returning: 還書 + noHistory: 你沒有借閱歷史 searchMethod: any: 任意 title: 標題 diff --git a/lib/school/library/i18n.dart b/lib/school/library/i18n.dart index 0475ecb63..5c9ed2e62 100644 --- a/lib/school/library/i18n.dart +++ b/lib/school/library/i18n.dart @@ -101,6 +101,8 @@ class _Borrowing { String get history => "$ns.history".tr(); String get renew => "$ns.renew".tr(); + + String get noBorrowing => "$ns.noBorrowing".tr(); } class _History { @@ -109,4 +111,6 @@ class _History { static const ns = "${_I18n.ns}.history"; String get title => "$ns.title".tr(); + + String get noHistory => "$ns.noHistory".tr(); } diff --git a/lib/school/library/page/borrowing.dart b/lib/school/library/page/borrowing.dart index 70698696d..69b9e462c 100644 --- a/lib/school/library/page/borrowing.dart +++ b/lib/school/library/page/borrowing.dart @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; import 'package:rettulf/rettulf.dart'; import 'package:sit/design/adaptive/foundation.dart'; import 'package:sit/design/widgets/card.dart'; +import 'package:sit/design/widgets/common.dart'; import 'package:sit/l10n/extension.dart'; import 'package:sit/school/library/init.dart'; import 'package:sit/school/library/utils.dart'; @@ -78,15 +79,23 @@ class _LibraryBorrowingPageState extends State { : null, ), if (borrowed != null) - SliverList.builder( - itemCount: borrowed.length, - itemBuilder: (ctx, i) { - return BorrowedBookCard( - borrowed[i], - elevated: false, - ); - }, - ), + if (borrowed.isEmpty) + SliverFillRemaining( + child: LeavingBlank( + icon: Icons.inbox_outlined, + desc: i18n.borrowing.noBorrowing, + ), + ) + else + SliverList.builder( + itemCount: borrowed.length, + itemBuilder: (ctx, i) { + return BorrowedBookCard( + borrowed[i], + elevated: false, + ); + }, + ), ], ), ); diff --git a/lib/school/library/page/history.dart b/lib/school/library/page/history.dart index 62c744c83..f26e66383 100644 --- a/lib/school/library/page/history.dart +++ b/lib/school/library/page/history.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:rettulf/rettulf.dart'; import 'package:sit/design/adaptive/foundation.dart'; import 'package:sit/design/widgets/card.dart'; +import 'package:sit/design/widgets/common.dart'; import 'package:sit/l10n/extension.dart'; import 'package:sit/school/library/init.dart'; import 'package:sit/utils/error.dart'; @@ -67,12 +68,20 @@ class _LibraryMyBorrowingHistoryPageState extends State Date: Thu, 28 Mar 2024 12:26:28 +0800 Subject: [PATCH 10/15] [expense&electricity] i18n of last update time --- assets/l10n/en.yaml | 2 ++ assets/l10n/zh-Hans.yaml | 2 ++ assets/l10n/zh-Hant.yaml | 2 ++ lib/life/electricity/i18n.dart | 2 ++ lib/life/electricity/index.dart | 2 +- lib/life/expense_records/i18n.dart | 2 ++ lib/life/expense_records/index.dart | 2 +- 7 files changed, 12 insertions(+), 2 deletions(-) diff --git a/assets/l10n/en.yaml b/assets/l10n/en.yaml index 424b0f724..deec51c8d 100644 --- a/assets/l10n/en.yaml +++ b/assets/l10n/en.yaml @@ -357,6 +357,7 @@ electricity: refreshSuccessTip: Electricity balance refreshed successfully refreshFailedTip: Failed to refresh electricity balance searchRoom: Search Room + lastUpdateTime: "Last update: {}" eduEmail: title: Edu email action: @@ -425,6 +426,7 @@ expenseRecords: noTransactionsTip: You have no transactions refreshSuccessTip: Expense records refreshed successfully refreshFailedTip: Failed to refresh expense records + lastUpdateTime: "Last update: {}" statsMode: week: Week month: Month diff --git a/assets/l10n/zh-Hans.yaml b/assets/l10n/zh-Hans.yaml index 2bb140a9a..f436b38d6 100644 --- a/assets/l10n/zh-Hans.yaml +++ b/assets/l10n/zh-Hans.yaml @@ -354,6 +354,7 @@ electricity: refreshSuccessTip: 电费余额刷新成功 refreshFailedTip: 电费余额刷新失败 searchRoom: 搜索房间 + lastUpdateTime: "上次更新:{}" eduEmail: title: 教育邮箱 action: @@ -422,6 +423,7 @@ expenseRecords: noTransactionsTip: 你没有交易记录 refreshSuccessTip: 消费记录刷新成功 refreshFailedTip: 消费记录刷新失败 + lastUpdateTime: "上次更新:{}" statsMode: week: 周 month: 月 diff --git a/assets/l10n/zh-Hant.yaml b/assets/l10n/zh-Hant.yaml index eea5208b7..d60d82d9f 100644 --- a/assets/l10n/zh-Hant.yaml +++ b/assets/l10n/zh-Hant.yaml @@ -354,6 +354,7 @@ electricity: refreshSuccessTip: 電費餘額重新整理成功 refreshFailedTip: 電費餘額重新整理失敗 searchRoom: 搜尋房間 + lastUpdateTime: "最後更新:{}" eduEmail: title: Edu 電郵 action: @@ -422,6 +423,7 @@ expenseRecords: noTransactionsTip: 你沒有交易記錄 refreshSuccessTip: 消費記錄重新整理成功 refreshFailedTip: 消費記錄重新整理失敗 + lastUpdateTime: "最後更新:{}" statsMode: week: 周 month: 月 diff --git a/lib/life/electricity/i18n.dart b/lib/life/electricity/i18n.dart index fcf5d7a4f..7e9e96143 100644 --- a/lib/life/electricity/i18n.dart +++ b/lib/life/electricity/i18n.dart @@ -22,4 +22,6 @@ class _I18n with CommonI18nMixin { String get refreshSuccessTip => "$ns.refreshSuccessTip".tr(); String get refreshFailedTip => "$ns.refreshFailedTip".tr(); + + String lastUpdateTime(String time) => "$ns.lastUpdateTime".tr(args: [time]); } diff --git a/lib/life/electricity/index.dart b/lib/life/electricity/index.dart index e47b57410..61358e78c 100644 --- a/lib/life/electricity/index.dart +++ b/lib/life/electricity/index.dart @@ -102,7 +102,7 @@ class _ElectricityBalanceAppCardState extends State { ) : const SizedBox(), title: (roomNumber == null ? i18n.title : "${i18n.title} #105604").text(), - subtitle: lastUpdateTime != null ? "Last update: ${context.formatMdhmNum(lastUpdateTime)}".text() : null, + subtitle: lastUpdateTime != null ? i18n.lastUpdateTime(context.formatMdhmNum(lastUpdateTime)).text() : null, leftActions: [ FilledButton.icon( onPressed: () async { diff --git a/lib/life/expense_records/i18n.dart b/lib/life/expense_records/i18n.dart index abb39ae72..b03e9654d 100644 --- a/lib/life/expense_records/i18n.dart +++ b/lib/life/expense_records/i18n.dart @@ -33,6 +33,8 @@ class _I18n with CommonI18nMixin { String income(String amount) => "$ns.income".tr(args: [amount]); String outcome(String amount) => "$ns.outcome".tr(args: [amount]); + + String lastUpdateTime(String time) => "$ns.lastUpdateTime".tr(args: [time]); } class _Stats { diff --git a/lib/life/expense_records/index.dart b/lib/life/expense_records/index.dart index 7fce2ba7f..e465e52e5 100644 --- a/lib/life/expense_records/index.dart +++ b/lib/life/expense_records/index.dart @@ -95,7 +95,7 @@ class _ExpenseRecordsAppCardState extends State { ).expanded(), ].row().sized(h: 140), title: i18n.title.text(), - subtitle: lastUpdateTime != null ? "Last update: ${context.formatMdhmNum(lastUpdateTime)}".text() : null, + subtitle: lastUpdateTime != null ? i18n.lastUpdateTime(context.formatMdhmNum(lastUpdateTime)).text() : null, leftActions: [ FilledButton.icon( icon: const Icon(Icons.assignment), From 301558cbe3156994486d6f3063e5b9e4a4dfc817 Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 12:29:56 +0800 Subject: [PATCH 11/15] [update] delay --- lib/update/service/update.dart | 1 - lib/update/utils.dart | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/update/service/update.dart b/lib/update/service/update.dart index 6f2e90362..2488c76af 100644 --- a/lib/update/service/update.dart +++ b/lib/update/service/update.dart @@ -5,7 +5,6 @@ import 'package:dio/dio.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:sit/files.dart'; import 'package:sit/init.dart'; -import 'package:sit/r.dart'; import 'package:sit/session/backend.dart'; import 'package:sit/utils/error.dart'; import 'package:universal_platform/universal_platform.dart'; diff --git a/lib/update/utils.dart b/lib/update/utils.dart index 1c6f20387..be5e1cdd0 100644 --- a/lib/update/utils.dart +++ b/lib/update/utils.dart @@ -25,13 +25,13 @@ Future checkAppUpdate({ if (kIsWeb) return; try { if (UniversalPlatform.isIOS || UniversalPlatform.isMacOS) { - _checkAppUpdateFromApple( + await _checkAppUpdateFromApple( context: context, delayAtLeast: delayAtLeast, manually: manually, ); } else { - _checkAppUpdateFromOfficial( + await _checkAppUpdateFromOfficial( context: context, delayAtLeast: delayAtLeast, manually: manually, @@ -48,10 +48,7 @@ Future _checkAppUpdateFromOfficial({ required bool manually, }) async { final service = UpdateInit.service; - final (latest, _) = await ( - service.getLatestVersionFromOfficial(), - Future.delayed(delayAtLeast), - ).wait; + final latest = await service.getLatestVersionFromOfficial(); debugPrint(latest.toString()); if (kDebugMode && manually) { if (!context.mounted) return; @@ -62,6 +59,9 @@ Future _checkAppUpdateFromOfficial({ if (latest.downloadOf(R.currentVersion.platform) == null) return; // if update checking was not manually triggered, skip it. if (!manually && _getSkippedVersion() == latest.version) return; + if (!manually) { + await Future.delayed(delayAtLeast); + } if (!context.mounted) return; if (latest.version > currentVersion) { await context.show$Sheet$((ctx) => ArtifactUpdatePage(info: latest)); From cb80f73a8e616fde1147174bc2404eb9e5e6daf3 Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 12:57:19 +0800 Subject: [PATCH 12/15] more platform icons --- lib/design/widgets/entry_card.dart | 2 +- lib/design/widgets/expansion_tile.dart | 3 +-- lib/life/electricity/aggregated.dart | 2 +- lib/login/page/index.dart | 2 +- lib/me/index.dart | 2 +- lib/network/checker.dart | 5 +++-- lib/r.dart | 2 +- lib/school/class2nd/index.dart | 4 ++-- lib/school/class2nd/page/attended.dart | 2 +- lib/school/class2nd/storage/activity.dart | 3 ++- lib/school/exam_arrange/index.dart | 2 +- lib/school/exam_result/page/gpa.dart | 11 +++++++---- lib/school/exam_result/storage/result.ug.dart | 6 ++++-- lib/school/library/page/login.dart | 2 +- lib/school/library/page/search.dart | 5 +++-- lib/school/yellow_pages/widgets/contact.dart | 3 ++- lib/school/ywb/widgets/application.dart | 1 - lib/settings/dev.dart | 3 ++- lib/settings/page/credentials.dart | 9 +++++---- lib/settings/page/developer.dart | 7 ++++--- lib/settings/page/index.dart | 3 ++- lib/settings/page/life.dart | 5 +++-- lib/settings/page/proxy.dart | 19 ++++++++++--------- lib/settings/page/school.dart | 3 ++- lib/settings/qrcode/proxy.dart | 7 +++---- lib/timetable/i18n.dart | 3 +-- lib/timetable/page/editor.dart | 12 ++++++------ lib/timetable/page/ical.dart | 7 ++++--- lib/timetable/page/mine.dart | 2 +- lib/timetable/page/p13n/background.dart | 2 +- lib/timetable/page/p13n/palette.dart | 2 +- lib/timetable/page/p13n/palette_editor.dart | 2 +- lib/timetable/qrcode/palette.dart | 1 - lib/timetable/settings.dart | 3 ++- lib/widgets/modal_image_view.dart | 2 +- lib/widgets/search.dart | 3 ++- lib/widgets/webview/page.dart | 5 +++-- 37 files changed, 86 insertions(+), 71 deletions(-) diff --git a/lib/design/widgets/entry_card.dart b/lib/design/widgets/entry_card.dart index f2179a686..142fcffa3 100644 --- a/lib/design/widgets/entry_card.dart +++ b/lib/design/widgets/entry_card.dart @@ -251,7 +251,7 @@ class EntryCard extends StatelessWidget { if (selectAction != null && !selected) { final selectCallback = selectAction.action; all.add(MenuAction( - image: MenuImage.icon(CupertinoIcons.check_mark), + image: MenuImage.icon(context.icons.checkMark), title: selectAction.selectLabel, callback: selectCallback, )); diff --git a/lib/design/widgets/expansion_tile.dart b/lib/design/widgets/expansion_tile.dart index 527517ff7..70e5dc6ba 100644 --- a/lib/design/widgets/expansion_tile.dart +++ b/lib/design/widgets/expansion_tile.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:sit/design/adaptive/multiplatform.dart'; // thanks to "https://github.com/simplewidgets/rounded_expansion_tile" const _kDefaultDuration = Duration(milliseconds: 300); @@ -179,7 +178,7 @@ class AnimatedExpansionTileState extends State with Ticke // Build trailing widget based on the user input. Widget? _trailingIcon() { - final trailing = widget.trailing ?? Icon(context.icons.downArrow); + final trailing = widget.trailing ?? const Icon(Icons.keyboard_arrow_down); if (_rotateTrailing!) { return RotationTransition(turns: Tween(begin: 0.0, end: 0.5).animate(_iconController), child: trailing); } else { diff --git a/lib/life/electricity/aggregated.dart b/lib/life/electricity/aggregated.dart index f3db0a394..f800f4e81 100644 --- a/lib/life/electricity/aggregated.dart +++ b/lib/life/electricity/aggregated.dart @@ -16,7 +16,7 @@ class ElectricityAggregated { ElectricityBalanceInit.storage.lastUpdateTime = null; } - static void clearSelectedRoom(){ + static void clearSelectedRoom() { Settings.life.electricity.selectedRoom = null; ElectricityBalanceInit.storage.lastUpdateTime = null; ElectricityBalanceInit.storage.lastBalance = null; diff --git a/lib/login/page/index.dart b/lib/login/page/index.dart index f3292b25d..8ec10ea1e 100644 --- a/lib/login/page/index.dart +++ b/lib/login/page/index.dart @@ -222,7 +222,7 @@ class _LoginPageState extends State { decoration: InputDecoration( labelText: i18n.credentials.account, hintText: i18n.accountHint, - icon: const Icon(Icons.person), + icon: Icon(context.icons.person), ), ), TextFormField( diff --git a/lib/me/index.dart b/lib/me/index.dart index d4bb52232..1d29a1499 100644 --- a/lib/me/index.dart +++ b/lib/me/index.dart @@ -91,7 +91,7 @@ class _MePageState extends State { if (!mounted) return; context.showSnackBar(content: "已复制到剪贴板".text()); }, - icon: const Icon(Icons.copy), + icon: Icon(context.icons.copy), ), ].row(mas: MainAxisSize.min), onTap: () async { diff --git a/lib/network/checker.dart b/lib/network/checker.dart index 543c9fae1..4b00bde1a 100644 --- a/lib/network/checker.dart +++ b/lib/network/checker.dart @@ -6,6 +6,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/animation/animated.dart'; import 'package:sit/init.dart'; import 'package:sit/settings/settings.dart'; @@ -162,7 +163,7 @@ class _ConnectivityCheckerState extends State { strokeWidth: 14, ).sizedAll(widget.iconSize); case ConnectivityStatus.connected: - return buildIcon(ctx, Icons.check_rounded); + return buildIcon(ctx, context.icons.checkMark); case ConnectivityStatus.disconnected: return buildIcon(ctx, Icons.public_off_rounded); } @@ -239,7 +240,7 @@ class _TestConnectionTileState extends State { padding: const EdgeInsets.all(8), child: switch (testState) { ConnectivityStatus.connecting => const CircularProgressIndicator.adaptive(), - ConnectivityStatus.connected => const Icon(Icons.check, color: Colors.green), + ConnectivityStatus.connected => Icon(context.icons.checkMark, color: Colors.green), ConnectivityStatus.disconnected => Icon(Icons.public_off_rounded, color: context.$red$), _ => null, }), diff --git a/lib/r.dart b/lib/r.dart index 3c33ac10b..dea530930 100644 --- a/lib/r.dart +++ b/lib/r.dart @@ -20,7 +20,7 @@ class R { static late AppMeta currentVersion; /// For debugging iOS on other platforms. - static const debugCupertino = kDebugMode ? false : false; + static const debugCupertino = kDebugMode ? true : false; /// The default window size is small enough for any modern desktop device. static const Size defaultWindowSize = Size(500, 800); diff --git a/lib/school/class2nd/index.dart b/lib/school/class2nd/index.dart index aa1288a8b..d11b94b3c 100644 --- a/lib/school/class2nd/index.dart +++ b/lib/school/class2nd/index.dart @@ -126,7 +126,7 @@ class _Class2ndAppCardState extends State { await shareSummery(summary: summary, target: getTargetScore(), context: context); } : null, - icon: const Icon(Icons.share_outlined), + icon: Icon(context.icons.share), ), ], ); @@ -147,7 +147,7 @@ class _Class2ndAppCardState extends State { return Menu( children: [ MenuAction( - image: MenuImage.icon(CupertinoIcons.share), + image: MenuImage.icon(context.icons.share), title: i18n.share, callback: () async { await shareSummery(summary: summary, target: target, context: ctx); diff --git a/lib/school/class2nd/page/attended.dart b/lib/school/class2nd/page/attended.dart index 09bbf7277..f76692ad2 100644 --- a/lib/school/class2nd/page/attended.dart +++ b/lib/school/class2nd/page/attended.dart @@ -463,7 +463,7 @@ class AttendedActivitySearchDelegate extends SearchDelegate { @override List? buildActions(BuildContext context) { return [ - IconButton(onPressed: () => query = '', icon: const Icon(Icons.clear)), + IconButton(onPressed: () => query = '', icon: Icon(context.icons.clear)), ]; } diff --git a/lib/school/class2nd/storage/activity.dart b/lib/school/class2nd/storage/activity.dart index 823b81e63..ba33a1efd 100644 --- a/lib/school/class2nd/storage/activity.dart +++ b/lib/school/class2nd/storage/activity.dart @@ -29,7 +29,8 @@ class Class2ndActivityStorage { Class2ndActivityDetails? getActivityDetails(int id) => box.safeGet(_K.activityDetails(id)); - Future setActivityDetails(int id, Class2ndActivityDetails? details) => box.safePut(_K.activityDetails(id), details); + Future setActivityDetails(int id, Class2ndActivityDetails? details) => + box.safePut(_K.activityDetails(id), details); List? getActivities(Class2ndActivityCat type) { final idList = getActivityIdList(type); diff --git a/lib/school/exam_arrange/index.dart b/lib/school/exam_arrange/index.dart index 872cdb07b..6be3ee52a 100644 --- a/lib/school/exam_arrange/index.dart +++ b/lib/school/exam_arrange/index.dart @@ -102,7 +102,7 @@ class _ExamArrangeAppCardState extends State { }, ), MenuAction( - image: MenuImage.icon(CupertinoIcons.share), + image: MenuImage.icon(context.icons.share), title: i18n.share, callback: () async { await shareExamArrange(exam: exam, context: context); diff --git a/lib/school/exam_result/page/gpa.dart b/lib/school/exam_result/page/gpa.dart index ab6be758d..b5c8bde8d 100644 --- a/lib/school/exam_result/page/gpa.dart +++ b/lib/school/exam_result/page/gpa.dart @@ -1,7 +1,9 @@ import 'package:collection/collection.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/animation/progress.dart'; import 'package:sit/design/widgets/card.dart'; import 'package:sit/design/widgets/common.dart'; @@ -230,10 +232,10 @@ class _ExamResultGroupBySemesterState extends State { trailing: IconButton( icon: Icon( isGroupNoneSelected - ? Icons.check_box_outline_blank + ? context.icons.checkBoxBlankOutlineRounded : isGroupAllSelected - ? Icons.check_box_outlined - : Icons.indeterminate_check_box_outlined, + ? context.icons.checkBoxCheckedOutlineRounded + : context.icons.checkBoxIndeterminateOutlineRounded, ), onPressed: () { for (final item in widget.items) { @@ -288,7 +290,8 @@ class ExamResultGpaTile extends StatelessWidget { return ListTile( isThreeLine: true, selected: selected, - leading: Icon(selected ? Icons.check_box_outlined : Icons.check_box_outline_blank).padAll(8), + leading: Icon(selected ? context.icons.checkBoxCheckedOutlineRounded : context.icons.checkBoxBlankOutlineRounded) + .padAll(8), titleTextStyle: textTheme.titleMedium, title: Text(result.courseName), subtitleTextStyle: textTheme.bodyMedium, diff --git a/lib/school/exam_result/storage/result.ug.dart b/lib/school/exam_result/storage/result.ug.dart index cedd1f902..b97fe50d5 100644 --- a/lib/school/exam_result/storage/result.ug.dart +++ b/lib/school/exam_result/storage/result.ug.dart @@ -18,9 +18,11 @@ class ExamResultUgStorage { const ExamResultUgStorage(); - List? getResultList(SemesterInfo info) => (box.safeGet(_K.resultList(info)) as List?)?.cast(); + List? getResultList(SemesterInfo info) => + (box.safeGet(_K.resultList(info)) as List?)?.cast(); - Future setResultList(SemesterInfo info, List? results) => box.safePut(_K.resultList(info), results); + Future setResultList(SemesterInfo info, List? results) => + box.safePut(_K.resultList(info), results); ValueListenable listenResultList(SemesterInfo info) => box.listenable(keys: [_K.resultList(info)]); diff --git a/lib/school/library/page/login.dart b/lib/school/library/page/login.dart index 7e75b6df7..1e3e57b75 100644 --- a/lib/school/library/page/login.dart +++ b/lib/school/library/page/login.dart @@ -109,7 +109,7 @@ class _LibraryLoginPageState extends State { hintText: i18n.login.passwordHint, icon: Icon(context.icons.lock), suffixIcon: IconButton( - icon: Icon(isPasswordClear ? context.icons.eyeSolid: context.icons.eyeSlashSolid), + icon: Icon(isPasswordClear ? context.icons.eyeSolid : context.icons.eyeSlashSolid), onPressed: () { setState(() { isPasswordClear = !isPasswordClear; diff --git a/lib/school/library/page/search.dart b/lib/school/library/page/search.dart index c82c17f14..c791f29f8 100644 --- a/lib/school/library/page/search.dart +++ b/lib/school/library/page/search.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/school/library/storage/search.dart'; import 'package:sit/school/library/widgets/search.dart'; @@ -39,7 +40,7 @@ class LibrarySearchDelegate extends SearchDelegate { List? buildActions(BuildContext context) { return [ IconButton( - icon: const Icon(Icons.clear), + icon: Icon(context.icons.clear), onPressed: () { query = ''; showSuggestions(context); @@ -226,7 +227,7 @@ class _LibrarySearchHistoryGroupState extends State { title: i18n.searching.searchHistory.text(), items: history, tileTrailing: IconButton( - icon: const Icon(Icons.delete), + icon: Icon(context.icons.delete), onPressed: history?.isNotEmpty == true ? () { LibraryInit.searchStorage.setSearchHistory(null); diff --git a/lib/school/yellow_pages/widgets/contact.dart b/lib/school/yellow_pages/widgets/contact.dart index 3a1ffbd4f..ca7ab7fb3 100644 --- a/lib/school/yellow_pages/widgets/contact.dart +++ b/lib/school/yellow_pages/widgets/contact.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:sit/design/adaptive/dialog.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/school/yellow_pages/init.dart'; import 'package:sit/school/yellow_pages/storage/contact.dart'; import 'package:sit/utils/guard_launch.dart'; @@ -29,7 +30,7 @@ class ContactTile extends StatelessWidget { backgroundColor: context.colorScheme.primary, radius: 20, child: name == null || name.isEmpty || _isDigit(name[0]) - ? Center(child: Icon(Icons.account_circle, size: 40, color: context.colorScheme.onPrimary)) + ? Center(child: Icon(context.icons.accountCircle, size: 40, color: context.colorScheme.onPrimary)) : name[0] .text( style: context.textTheme.titleLarge?.copyWith(color: context.colorScheme.onPrimary), diff --git a/lib/school/ywb/widgets/application.dart b/lib/school/ywb/widgets/application.dart index 00ca34852..258a50361 100644 --- a/lib/school/ywb/widgets/application.dart +++ b/lib/school/ywb/widgets/application.dart @@ -19,7 +19,6 @@ class YwbApplicationTile extends StatelessWidget { return AnimatedExpansionTile( title: "${application.name} #${application.workId}".text(), subtitle: context.formatYmdWeekText(application.startTs).text(), - trailing: const Icon(Icons.keyboard_arrow_down), children: application.track.map((e) => YwbApplicationTrackTile(e)).toList(), ); } diff --git a/lib/settings/dev.dart b/lib/settings/dev.dart index c4ec1c125..e407872fe 100644 --- a/lib/settings/dev.dart +++ b/lib/settings/dev.dart @@ -32,7 +32,8 @@ class DevSettingsImpl { ValueListenable listenDemoMode() => box.listenable(keys: [_K.demoMode]); - List? getSavedOaCredentialsList() => (box.safeGet(_K.savedOaCredentialsList) as List?)?.cast(); + List? getSavedOaCredentialsList() => + (box.safeGet(_K.savedOaCredentialsList) as List?)?.cast(); Future setSavedOaCredentialsList(List? newV) async { newV?.distinctBy((c) => c.account); diff --git a/lib/settings/page/credentials.dart b/lib/settings/page/credentials.dart index 13ece8fe6..093cf5a7d 100644 --- a/lib/settings/page/credentials.dart +++ b/lib/settings/page/credentials.dart @@ -6,6 +6,7 @@ import 'package:sit/credentials/widgets/oa_scope.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/design/adaptive/editor.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/init.dart'; import 'package:sit/login/utils.dart'; import '../i18n.dart'; @@ -63,8 +64,8 @@ class _CredentialsPageState extends State { return ListTile( title: i18n.oaCredentials.oaAccount.text(), subtitle: credential.account.text(), - leading: const Icon(Icons.person_rounded), - trailing: const Icon(Icons.copy_rounded), + leading: Icon(context.icons.person), + trailing: Icon(context.icons.copy), onTap: () async { context.showSnackBar(content: i18n.copyTipOf(i18n.oaCredentials.oaAccount).text()); // Copy the student ID to clipboard @@ -82,7 +83,7 @@ class _CredentialsPageState extends State { leading: const Icon(Icons.password_rounded), trailing: [ IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: () async { final newPwd = await Editor.showStringEditor( context, @@ -141,7 +142,7 @@ class _TestLoginTileState extends State { padding: const EdgeInsets.all(8), child: switch (loggingState) { _TestLoginState.loggingIn => const CircularProgressIndicator.adaptive(), - _TestLoginState.success => const Icon(Icons.check, color: Colors.green), + _TestLoginState.success => Icon(context.icons.checkMark, color: Colors.green), _ => null, }, ), diff --git a/lib/settings/page/developer.dart b/lib/settings/page/developer.dart index 34f2e780d..1ffce0e92 100644 --- a/lib/settings/page/developer.dart +++ b/lib/settings/page/developer.dart @@ -5,6 +5,7 @@ import 'package:sit/credentials/entity/credential.dart'; import 'package:sit/credentials/init.dart'; import 'package:sit/credentials/utils.dart'; import 'package:sit/design/adaptive/editor.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/expansion_tile.dart'; import 'package:sit/init.dart'; import 'package:sit/login/aggregated.dart'; @@ -98,7 +99,7 @@ class _DeveloperOptionsPageState extends State { return ListTile( title: i18n.dev.reload.text(), subtitle: i18n.dev.reloadDesc.text(), - leading: const Icon(Icons.refresh_rounded), + leading: Icon(context.icons.refresh), onTap: () async { await Init.initNetwork(); await Init.initModules(); @@ -195,7 +196,7 @@ class _SwitchOaUserTileState extends State { Widget buildCredentialsHistoryTile(Credentials credentials) { final isCurrent = credentials == widget.currentCredentials; return ListTile( - leading: const Icon(Icons.account_circle), + leading: Icon(context.icons.accountCircle), title: credentials.account.text(), subtitle: isCurrent ? "Current user".text() : estimateOaUserType(credentials.account)?.l10n().text(), trailing: const Icon(Icons.login).padAll(8), @@ -208,7 +209,7 @@ class _SwitchOaUserTileState extends State { Widget buildLoginNewTile() { return ListTile( - leading: const Icon(Icons.add), + leading: Icon(context.icons.add), title: "New account".text(), onTap: () async { final credentials = await await Editor.showAnyEditor( diff --git a/lib/settings/page/index.dart b/lib/settings/page/index.dart index d61fb6235..5b4022257 100644 --- a/lib/settings/page/index.dart +++ b/lib/settings/page/index.dart @@ -6,6 +6,7 @@ import 'package:go_router/go_router.dart'; import 'package:sit/credentials/entity/login_status.dart'; import 'package:sit/credentials/widgets/oa_scope.dart'; import 'package:sit/design/adaptive/dialog.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/login/i18n.dart'; import 'package:sit/network/widgets/entry.dart'; import 'package:sit/storage/hive/init.dart'; @@ -150,7 +151,7 @@ class _SettingsPageState extends State { all.add(const WipeDataTile()); all.add(PageNavigationTile( title: i18n.about.title.text(), - leading: const Icon(Icons.info), + leading: Icon(context.icons.info), path: "/settings/about", )); all[all.length - 1] = all.last.safeArea(t: false); diff --git a/lib/settings/page/life.dart b/lib/settings/page/life.dart index e9ba268c8..c5bfcd999 100644 --- a/lib/settings/page/life.dart +++ b/lib/settings/page/life.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/settings/settings.dart'; import 'package:rettulf/rettulf.dart'; import '../i18n.dart'; @@ -41,7 +42,7 @@ class _LifeSettingsPageState extends State { builder: (ctx, setState) => ListTile( title: i18n.life.electricity.autoRefresh.text(), subtitle: i18n.life.electricity.autoRefreshDesc.text(), - leading: const Icon(Icons.refresh_outlined), + leading: Icon(context.icons.refresh), trailing: Switch.adaptive( value: Settings.life.electricity.autoRefresh, onChanged: (newV) { @@ -59,7 +60,7 @@ class _LifeSettingsPageState extends State { builder: (ctx, setState) => ListTile( title: i18n.life.expense.autoRefresh.text(), subtitle: i18n.life.expense.autoRefreshDesc.text(), - leading: const Icon(Icons.refresh_outlined), + leading: Icon(context.icons.refresh), trailing: Switch.adaptive( value: Settings.life.expense.autoRefresh, onChanged: (newV) { diff --git a/lib/settings/page/proxy.dart b/lib/settings/page/proxy.dart index c5dfa9da3..b1e07fefa 100644 --- a/lib/settings/page/proxy.dart +++ b/lib/settings/page/proxy.dart @@ -7,6 +7,7 @@ import 'package:go_router/go_router.dart'; import 'package:sit/design/adaptive/dialog.dart'; import 'package:sit/design/adaptive/editor.dart'; import 'package:sit/design/adaptive/foundation.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/list_tile.dart'; import 'package:sit/network/checker.dart'; import 'package:sit/qrcode/page/view.dart'; @@ -122,10 +123,10 @@ class ProxyShareQrCodeTile extends StatelessWidget { @override Widget build(BuildContext context) { return ListTile( - leading: const Icon(Icons.qr_code), + leading: Icon(context.icons.qrcode), title: i18n.proxy.shareQrCode.text(), subtitle: i18n.proxy.shareQrCodeDesc.text(), - trailing: const Icon(Icons.share).padAll(8), + trailing: Icon(context.icons.share), onTap: () async { final proxy = Settings.proxy; final qrCodeData = const ProxyDeepLink().encode( @@ -239,10 +240,10 @@ class _ProxyProfileEditorPageState extends State { this.uri = type.buildDefaultUri(); }); }, - icon: const Icon(Icons.delete), + icon: Icon(context.icons.delete), ), IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: () async { final newFullProxy = await Editor.showStringEditor( context, @@ -301,7 +302,7 @@ class _ProxyProfileEditorPageState extends State { title: i18n.proxy.hostname, subtitle: host, trailing: IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: () async { final newHostRaw = await Editor.showStringEditor( context, @@ -329,7 +330,7 @@ class _ProxyProfileEditorPageState extends State { title: i18n.proxy.port, subtitle: port.toString(), trailing: IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: () async { final newPort = await Editor.showIntEditor( context, @@ -365,10 +366,10 @@ class _ProxyProfileEditorPageState extends State { uri = uri.replace(userInfo: ""); }); }, - icon: const Icon(Icons.delete), + icon: Icon(context.icons.delete), ), IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: () async { final newAuth = await showAdaptiveDialog<({String username, String password})>( context: context, @@ -470,7 +471,7 @@ class _ProxyModeSwitcherTile extends StatelessWidget { trailing: Tooltip( triggerMode: TooltipTriggerMode.tap, message: buildTooltip(), - child: const Icon(Icons.info_outline), + child: Icon(context.icons.info), ).padAll(8), ); } diff --git a/lib/settings/page/school.dart b/lib/settings/page/school.dart index 86f505ed9..ec95f95ae 100644 --- a/lib/settings/page/school.dart +++ b/lib/settings/page/school.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:sit/credentials/entity/user_type.dart'; import 'package:sit/credentials/widgets/oa_scope.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/settings/settings.dart'; import 'package:rettulf/rettulf.dart'; import '../i18n.dart'; @@ -57,7 +58,7 @@ class _SchoolSettingsPageState extends State { builder: (ctx, setState) => ListTile( title: i18n.school.class2nd.autoRefresh.text(), subtitle: i18n.school.class2nd.autoRefreshDesc.text(), - leading: const Icon(Icons.refresh_outlined), + leading: Icon(context.icons.refresh), trailing: Switch.adaptive( value: Settings.school.class2nd.autoRefresh, onChanged: (newV) { diff --git a/lib/settings/qrcode/proxy.dart b/lib/settings/qrcode/proxy.dart index 846cdc533..c91eb963c 100644 --- a/lib/settings/qrcode/proxy.dart +++ b/lib/settings/qrcode/proxy.dart @@ -1,4 +1,3 @@ - import 'package:flutter/widgets.dart'; import 'package:sit/qrcode/protocol.dart'; import 'package:sit/r.dart'; @@ -32,9 +31,9 @@ class ProxyDeepLink extends DeepLinkHandlerProtocol { https = http; } return ( - http: http == null ? null : Uri.tryParse(http), - https: https == null ? null : Uri.tryParse(https), - all: all == null ? null : Uri.tryParse(all), + http: http == null ? null : Uri.tryParse(http), + https: https == null ? null : Uri.tryParse(https), + all: all == null ? null : Uri.tryParse(all), ); } diff --git a/lib/timetable/i18n.dart b/lib/timetable/i18n.dart index 7fc991733..164825c77 100644 --- a/lib/timetable/i18n.dart +++ b/lib/timetable/i18n.dart @@ -255,8 +255,7 @@ class _Editor { "from": from, "to": to, }); - String timeslotsSpanSingle(String at) => - "$ns.timeslots.single".tr(args: [at]); + String timeslotsSpanSingle(String at) => "$ns.timeslots.single".tr(args: [at]); } class _Export { diff --git a/lib/timetable/page/editor.dart b/lib/timetable/page/editor.dart index 5cb88a7e8..b8023003f 100644 --- a/lib/timetable/page/editor.dart +++ b/lib/timetable/page/editor.dart @@ -138,7 +138,7 @@ class _TimetableEditorPageState extends State { Widget addCourseTile() { return ListTile( title: i18n.editor.addCourse.text(), - trailing: const Icon(Icons.add), + trailing: Icon(context.icons.add), onTap: () async { final newCourse = await context.show$Sheet$((ctx) => SitCourseEditorPage( title: i18n.editor.newCourse, @@ -313,7 +313,7 @@ class TimetableEditableCourseCard extends StatelessWidget { title: template.courseName.text(), trailing: [ IconButton.filledTonal( - icon: const Icon(Icons.add), + icon: Icon(context.icons.add), padding: EdgeInsets.zero, onPressed: () async { final tempItem = template.createSubItem(courseKey: 0); @@ -328,7 +328,7 @@ class TimetableEditableCourseCard extends StatelessWidget { }, ), IconButton.filledTonal( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), padding: EdgeInsets.zero, onPressed: () async { final newTemplate = await context.show$Sheet$((context) => SitCourseEditorPage.template( @@ -368,7 +368,7 @@ class TimetableEditableCourseCard extends StatelessWidget { ...weekNumbers.map((n) => n.text()), ].column(mas: MainAxisSize.min, caa: CrossAxisAlignment.start), trailing: IconButton.filledTonal( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), padding: EdgeInsets.zero, onPressed: () async { final newItem = await context.show$Sheet$((context) => SitCourseEditorPage.item( @@ -608,7 +608,7 @@ class _SitCourseEditorPageState extends State { initiallyExpanded: true, rotateTrailing: false, trailing: IconButton.filledTonal( - icon: const Icon(Icons.add), + icon: Icon(context.icons.add), onPressed: () { final newIndices = List.of(weekIndices.indices); newIndices.add(const TimetableWeekIndex.all((start: 0, end: 1))); @@ -645,7 +645,7 @@ class _SitCourseEditorPageState extends State { title: i18n.course.teacher(2).text(), isThreeLine: true, trailing: IconButton( - icon: const Icon(Icons.add), + icon: Icon(context.icons.add), onPressed: () async { final newTeacher = await Editor.showStringEditor( context, diff --git a/lib/timetable/page/ical.dart b/lib/timetable/page/ical.dart index e923a678b..ea7ba4ee9 100644 --- a/lib/timetable/page/ical.dart +++ b/lib/timetable/page/ical.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_platform_widgets/flutter_platform_widgets.dart'; import 'package:go_router/go_router.dart'; import 'package:rettulf/rettulf.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/duration_picker.dart'; import '../entity/timetable.dart'; import "../i18n.dart"; @@ -117,7 +118,7 @@ class _TimetableICalConfigEditorState extends State { trailing: Tooltip( triggerMode: TooltipTriggerMode.tap, message: merged ? i18n.export.lessonModeMergedTip : i18n.export.lessonModeSeparateTip, - child: const Icon(Icons.info_outline), + child: Icon(context.icons.info), ).padAll(8), ); } @@ -177,7 +178,7 @@ class _TimetableICalConfigEditorState extends State { title: i18n.export.alarmDuration.text(), subtitle: i18n.time.minuteFormat(duration.inMinutes.toString()).text(), trailing: IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: !enabled ? null : () async { @@ -202,7 +203,7 @@ class _TimetableICalConfigEditorState extends State { title: i18n.export.alarmBeforeClassBegins.text(), subtitle: i18n.export.alarmBeforeClassBeginsDesc(duration).text(), trailing: IconButton( - icon: const Icon(Icons.edit), + icon: Icon(context.icons.edit), onPressed: !enabled ? null : () async { diff --git a/lib/timetable/page/mine.dart b/lib/timetable/page/mine.dart index ab4e97a86..3d4733320 100644 --- a/lib/timetable/page/mine.dart +++ b/lib/timetable/page/mine.dart @@ -150,7 +150,7 @@ class _MyTimetableListPageState extends State { controller: scrollController, onPressed: goImport, label: Text(isLoginGuarded(context) ? i18n.import.fromFile : i18n.import.import), - icon: const Icon(Icons.add_outlined), + icon: Icon(context.icons.add), ), ); } diff --git a/lib/timetable/page/p13n/background.dart b/lib/timetable/page/p13n/background.dart index 9b85afeca..f742c9dc0 100644 --- a/lib/timetable/page/p13n/background.dart +++ b/lib/timetable/page/p13n/background.dart @@ -158,7 +158,7 @@ class _TimetableBackgroundEditorState extends State w return [ FilledButton.icon( onPressed: pickImage, - icon: Icon(context.icons.edit), + icon: Icon(context.icons.create), label: i18n.choose.text(), ), OutlinedButton.icon( diff --git a/lib/timetable/page/p13n/palette.dart b/lib/timetable/page/p13n/palette.dart index dca37162f..cf2b7af74 100644 --- a/lib/timetable/page/p13n/palette.dart +++ b/lib/timetable/page/p13n/palette.dart @@ -86,7 +86,7 @@ class _TimetableP13nPageState extends State with SingleTicker return Scaffold( floatingActionButton: FloatingActionButton.extended( label: i18n.p13n.palette.fab.text(), - icon: const Icon(Icons.add), + icon: Icon(context.icons.add), onPressed: () async { final palette = TimetablePalette( name: i18n.p13n.palette.newPaletteName, diff --git a/lib/timetable/page/p13n/palette_editor.dart b/lib/timetable/page/p13n/palette_editor.dart index e6b9eeef1..b0169b1dd 100644 --- a/lib/timetable/page/p13n/palette_editor.dart +++ b/lib/timetable/page/p13n/palette_editor.dart @@ -137,7 +137,7 @@ class _TimetablePaletteEditorPageState extends State SliverList.list(children: [ const Divider(indent: 12, endIndent: 12), ListTile( - leading: const Icon(Icons.add), + leading: Icon(context.icons.add), title: i18n.p13n.palette.addColor.text(), onTap: () { setState(() { diff --git a/lib/timetable/qrcode/palette.dart b/lib/timetable/qrcode/palette.dart index 9470ec8a3..9d5f1119b 100644 --- a/lib/timetable/qrcode/palette.dart +++ b/lib/timetable/qrcode/palette.dart @@ -1,4 +1,3 @@ - import 'package:flutter/widgets.dart'; import 'package:sit/qrcode/protocol.dart'; import 'package:sit/r.dart'; diff --git a/lib/timetable/settings.dart b/lib/timetable/settings.dart index 1ac89e922..eb84e4042 100644 --- a/lib/timetable/settings.dart +++ b/lib/timetable/settings.dart @@ -26,7 +26,8 @@ class TimetableSettings { set autoUseImported(bool newV) => box.safePut(_K.autoUseImported, newV); - CourseCellStyle? get cellStyle => decodeJsonObject(box.safeGet(_K.cellStyle), (obj) => CourseCellStyle.fromJson(obj)); + CourseCellStyle? get cellStyle => + decodeJsonObject(box.safeGet(_K.cellStyle), (obj) => CourseCellStyle.fromJson(obj)); set cellStyle(CourseCellStyle? newV) => box.safePut(_K.cellStyle, encodeJsonObject(newV, (obj) => obj.toJson())); diff --git a/lib/widgets/modal_image_view.dart b/lib/widgets/modal_image_view.dart index 793ca8054..b2d1144cb 100644 --- a/lib/widgets/modal_image_view.dart +++ b/lib/widgets/modal_image_view.dart @@ -61,7 +61,7 @@ class FullScreenViewer extends StatelessWidget { children: [ Positioned.fill( child: GestureDetector( - onDoubleTap: (){ + onDoubleTap: () { Navigator.of(context).pop(); }, child: InteractiveViewer( diff --git a/lib/widgets/search.dart b/lib/widgets/search.dart index fdb58ab17..7d78686e9 100644 --- a/lib/widgets/search.dart +++ b/lib/widgets/search.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/design/widgets/common.dart'; import 'package:rettulf/rettulf.dart'; @@ -133,7 +134,7 @@ class ItemSearchDelegate extends SearchDelegate { List? buildActions(BuildContext context) { return [ IconButton( - icon: const Icon(Icons.clear), + icon: Icon(context.icons.clear), onPressed: () => query = "", ) ]; diff --git a/lib/widgets/webview/page.dart b/lib/widgets/webview/page.dart index ccd7940ef..14295b83c 100644 --- a/lib/widgets/webview/page.dart +++ b/lib/widgets/webview/page.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:sit/design/adaptive/multiplatform.dart'; import 'package:sit/l10n/common.dart'; import 'package:sit/utils/error.dart'; import 'package:sit/widgets/webview/injectable.dart'; @@ -125,12 +126,12 @@ class _WebViewPageState extends State { if (widget.showRefreshButton) IconButton( onPressed: _onRefresh, - icon: const Icon(Icons.refresh), + icon: Icon(context.icons.refresh), ), if (widget.showSharedButton) IconButton( onPressed: _onShared, - icon: const Icon(Icons.share), + icon: Icon(context.icons.share), ), if (widget.showOpenInBrowser) IconButton( From e2f9beadb46167a8e180d8474b3bd7aa14f723bb Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 12:59:34 +0800 Subject: [PATCH 13/15] resort TODO --- lib/school/exam_arrange/service/exam.demo.dart | 1 - lib/school/ywb/service/application.demo.dart | 1 - lib/timetable/page/import.dart | 1 + lib/timetable/service/school.demo.dart | 1 - 4 files changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/school/exam_arrange/service/exam.demo.dart b/lib/school/exam_arrange/service/exam.demo.dart index b48a724f5..385cce9d5 100644 --- a/lib/school/exam_arrange/service/exam.demo.dart +++ b/lib/school/exam_arrange/service/exam.demo.dart @@ -8,7 +8,6 @@ class DemoExamArrangeService implements ExamArrangeService { @override Future> fetchExamList(SemesterInfo info) async { - // TODO: l10n final now = DateTime.now(); return [ ExamEntry( diff --git a/lib/school/ywb/service/application.demo.dart b/lib/school/ywb/service/application.demo.dart index f54c4d5f3..d2d55bd50 100644 --- a/lib/school/ywb/service/application.demo.dart +++ b/lib/school/ywb/service/application.demo.dart @@ -10,7 +10,6 @@ class DemoYwbApplicationService implements YwbApplicationService { void Function(double progress)? onProgress, }) async { onProgress?.call(1); - // TODO: l10n final now = DateTime.now(); return [ YwbApplication( diff --git a/lib/timetable/page/import.dart b/lib/timetable/page/import.dart index 539ac6d79..075c4560a 100644 --- a/lib/timetable/page/import.dart +++ b/lib/timetable/page/import.dart @@ -80,6 +80,7 @@ class _ImportTimetablePageState extends State { debugPrint(err.toString()); debugPrintStack(stackTrace: stackTrace); if (!mounted) return; + // TODO: i18n context.showSnackBar(content: "Format Error. Please select a timetable file.".text()); } } diff --git a/lib/timetable/service/school.demo.dart b/lib/timetable/service/school.demo.dart index 49f675df6..2a3c3baac 100644 --- a/lib/timetable/service/school.demo.dart +++ b/lib/timetable/service/school.demo.dart @@ -14,7 +14,6 @@ class DemoTimetableService implements TimetableService { @override Future fetchUgTimetable(SemesterInfo info) async { var key = 0; - // TODO: l10n return SitTimetable( courses: { "$key": SitCourse( From a75fe17dd990b802d207e361075270605503413e Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 16:25:17 +0800 Subject: [PATCH 14/15] request before adding from QR code --- assets/l10n/en.yaml | 6 ++-- assets/l10n/zh-Hans.yaml | 12 ++++--- assets/l10n/zh-Hant.yaml | 8 +++-- lib/design/adaptive/dialog.dart | 32 +++++++++++++++--- lib/network/checker.dart | 14 ++++---- lib/r.dart | 2 +- lib/settings/i18n.dart | 4 ++- lib/settings/page/proxy.dart | 49 +++++++++++++++++++++------- lib/timetable/i18n.dart | 9 ++--- lib/timetable/page/p13n/palette.dart | 7 +++- 10 files changed, 103 insertions(+), 40 deletions(-) diff --git a/assets/l10n/en.yaml b/assets/l10n/en.yaml index deec51c8d..0db955cab 100644 --- a/assets/l10n/en.yaml +++ b/assets/l10n/en.yaml @@ -131,8 +131,9 @@ timetable: newPaletteName: New palette deleteRequest: Conform to delete? deleteRequestDesc: The palette will be deleted permanently without unless a QR code backup is saved - addFromQrCode: Palette was added from QR code addColor: Add a color + addFromQrCodeAction: Add palette + addFromQrCodeDesc: Confirm to add a timetable palette from QR code? cellStyle: title: Cell Style showTeachers: @@ -636,7 +637,8 @@ settings: username: Username password: Password invalidProxyFormatTip: Invalid proxy format - proxyChangedTip: Proxy was changed + setFromQrCodeAction: Set proxy + setFromQrCodeDesc: Confirm to set proxy from QR code? shareQrCode: title: Share QR code desc: Share proxy as QR code diff --git a/assets/l10n/zh-Hans.yaml b/assets/l10n/zh-Hans.yaml index f436b38d6..cdf9cbbb5 100644 --- a/assets/l10n/zh-Hans.yaml +++ b/assets/l10n/zh-Hans.yaml @@ -13,7 +13,7 @@ timetable: mine: title: 你的课程表 exportCalendar: 导出日历 - deleteRequest: 确认删除? + deleteRequest: 确定删除? deleteRequestDesc: 这个课程表将被永久删除 emptyTip: 快去导入一个课程表吧! details: 详情 @@ -129,10 +129,11 @@ timetable: fab: 配色方案 shareQrCode: 分享二维码 newPaletteName: 新的配色方案 - deleteRequest: 确认删除? + deleteRequest: 确定删除? deleteRequestDesc: 推荐先保存二维码备份再删除 - addFromQrCode: 已从二维码添加配色方案 addColor: 添加一种配色 + addFromQrCodeAction: 添加配色方案 + addFromQrCodeDesc: 确定从读取的二维码中添加配色方案? cellStyle: title: 单元格风格 showTeachers: @@ -227,7 +228,7 @@ class2nd: btn: 申请 replyTip: 校方回复 applyRequest: 申请 - applyRequestDesc: 确认申请这个活动吗? + applyRequestDesc: 确定申请这个活动吗? applySuccessTip: 申请活动成功 applyFailureTip: 申请活动失败 info: @@ -636,7 +637,8 @@ settings: username: 用户名 password: 密码 invalidProxyFormatTip: 代理的格式无效 - proxyChangedTip: 代理已更改 + setFromQrCodeAction: 设置代理 + setFromQrCodeDesc: 确定从读取的二维码中设置代理? shareQrCode: title: 分享二维码 desc: 将代理通过二维码分享 diff --git a/assets/l10n/zh-Hant.yaml b/assets/l10n/zh-Hant.yaml index d60d82d9f..6d5aa0ed2 100644 --- a/assets/l10n/zh-Hant.yaml +++ b/assets/l10n/zh-Hant.yaml @@ -132,8 +132,9 @@ timetable: newPaletteName: 新的調色盤 deleteRequest: 確認刪除? deleteRequestDesc: 除非儲存了 QR 碼備份,否則調色板將被永久刪除 - addFromQrCode: 已從 QR 碼加載調色盤 addColor: 增加一對顏色 + addFromQrCodeAction: 新增調色盤 + addFromQrCodeDesc: 確認從 QR 碼中新增調色盤? cellStyle: title: 單元樣式 showTeachers: @@ -627,7 +628,7 @@ settings: themeMode: title: 亮度 proxy: - title: 代理 + title: 網路代理 desc: 代理校園網路連線 authentication: 驗證 protocol: 通訊協定 @@ -636,7 +637,8 @@ settings: username: 使用者名稱 password: 密碼 invalidProxyFormatTip: 無效的代理格式 - proxyChangedTip: 網路代理已變更 + setFromQrCodeAction: 設定代理 + setFromQrCodeDesc: 確認從 QR 碼中設定代理? shareQrCode: title: 分享 QR 碼 desc: 使用 QR 碼分享代理 diff --git a/lib/design/adaptive/dialog.dart b/lib/design/adaptive/dialog.dart index 0de909d6f..058a1ad2c 100644 --- a/lib/design/adaptive/dialog.dart +++ b/lib/design/adaptive/dialog.dart @@ -53,7 +53,7 @@ extension DialogEx on BuildContext { } Future showRequest({ - required String title, + String? title, required String desc, required String yes, required String no, @@ -78,8 +78,32 @@ extension DialogEx on BuildContext { ); } + Future showActionRequest({ + required String desc, + required String action, + required String cancel, + bool destructive = false, + }) async { + if (isCupertino) { + return showCupertinoRequest( + desc: desc, + yes: action, + cancel: cancel, + destructive: destructive, + ); + } + return await showAnyRequest( + title: action, + make: (_) => desc.text(style: const TextStyle()), + yes: action, + no: cancel, + highlight: destructive, + serious: destructive, + ); + } + Future showCupertinoRequest({ - required String title, + String? title, required String desc, required String yes, required String cancel, @@ -88,7 +112,7 @@ extension DialogEx on BuildContext { return await showCupertinoModalPopup( context: this, builder: (ctx) => CupertinoActionSheet( - title: title.text(), + title: title?.text(), message: desc.text(), actions: [ CupertinoActionSheetAction( @@ -110,7 +134,7 @@ extension DialogEx on BuildContext { } Future showAnyRequest({ - required String title, + String? title, required WidgetBuilder make, required String yes, required String no, diff --git a/lib/network/checker.dart b/lib/network/checker.dart index 4b00bde1a..2aef21db9 100644 --- a/lib/network/checker.dart +++ b/lib/network/checker.dart @@ -236,14 +236,12 @@ class _TestConnectionTileState extends State { leading: const Icon(Icons.network_check), title: _i18n.testConnection.text(), subtitle: _i18n.testConnectionDesc.text(), - trailing: Padding( - padding: const EdgeInsets.all(8), - child: switch (testState) { - ConnectivityStatus.connecting => const CircularProgressIndicator.adaptive(), - ConnectivityStatus.connected => Icon(context.icons.checkMark, color: Colors.green), - ConnectivityStatus.disconnected => Icon(Icons.public_off_rounded, color: context.$red$), - _ => null, - }), + trailing: switch(testState) { + ConnectivityStatus.connecting => const CircularProgressIndicator.adaptive(), + ConnectivityStatus.connected => Icon(context.icons.checkMark, color: Colors.green), + ConnectivityStatus.disconnected => Icon(Icons.public_off_rounded, color: context.$red$), + _ => null, + }, onTap: () async { setState(() { testState = ConnectivityStatus.connecting; diff --git a/lib/r.dart b/lib/r.dart index dea530930..3c33ac10b 100644 --- a/lib/r.dart +++ b/lib/r.dart @@ -20,7 +20,7 @@ class R { static late AppMeta currentVersion; /// For debugging iOS on other platforms. - static const debugCupertino = kDebugMode ? true : false; + static const debugCupertino = kDebugMode ? false : false; /// The default window size is small enough for any modern desktop device. static const Size defaultWindowSize = Size(500, 800); diff --git a/lib/settings/i18n.dart b/lib/settings/i18n.dart index 9123b3d42..3fbd895bd 100644 --- a/lib/settings/i18n.dart +++ b/lib/settings/i18n.dart @@ -75,7 +75,9 @@ class _Proxy { String get invalidProxyFormatTip => "$ns.invalidProxyFormatTip".tr(); - String get proxyChangedTip => "$ns.proxyChangedTip".tr(); + String get setFromQrCodeAction => "$ns.setFromQrCodeAction".tr(); + + String get setFromQrCodeDesc => "$ns.setFromQrCodeDesc".tr(); } class _Timetable { diff --git a/lib/settings/page/proxy.dart b/lib/settings/page/proxy.dart index b1e07fefa..4d47cad80 100644 --- a/lib/settings/page/proxy.dart +++ b/lib/settings/page/proxy.dart @@ -115,6 +115,20 @@ class _ProxySettingsPageState extends State { } } +Uri? _validateProxyUri(String uriString) { + final uri = Uri.tryParse(uriString); + if (uri == null || !uri.isAbsolute) { + return null; + } + return uri; +} + +Uri? _validateProxyUriForType(String uriString, ProxyType type) { + final uri = _validateProxyUri(uriString); + if (uri == null) return null; + return !type.supportedProtocols.contains(uri.scheme) ? null : uri; +} + class ProxyShareQrCodeTile extends StatelessWidget { const ProxyShareQrCodeTile({ super.key, @@ -151,18 +165,30 @@ Future onProxyFromQrCode({ required Uri? https, required Uri? all, }) async { - if (http != null) { - Settings.proxy.resolve(ProxyType.http).address = http.toString(); - } - if (https != null) { - Settings.proxy.resolve(ProxyType.https).address = https.toString(); + final confirm = await context.showActionRequest( + desc: i18n.proxy.setFromQrCodeDesc, + action: i18n.proxy.setFromQrCodeAction, + cancel: i18n.cancel, + ); + if (confirm != true) return; + bool isValid(Uri? uri, ProxyType type) { + return uri == null ? true : _validateProxyUriForType(uri.toString(), type) != null; } - if (http != null) { - Settings.proxy.resolve(ProxyType.all).address = all.toString(); + var valid = isValid(http, ProxyType.http) && isValid(https, ProxyType.https) && isValid(all, ProxyType.all); + if (!valid) { + if (!context.mounted) return; + context.showTip( + title: i18n.error, + desc: i18n.proxy.invalidProxyFormatTip, + ok: i18n.close, + ); + return; } + if (http != null) Settings.proxy.resolve(ProxyType.http).address = http.toString(); + if (https != null) Settings.proxy.resolve(ProxyType.https).address = https.toString(); + if (all != null) Settings.proxy.resolve(ProxyType.all).address = all.toString(); await HapticFeedback.mediumImpact(); if (!context.mounted) return; - context.showSnackBar(content: i18n.proxy.proxyChangedTip.text()); context.push("/settings/proxy"); } @@ -245,14 +271,15 @@ class _ProxyProfileEditorPageState extends State { IconButton( icon: Icon(context.icons.edit), onPressed: () async { - final newFullProxy = await Editor.showStringEditor( + var newFullProxy = await Editor.showStringEditor( context, desc: i18n.proxy.title, initial: uri.toString(), ); if (newFullProxy == null) return; - final newUri = Uri.tryParse(newFullProxy.trim()); - if (newUri == null || !newUri.isAbsolute || !type.supportedProtocols.contains(newUri.scheme)) { + newFullProxy = newFullProxy.trim(); + final newUri = _validateProxyUriForType(newFullProxy, type); + if (newUri == null) { if (!mounted) return; context.showTip( title: i18n.error, diff --git a/lib/timetable/i18n.dart b/lib/timetable/i18n.dart index 164825c77..f3ddd51da 100644 --- a/lib/timetable/i18n.dart +++ b/lib/timetable/i18n.dart @@ -124,14 +124,10 @@ class _Palette { String get newPaletteName => "$ns.newPaletteName".tr(); - String copyPaletteName(String old) => "$ns.copyPaletteName".tr(args: [old]); - String get deleteRequest => "$ns.deleteRequest".tr(); String get deleteRequestDesc => "$ns.deleteRequestDesc".tr(); - String get addFromQrCode => "$ns.addFromQrCode".tr(); - String get addColor => "$ns.addColor".tr(); String get name => "$ns.name".tr(); @@ -145,6 +141,10 @@ class _Palette { String get color => "$ns.color".tr(); String get details => "$ns.details".tr(); + + String get addFromQrCodeAction => "$ns.addFromQrCodeAction".tr(); + + String get addFromQrCodeDesc => "$ns.addFromQrCodeDesc".tr(); } class _Background { @@ -255,6 +255,7 @@ class _Editor { "from": from, "to": to, }); + String timeslotsSpanSingle(String at) => "$ns.timeslots.single".tr(args: [at]); } diff --git a/lib/timetable/page/p13n/palette.dart b/lib/timetable/page/p13n/palette.dart index cf2b7af74..15c6fd33b 100644 --- a/lib/timetable/page/p13n/palette.dart +++ b/lib/timetable/page/p13n/palette.dart @@ -553,9 +553,14 @@ Future onTimetablePaletteFromQrCode({ required BuildContext context, required TimetablePalette palette, }) async { + final confirm = await context.showActionRequest( + desc: i18n.p13n.palette.addFromQrCodeDesc, + action: i18n.p13n.palette.addFromQrCodeAction, + cancel: i18n.cancel, + ); + if (confirm != true) return; TimetableInit.storage.palette.add(palette); await HapticFeedback.mediumImpact(); if (!context.mounted) return; - context.showSnackBar(content: i18n.p13n.palette.addFromQrCode.text()); context.push("/timetable/p13n/custom"); } From 3d537aad2eca402ac72f0c69ec1065e0bfe5f54c Mon Sep 17 00:00:00 2001 From: Liplum Date: Thu, 28 Mar 2024 16:27:04 +0800 Subject: [PATCH 15/15] bump some packages to the latest --- pubspec.lock | 12 ++++++------ pubspec.yaml | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index dc3d7a605..24287c11a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -413,10 +413,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "50fec96118958b97c727d0d8f67255d3683f16cc1f90d9bc917b5d4fe3abeca9" + sha256: "0978e9a3e45305a80a7210dbeaf79d6ee8bee33f70c8e542dc654c952070217f" url: "https://pub.dev" source: hosted - version: "5.4.2" + version: "5.4.2+1" dio_cookie_manager: dependency: "direct main" description: @@ -1457,10 +1457,10 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "74e962b7fad7ff75959161bb2c0ad8fe7f2568ee82621c9c2660b751146bfe44" + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" url: "https://pub.dev" source: hosted - version: "11.3.0" + version: "11.3.1" permission_handler_android: dependency: transitive description: @@ -1473,10 +1473,10 @@ packages: dependency: transitive description: name: permission_handler_apple - sha256: "92861b0f0c2443dd8898398c2baa4f1ae925109b5909ae4a17d0108a6a788932" + sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662 url: "https://pub.dev" source: hosted - version: "9.4.2" + version: "9.4.4" permission_handler_html: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index bcfe02a13..b97eb8784 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -59,7 +59,7 @@ dependencies: html: ^0.15.4 # Dio (http client) - dio: ^5.4.2 + dio: ^5.4.2+1 dio_cookie_manager: ^3.1.1 # WebView and browser related @@ -76,7 +76,7 @@ dependencies: # Platform # Android / iOS / Windows Permission - permission_handler: ^11.3.0 + permission_handler: ^11.3.1 # Android / iOS Home screen quick actions quick_actions: ^1.0.7 # Deep links on Android and custom scheme links on iOS