From e155f69e8751a6349c25fad0c764536fffa26e18 Mon Sep 17 00:00:00 2001 From: ZhuJHua <1624109111@qq.com> Date: Sun, 5 Jan 2025 23:58:53 +0800 Subject: [PATCH 1/3] refactor(ui): improve ui --- android/app/src/main/AndroidManifest.xml | 2 +- .../app/src/main/res/values-en/appname.xml | 4 - .../app/src/main/res/values-zh/appname.xml | 4 - android/app/src/main/res/values/appname.xml | 4 - ios/Podfile.lock | 72 ++-- ios/Runner.xcodeproj/project.pbxproj | 44 ++- ios/Runner/Info.plist | 4 +- lib/components/dashboard/dashboard_view.dart | 19 +- .../input_dialog/input_dialog_logic.dart | 5 + .../input_dialog/input_dialog_view.dart | 15 + .../calendar_diary_card_view.dart | 71 ++-- .../large_diary_card_view.dart | 105 ++++-- .../small_diary_card_view.dart | 24 +- lib/components/media/media_audio_view.dart | 3 +- lib/components/media/media_image_view.dart | 3 +- lib/components/media/media_video_view.dart | 3 +- lib/components/time_line/time_line_view.dart | 2 +- lib/l10n/intl_en.arb | 1 + lib/l10n/intl_zh.arb | 1 + lib/pages/about/about_logic.dart | 19 +- lib/pages/about/about_state.dart | 2 + lib/pages/about/about_view.dart | 229 ++++++++---- lib/pages/analyse/analyse_view.dart | 2 +- lib/pages/backup_sync/backup_sync_view.dart | 4 +- .../diary_details/diary_details_view.dart | 3 +- lib/pages/edit/edit_logic.dart | 26 +- lib/pages/edit/edit_view.dart | 181 +++++----- lib/pages/font/font_logic.dart | 14 +- lib/pages/font/font_view.dart | 7 + lib/pages/home/calendar/calendar_logic.dart | 33 +- lib/pages/home/calendar/calendar_state.dart | 4 + lib/pages/home/calendar/calendar_view.dart | 239 ++++++++---- lib/pages/home/diary/diary_view.dart | 12 +- lib/pages/home/home_logic.dart | 8 + lib/pages/home/media/media_view.dart | 5 +- lib/pages/home/setting/setting_logic.dart | 25 +- lib/pages/home/setting/setting_view.dart | 122 +++---- lib/pages/lock/lock_view.dart | 114 +++--- lib/pages/sponsor/sponsor_logic.dart | 7 + lib/pages/sponsor/sponsor_view.dart | 41 +++ lib/router/app_pages.dart | 15 +- lib/router/app_routes.dart | 3 + lib/src/rust/api/compress.dart | 3 +- lib/src/rust/api/constants.dart | 3 +- lib/src/rust/api/font.dart | 8 +- lib/src/rust/api/kmp.dart | 3 +- lib/src/rust/frb_generated.dart | 151 +++++++- lib/src/rust/frb_generated.io.dart | 50 ++- lib/src/rust/frb_generated.web.dart | 48 ++- lib/utils/data/isar.dart | 5 + lib/utils/http_util.dart | 2 +- lib/utils/package_util.dart | 17 + lib/utils/theme_util.dart | 339 +++++++++--------- macos/Flutter/GeneratedPluginRegistrant.swift | 6 + macos/Podfile.lock | 18 + macos/Runner.xcodeproj/project.pbxproj | 19 +- .../xcshareddata/xcschemes/Runner.xcscheme | 8 +- macos/Runner/Configs/AppInfo.xcconfig | 4 +- pubspec.lock | 96 +++-- pubspec.yaml | 13 +- rust/Cargo.lock | 5 +- rust/Cargo.toml | 2 +- rust/src/api/font.rs | 64 +++- rust/src/frb_generated.rs | 126 ++++++- windows/runner/Runner.rc | 10 +- windows/runner/main.cpp | 2 +- 66 files changed, 1657 insertions(+), 846 deletions(-) delete mode 100644 android/app/src/main/res/values-en/appname.xml delete mode 100644 android/app/src/main/res/values-zh/appname.xml delete mode 100644 android/app/src/main/res/values/appname.xml create mode 100644 lib/components/dialog/input_dialog/input_dialog_logic.dart create mode 100644 lib/components/dialog/input_dialog/input_dialog_view.dart create mode 100644 lib/pages/sponsor/sponsor_logic.dart create mode 100644 lib/pages/sponsor/sponsor_view.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index fab73b1..cea58c0 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -34,7 +34,7 @@ - - Moodiary - \ No newline at end of file diff --git a/android/app/src/main/res/values-zh/appname.xml b/android/app/src/main/res/values-zh/appname.xml deleted file mode 100644 index 983a7d0..0000000 --- a/android/app/src/main/res/values-zh/appname.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 心绪日记 - \ No newline at end of file diff --git a/android/app/src/main/res/values/appname.xml b/android/app/src/main/res/values/appname.xml deleted file mode 100644 index 983a7d0..0000000 --- a/android/app/src/main/res/values/appname.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - 心绪日记 - \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 91788ab..852c9b0 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -292,54 +292,54 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/wakelock_plus/ios" SPEC CHECKSUMS: - app_links: e7a6750a915a9e161c58d91bc610e8cd1d4d0ad0 - audioplayers_darwin: 877d9a4d06331c5c374595e46e16453ac7eafa40 - connectivity_plus: 18382e7311ba19efcaee94442b23b32507b20695 - device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342 + app_links: 3da4c36b46cac3bf24eb897f1a6ce80bda109874 + audioplayers_darwin: ccf9c770ee768abb07e26d90af093f7bab1c12ab + connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee + device_info_plus: 21fcca2080fbcd348be798aa36c3e5ed849eefbe DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - fc_native_video_thumbnail: 927d4dcfd4c7e9f2cc1a20bb52dfee83de3792c2 - file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655 + fc_native_video_thumbnail: b511cec81fad66be9b28dd54b9adb39d40fcd6cc + file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 - flutter_image_compress_common: ec1d45c362c9d30a3f6a0426c297f47c52007e3e - flutter_keyboard_visibility_temp_fork: 8a8809c4129e31d25fca77446e0f3fd548122ced - flutter_native_splash: e8a1e01082d97a8099d973f919f57904c925008a - fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c - gal: 6a522c75909f1244732d4596d11d6a2f86ff37a5 - geolocator_apple: 9bcea1918ff7f0062d98345d238ae12718acfbc1 - image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1 - isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 + flutter_image_compress_common: 1697a328fd72bfb335507c6bca1a65fa5ad87df1 + flutter_keyboard_visibility_temp_fork: 95b2d534bacf6ac62e7fcbe5c2a9e2c2a17ce06f + flutter_native_splash: 6cad9122ea0fad137d23137dd14b937f3e90b145 + fluttertoast: 76fea30fcf04176325f6864c87306927bd7d2038 + gal: baecd024ebfd13c441269ca7404792a7152fde89 + geolocator_apple: 1560c3c875af2a412242c7a923e15d0d401966ff + image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a + isar_flutter_libs: 9fc2cfb928c539e1b76c481ba5d143d556d94920 libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 - local_auth_darwin: 66e40372f1c29f383a314c738c7446e2f7fdadc3 + local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391 Mantle: c5aa8794a29a022dfbbfc9799af95f477a69b62d - media_kit_libs_ios_video: a5fe24bc7875ccd6378a0978c13185e1344651c1 - media_kit_native_event_loop: e6b2ab20cf0746eb1c33be961fcf79667304fa2a - media_kit_video: 5da63f157170e5bf303bf85453b7ef6971218a2e - network_info_plus: 6613d9d7cdeb0e6f366ed4dbe4b3c51c52d567a9 + media_kit_libs_ios_video: 5a18affdb97d1f5d466dc79988b13eff6c5e2854 + media_kit_native_event_loop: 5fba1a849a6c87a34985f1e178a0de5bd444a0cf + media_kit_video: 1746e198cb697d1ffb734b1d05ec429d1fcd1474 + network_info_plus: cf61925ab5205dce05a4f0895989afdb6aade5fc ObjectBox: 0bc4bb75eea85f6af06b369148b334c2056bbc29 - objectbox_flutter_libs: 2ce0da386c780878687c736b528ceaf371573efb - package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 - path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 - permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - quill_native_bridge_ios: 2b01d585fcc73d0f5eed78c0bd244ee564b06f5a - record_darwin: 3b1a8e7d5c0cbf45ad6165b4d83a6ca643d929c3 - rive_common: 4743dbfd2911c99066547a3c6454681e0fa907df - rust_lib_mood_diary: 38a92354760d3409ebc859f812193e7c69e184ef - screen_brightness_ios: 715ca807df953bf676d339f11464e438143ee625 + objectbox_flutter_libs: 3af037f7cc35e687acca01f1f6da6cb6c2abc22b + package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 + path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564 + permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d + quill_native_bridge_ios: f47af4b14e7757968486641656c5d23250cee521 + record_darwin: fb1f375f1d9603714f55b8708a903bbb91ffdb0a + rive_common: dd421daaf9ae69f0125aa761dd96abd278399952 + rust_lib_mood_diary: ea9f784d50426d5994e53cecee71cd23d965542a + screen_brightness_ios: 5ed898fa50fa82a26171c086ca5e28228f932576 SDWebImage: 8a6b7b160b4d710e2a22b6900e25301075c34cb3 SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 - share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f - shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 - sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d + share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a + shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 + sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 TensorFlowLiteC: 20785a69299185a379ba9852b6625f00afd7984a TensorFlowLiteSwift: 3a4928286e9e35bdd3e17970f48e53c80d25e793 - tflite_flutter: 9433d086a3060431bbc9f3c7c20d017db0e72d08 + tflite_flutter: 64b192e11352fe36943ab6656e1d49207f1a5595 Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e - url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe - video_player_avfoundation: 7c6c11d8470e1675df7397027218274b6d2360b3 - volume_controller: 531ddf792994285c9b17f9d8a7e4dcdd29b3eae9 - wakelock_plus: 78ec7c5b202cab7761af8e2b2b3d0671be6c4ae1 + url_launcher_ios: 694010445543906933d732453a59da0a173ae33d + video_player_avfoundation: 2cef49524dd1f16c5300b9cd6efd9611ce03639b + volume_controller: ca1cde542ee70fad77d388f82e9616488110942b + wakelock_plus: 04623e3f525556020ebd4034310f20fe7fda8b49 PODFILE CHECKSUM: 9752b5340b4d3f9618318fcd530d907790e2a9f5 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 11bd5b3..df05cf0 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -489,9 +489,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 3XA29H789G; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; @@ -500,9 +502,10 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-ios-dev"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; @@ -514,13 +517,14 @@ baseConfigurationReference = D73569CF22DB2A16EAE0220D /* Pods-RunnerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 3XA29H789G; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -533,13 +537,14 @@ baseConfigurationReference = E7AEAE59248BEA6C8378B114 /* Pods-RunnerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 3XA29H789G; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; @@ -550,13 +555,14 @@ baseConfigurationReference = E231F0C855BB3DD103DA44E9 /* Pods-RunnerTests.profile.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = 3XA29H789G; + DEVELOPMENT_TEAM = ""; GENERATE_INFOPLIST_FILE = YES; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary.RunnerTests; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; }; @@ -682,9 +688,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 3XA29H789G; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 3XA29H789G; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; @@ -693,9 +701,10 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-ios-dev"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -710,9 +719,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - DEVELOPMENT_TEAM = 3XA29H789G; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 3XA29H789G; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; @@ -721,9 +732,10 @@ "$(inherited)", "@executable_path/Frameworks", ); - PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "moodiary-ios-dev"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_VERSION = 5.0; VERSIONING_SYSTEM = "apple-generic"; diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 6f01274..7ee228c 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -7,7 +7,7 @@ CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - 心绪日记 + Moodiary CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -15,7 +15,7 @@ CFBundleInfoDictionaryVersion 6.0 CFBundleName - 心绪日记 + Moodiary CFBundlePackageType APPL CFBundleShortVersionString diff --git a/lib/components/dashboard/dashboard_view.dart b/lib/components/dashboard/dashboard_view.dart index 522e687..a408757 100644 --- a/lib/components/dashboard/dashboard_view.dart +++ b/lib/components/dashboard/dashboard_view.dart @@ -133,10 +133,21 @@ class DashboardComponent extends StatelessWidget { style: textStyle.labelMedium! .copyWith(color: colorScheme.onSurface.withAlpha(220)), ), - Text( - count.isEmpty ? '...' : count, - style: textStyle.titleMedium, - ) + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: count.isEmpty + ? Text( + '...', + key: const ValueKey('count_empty'), + style: textStyle.titleMedium + ?.copyWith(color: colorScheme.secondary), + ) + : Text( + count, + key: const ValueKey('count'), + style: textStyle.titleMedium + ?.copyWith(color: colorScheme.secondary), + )), ], ); } diff --git a/lib/components/dialog/input_dialog/input_dialog_logic.dart b/lib/components/dialog/input_dialog/input_dialog_logic.dart new file mode 100644 index 0000000..ea0f4c4 --- /dev/null +++ b/lib/components/dialog/input_dialog/input_dialog_logic.dart @@ -0,0 +1,5 @@ +import 'package:get/get.dart'; + +class InputDialogLogic extends GetxController { + +} diff --git a/lib/components/dialog/input_dialog/input_dialog_view.dart b/lib/components/dialog/input_dialog/input_dialog_view.dart new file mode 100644 index 0000000..25fe51f --- /dev/null +++ b/lib/components/dialog/input_dialog/input_dialog_view.dart @@ -0,0 +1,15 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'input_dialog_logic.dart'; + +class InputDialogComponent extends StatelessWidget { + const InputDialogComponent({super.key}); + + @override + Widget build(BuildContext context) { + final InputDialogLogic logic = Get.put(InputDialogLogic()); + return Container(); + } +} diff --git a/lib/components/diary_card/calendar_diary_card/calendar_diary_card_view.dart b/lib/components/diary_card/calendar_diary_card/calendar_diary_card_view.dart index d5d4612..9447385 100644 --- a/lib/components/diary_card/calendar_diary_card/calendar_diary_card_view.dart +++ b/lib/components/diary_card/calendar_diary_card/calendar_diary_card_view.dart @@ -19,27 +19,6 @@ class CalendarDiaryCardComponent extends StatelessWidget with BasicCardLogic { final textStyle = Theme.of(context).textTheme; final pixelRatio = MediaQuery.devicePixelRatioOf(context); - Widget buildContent() { - return Column( - spacing: 4.0, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...[ - Text( - diary.title, - style: textStyle.titleMedium!.copyWith(), - ) - ], - Text( - diary.contentText.trim(), - overflow: TextOverflow.ellipsis, - maxLines: getMaxLines(diary.contentText), - style: textStyle.bodyMedium, - ), - ], - ); - } - Widget buildImage() { return SingleChildScrollView( scrollDirection: Axis.horizontal, @@ -62,7 +41,7 @@ class CalendarDiaryCardComponent extends StatelessWidget with BasicCardLogic { fit: BoxFit.cover, ), border: Border.all(color: colorScheme.outline), - borderRadius: AppBorderRadius.mediumBorderRadius, + borderRadius: AppBorderRadius.smallBorderRadius, ), ), ); @@ -73,25 +52,47 @@ class CalendarDiaryCardComponent extends StatelessWidget with BasicCardLogic { Widget buildTime() { return Text( - DateFormat.yMd().add_jms().format(diary.time), - style: textStyle.labelSmall, + DateFormat.yMMMMEEEEd().add_jms().format(diary.time), + style: textStyle.labelSmall?.copyWith(color: colorScheme.secondary), ); } return InkWell( - borderRadius: AppBorderRadius.mediumBorderRadius, - onTap: () async { - await toDiaryInCalendar(diary); - }, child: Card.filled( color: colorScheme.surfaceContainerLow, - child: Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - spacing: 4.0, - crossAxisAlignment: CrossAxisAlignment.start, - children: [buildTime(), buildContent(), buildImage()], - ))), + child: InkWell( + borderRadius: AppBorderRadius.mediumBorderRadius, + onTap: () async { + await toDiaryInCalendar(diary); + }, + child: Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + spacing: 4.0, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + buildTime(), + if (diary.title.isNotEmpty) + Text( + diary.title, + maxLines: 2, + style: textStyle.titleMedium!.copyWith( + color: colorScheme.onSurface, + ), + ), + if (diary.contentText.isNotEmpty) + Text( + diary.contentText.trim(), + overflow: TextOverflow.ellipsis, + maxLines: 4, + style: textStyle.bodyMedium?.copyWith( + color: colorScheme.onSurface, + ), + ), + buildImage() + ], + )), + )), ); } } diff --git a/lib/components/diary_card/large_diary_card/large_diary_card_view.dart b/lib/components/diary_card/large_diary_card/large_diary_card_view.dart index 0a7529e..3f75f83 100644 --- a/lib/components/diary_card/large_diary_card/large_diary_card_view.dart +++ b/lib/components/diary_card/large_diary_card/large_diary_card_view.dart @@ -6,6 +6,7 @@ import 'package:mood_diary/common/models/isar/diary.dart'; import 'package:mood_diary/common/values/border.dart'; import 'package:mood_diary/components/diary_card/basic_diary_card/basic_card_logic.dart'; +import '../../../common/values/colors.dart'; import '../../../utils/file_util.dart'; class LargeDiaryCardComponent extends StatelessWidget with BasicCardLogic { @@ -36,44 +37,76 @@ class LargeDiaryCardComponent extends StatelessWidget with BasicCardLogic { ); } - return InkWell( - borderRadius: AppBorderRadius.mediumBorderRadius, - onTap: () { - toDiary(diary); - }, - child: Card.filled( - color: colorScheme.surfaceContainerLow, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + return Card.filled( + color: colorScheme.surfaceContainerLow, + child: InkWell( + borderRadius: AppBorderRadius.mediumBorderRadius, + onTap: () { + toDiary(diary); + }, + child: Stack( children: [ - if (diary.imageName.isNotEmpty) ...[buildImage()], - Padding( - padding: const EdgeInsets.all(12.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - spacing: 4.0, - children: [ - if (diary.title.isNotEmpty) ...[ - Text( - diary.title, - style: textStyle.titleMedium!.copyWith(), - ) - ], - Text( - diary.contentText.trim(), - overflow: TextOverflow.ellipsis, - maxLines: getMaxLines(diary.contentText), - style: textStyle.bodyMedium, + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (diary.imageName.isNotEmpty) ...[buildImage()], + Padding( + padding: const EdgeInsets.all(12.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + spacing: 4.0, + children: [ + if (diary.title.isNotEmpty) + Text( + diary.title, + maxLines: 2, + overflow: TextOverflow.ellipsis, + style: textStyle.titleMedium + ?.copyWith(color: colorScheme.onSurface), + ), + if (diary.contentText.isNotEmpty) + Text( + diary.contentText.trim(), + overflow: TextOverflow.ellipsis, + maxLines: 4, + style: textStyle.bodyMedium + ?.copyWith(color: colorScheme.onSurface), + ), + Text( + DateFormat.yMd().add_Hms().format(diary.time), + style: textStyle.labelSmall?.copyWith( + color: + colorScheme.onSurface.withValues(alpha: 0.8)), + overflow: TextOverflow.ellipsis, + ), + ], ), - Text( - DateFormat.yMMMd().add_Hms().format(diary.time), - style: textStyle.labelSmall, - overflow: TextOverflow.ellipsis, - ) - ], - ), - ) + ) + ], + ), + // Positioned( + // top: 4, + // right: 4, + // child: Container( + // decoration: ShapeDecoration( + // shape: const CircleBorder(), + // color: colorScheme.surfaceContainerLow), + // width: 12, + // height: 12, + // child: Center( + // child: Container( + // decoration: ShapeDecoration( + // shape: const CircleBorder(), + // color: Color.lerp(AppColor.emoColorList.first, + // AppColor.emoColorList.last, diary.mood), + // ), + // width: 8, + // height: 8, + // ), + // ), + // ), + // ), ], ), ), diff --git a/lib/components/diary_card/small_diary_card/small_diary_card_view.dart b/lib/components/diary_card/small_diary_card/small_diary_card_view.dart index 140720c..fbd17c4 100644 --- a/lib/components/diary_card/small_diary_card/small_diary_card_view.dart +++ b/lib/components/diary_card/small_diary_card/small_diary_card_view.dart @@ -40,13 +40,13 @@ class SmallDiaryCardComponent extends StatelessWidget with BasicCardLogic { ); } - return InkWell( - borderRadius: AppBorderRadius.mediumBorderRadius, - onTap: () async { - await toDiary(diary); - }, - child: Card.filled( - color: colorScheme.surfaceContainerLow, + return Card.filled( + color: colorScheme.surfaceContainerLow, + child: InkWell( + borderRadius: AppBorderRadius.mediumBorderRadius, + onTap: () async { + await toDiary(diary); + }, child: SizedBox( height: 122.0, child: Row( @@ -65,7 +65,8 @@ class SmallDiaryCardComponent extends StatelessWidget with BasicCardLogic { Text( diary.title, overflow: TextOverflow.ellipsis, - style: textStyle.titleMedium, + style: textStyle.titleMedium + ?.copyWith(color: colorScheme.onSurface), maxLines: 1, ) ], @@ -73,11 +74,14 @@ class SmallDiaryCardComponent extends StatelessWidget with BasicCardLogic { diary.contentText.trim(), overflow: TextOverflow.ellipsis, maxLines: 2, - style: textStyle.bodyMedium, + style: textStyle.bodyMedium + ?.copyWith(color: colorScheme.onSurface), ), Text( DateFormat.yMMMd().add_Hms().format(diary.time), - style: textStyle.labelSmall, + style: textStyle.labelSmall?.copyWith( + color: colorScheme.onSurface.withValues(alpha: 0.8), + ), ) ], ), diff --git a/lib/components/media/media_audio_view.dart b/lib/components/media/media_audio_view.dart index 31900cc..528c94a 100644 --- a/lib/components/media/media_audio_view.dart +++ b/lib/components/media/media_audio_view.dart @@ -12,6 +12,7 @@ class MediaAudioComponent extends StatelessWidget { @override Widget build(BuildContext context) { final textStyle = Theme.of(context).textTheme; + final colorScheme = Theme.of(context).colorScheme; return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, @@ -20,7 +21,7 @@ class MediaAudioComponent extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: Text( DateFormat.yMMMEd().format(dateTime), - style: textStyle.titleSmall, + style: textStyle.titleSmall?.copyWith(color: colorScheme.secondary), ), ), ListView.builder( diff --git a/lib/components/media/media_image_view.dart b/lib/components/media/media_image_view.dart index 886ff45..e3b0d18 100644 --- a/lib/components/media/media_image_view.dart +++ b/lib/components/media/media_image_view.dart @@ -22,6 +22,7 @@ class MediaImageComponent extends StatelessWidget { Widget build(BuildContext context) { final pixelRatio = MediaQuery.devicePixelRatioOf(context); final textStyle = Theme.of(context).textTheme; + final colorScheme = Theme.of(context).colorScheme; return Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -31,7 +32,7 @@ class MediaImageComponent extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: Text( DateFormat.yMMMEd().format(dateTime), - style: textStyle.titleSmall, + style: textStyle.titleSmall?.copyWith(color: colorScheme.secondary), ), ), GridView.builder( diff --git a/lib/components/media/media_video_view.dart b/lib/components/media/media_video_view.dart index 4848ff5..0f27a51 100644 --- a/lib/components/media/media_video_view.dart +++ b/lib/components/media/media_video_view.dart @@ -25,6 +25,7 @@ class MediaVideoComponent extends StatelessWidget { Widget build(BuildContext context) { final pixelRatio = MediaQuery.devicePixelRatioOf(context); final textStyle = Theme.of(context).textTheme; + final colorScheme = Theme.of(context).colorScheme; // 将视频路径转换为缩略图路径 final thumbnailList = videoList.map((e) { final id = e.split('video-')[1].split('.')[0]; @@ -39,7 +40,7 @@ class MediaVideoComponent extends StatelessWidget { padding: const EdgeInsets.all(8.0), child: Text( DateFormat.yMMMEd().format(dateTime), - style: textStyle.titleSmall, + style: textStyle.titleSmall?.copyWith(color: colorScheme.secondary), ), ), GridView.builder( diff --git a/lib/components/time_line/time_line_view.dart b/lib/components/time_line/time_line_view.dart index 474e111..22748a8 100644 --- a/lib/components/time_line/time_line_view.dart +++ b/lib/components/time_line/time_line_view.dart @@ -41,7 +41,7 @@ class TimeLineComponent extends StatelessWidget { return CustomPaint( painter: TimeLinePainter( - lineColor: colorScheme.outline, + lineColor: colorScheme.outlineVariant, actionColor: actionColor, lineWidth: 2.0), child: Padding( diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index b99cc06..8fb9406 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -94,6 +94,7 @@ "aboutUserAgreement": "User Agreement", "aboutPrivacyPolicy": "Privacy Policy", "aboutBugReport": "BUG Report", + "aboutDonate": "Donate", "mediaTypeImage": "Image", "mediaTypeAudio": "Audio", "mediaTypeVideo": "Video", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index dd855ef..3f69cb3 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -94,6 +94,7 @@ "aboutUserAgreement": "用户协议", "aboutPrivacyPolicy": "隐私政策", "aboutBugReport": "BUG 反馈", + "aboutDonate": "捐助我们", "mediaTypeImage": "图片", "mediaTypeAudio": "音频", "mediaTypeVideo": "视频", diff --git a/lib/pages/about/about_logic.dart b/lib/pages/about/about_logic.dart index 4808ff0..cf07f17 100644 --- a/lib/pages/about/about_logic.dart +++ b/lib/pages/about/about_logic.dart @@ -1,3 +1,4 @@ +import 'package:device_info_plus/device_info_plus.dart'; import 'package:get/get.dart'; import 'package:mood_diary/router/app_routes.dart'; import 'package:mood_diary/utils/package_util.dart'; @@ -17,8 +18,20 @@ class AboutLogic extends GetxController { Future getInfo() async { var packageInfo = await PackageUtil.getPackageInfo(); + var deviceInfo = await PackageUtil.getInfo(); + if (deviceInfo is AndroidDeviceInfo) { + state.systemVersion = 'Android ${deviceInfo.version.release}'; + } else if (deviceInfo is IosDeviceInfo) { + state.systemVersion = + '${deviceInfo.systemName} ${deviceInfo.systemVersion}'; + } else if (deviceInfo is WindowsDeviceInfo) { + state.systemVersion = 'Windows ${deviceInfo.majorVersion}'; + } else if (deviceInfo is MacOsDeviceInfo) { + state.systemVersion = 'MacOS ${deviceInfo.osRelease} '; + } + state.appName = packageInfo.appName; - state.appVersion = packageInfo.version; + state.appVersion = '${packageInfo.version}(${packageInfo.buildNumber})'; update(); } @@ -54,4 +67,8 @@ class AboutLogic extends GetxController { void toAgreement() { Get.toNamed(AppRoutes.agreementPage); } + + void toSponsor() { + Get.toNamed(AppRoutes.sponsorPage); + } } diff --git a/lib/pages/about/about_state.dart b/lib/pages/about/about_state.dart index 83da6f7..30a0fbc 100644 --- a/lib/pages/about/about_state.dart +++ b/lib/pages/about/about_state.dart @@ -3,6 +3,8 @@ class AboutState { late String appVersion; + String systemVersion = ''; + AboutState() { appName = ''; appVersion = ''; diff --git a/lib/pages/about/about_view.dart b/lib/pages/about/about_view.dart index 036bb7c..6ab90ac 100644 --- a/lib/pages/about/about_view.dart +++ b/lib/pages/about/about_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:mood_diary/utils/update_util.dart'; @@ -13,30 +14,60 @@ class AboutPage extends StatelessWidget { final logic = Bind.find(); final state = Bind.find().state; final colorScheme = Theme.of(context).colorScheme; + final textStyle = Theme.of(context).textTheme; Widget buildLogoTitle() { - return Padding( - padding: const EdgeInsets.all(32.0), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.asset( - colorScheme.brightness == Brightness.light - ? 'assets/icon/light/light_foreground.png' - : 'assets/icon/dark/dark_foreground.png', - height: 160.0, - width: 160.0, - ), - Column( - spacing: 4.0, - mainAxisSize: MainAxisSize.min, - children: [ - Text(state.appName), - Text('Version: ${state.appVersion}') - ], - ) - ], - ), + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + Image.asset( + colorScheme.brightness == Brightness.light + ? 'assets/icon/light/light_foreground.png' + : 'assets/icon/dark/dark_foreground.png', + color: colorScheme.onSurface, + height: 160.0, + width: 160.0, + ), + Column( + spacing: 16.0, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + state.appName, + style: textStyle.titleLarge + ?.copyWith(color: colorScheme.onSurface), + ), + RichText( + text: TextSpan( + style: textStyle.labelMedium + ?.copyWith(color: colorScheme.onSurface), + children: [ + TextSpan( + text: 'Version: ', + style: textStyle.labelSmall + ?.copyWith(color: colorScheme.onSurface), + ), + TextSpan(text: state.appVersion), + const WidgetSpan( + child: SizedBox( + height: 12, + child: VerticalDivider( + thickness: 2, + ), + ), + alignment: PlaceholderAlignment.middle), + TextSpan( + text: 'System: ', + style: textStyle.labelSmall + ?.copyWith(color: colorScheme.onSurface), + ), + TextSpan(text: state.systemVersion), + ], + ), + ) + ], + ), + ], ); } @@ -44,63 +75,117 @@ class AboutPage extends StatelessWidget { appBar: AppBar( title: Text(l10n.aboutTitle), ), - body: ListView( - padding: const EdgeInsets.all(4.0), - children: [ - GetBuilder(builder: (_) { - return buildLogoTitle(); - }), - Card.outlined( - color: colorScheme.surfaceContainerLow, - child: Column( - children: [ - GetBuilder(builder: (_) { - return ListTile( - leading: const Icon(Icons.update), - title: Text(l10n.aboutUpdate), - trailing: const Icon(Icons.chevron_right), + body: SafeArea( + child: ListView( + padding: const EdgeInsets.all(4.0), + children: [ + GetBuilder(builder: (_) { + return buildLogoTitle(); + }), + const SizedBox(height: 16.0), + Card.outlined( + color: colorScheme.surfaceContainerLow, + child: Column( + children: [ + GetBuilder(builder: (_) { + return ListTile( + leading: const Icon(Icons.update_rounded), + title: Text(l10n.aboutUpdate), + trailing: const Icon(Icons.chevron_right_rounded), + onTap: () async { + await UpdateUtil.checkShouldUpdate(state.appVersion, + handle: true); + }, + ); + }), + ListTile( + leading: const Icon(Icons.source_rounded), + title: Text(l10n.aboutSource), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () async { - await UpdateUtil.checkShouldUpdate(state.appVersion, - handle: true); + await logic.toSource(); }, - ); - }), - ListTile( - leading: const Icon(Icons.source_outlined), - title: Text(l10n.aboutSource), - trailing: const Icon(Icons.chevron_right), - onTap: () async { - await logic.toSource(); - }, + ), + ListTile( + leading: const Icon(Icons.file_copy_rounded), + title: Text(l10n.aboutUserAgreement), + trailing: const Icon(Icons.chevron_right_rounded), + onTap: () { + logic.toAgreement(); + }, + ), + ListTile( + leading: const Icon(Icons.security_rounded), + title: Text(l10n.aboutPrivacyPolicy), + trailing: const Icon(Icons.chevron_right_rounded), + onTap: () { + logic.toPrivacy(); + }, + ), + ListTile( + leading: const Icon(Icons.bug_report_rounded), + title: Text(l10n.aboutBugReport), + trailing: const Icon(Icons.chevron_right_rounded), + onTap: () async { + await logic.toReportPage(); + }, + ), + ListTile( + leading: const Icon(Icons.attach_money_rounded), + title: Text(l10n.aboutDonate), + trailing: const Icon(Icons.chevron_right_rounded), + onTap: logic.toSponsor, + ), + ], + ), + ), + const SizedBox(height: 16.0), + Row( + mainAxisAlignment: MainAxisAlignment.center, + spacing: 4.0, + children: [ + const FaIcon( + FontAwesomeIcons.flutter, + size: 16, + color: Colors.lightBlue, + ), + const SizedBox( + height: 12, + child: VerticalDivider( + thickness: 2, + ), ), - ListTile( - leading: const Icon(Icons.file_copy_outlined), - title: Text(l10n.aboutUserAgreement), - trailing: const Icon(Icons.chevron_right), - onTap: () { - logic.toAgreement(); - }, + FaIcon( + FontAwesomeIcons.dartLang, + size: 16, + color: colorScheme.onSurface.withValues(alpha: 0.8), ), - ListTile( - leading: const Icon(Icons.security_outlined), - title: Text(l10n.aboutPrivacyPolicy), - trailing: const Icon(Icons.chevron_right), - onTap: () { - logic.toPrivacy(); - }, + const SizedBox( + height: 12, + child: VerticalDivider( + thickness: 2, + ), ), - ListTile( - leading: const Icon(Icons.bug_report_outlined), - title: Text(l10n.aboutBugReport), - trailing: const Icon(Icons.chevron_right), - onTap: () async { - await logic.toReportPage(); - }, + FaIcon( + FontAwesomeIcons.rust, + size: 16, + color: colorScheme.onSurface.withValues(alpha: 0.8), + ), + const SizedBox( + height: 12, + child: VerticalDivider( + thickness: 2, + ), + ), + const FaIcon( + FontAwesomeIcons.solidHeart, + size: 16, + color: Colors.pinkAccent, ), ], - ), - ), - ], + ) + ], + ), ), ); } diff --git a/lib/pages/analyse/analyse_view.dart b/lib/pages/analyse/analyse_view.dart index 209844b..9afe1fc 100644 --- a/lib/pages/analyse/analyse_view.dart +++ b/lib/pages/analyse/analyse_view.dart @@ -193,7 +193,7 @@ class AnalysePage extends StatelessWidget { ), ), GridView.count( - crossAxisCount: size.width > 700 ? 2 : 1, + crossAxisCount: size.width > 600 ? 2 : 1, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), padding: EdgeInsets.zero, diff --git a/lib/pages/backup_sync/backup_sync_view.dart b/lib/pages/backup_sync/backup_sync_view.dart index 39acf47..058887c 100644 --- a/lib/pages/backup_sync/backup_sync_view.dart +++ b/lib/pages/backup_sync/backup_sync_view.dart @@ -43,7 +43,7 @@ class BackupSyncPage extends StatelessWidget { ); }); }, - trailing: const Icon(Icons.chevron_right), + trailing: const Icon(Icons.chevron_right_rounded), leading: const Icon(Icons.file_upload_outlined), ), ListTile( @@ -71,7 +71,7 @@ class BackupSyncPage extends StatelessWidget { ); }); }, - trailing: const Icon(Icons.chevron_right), + trailing: const Icon(Icons.chevron_right_rounded), leading: const Icon(Icons.file_download_outlined), ), const LocalSendComponent(), diff --git a/lib/pages/diary_details/diary_details_view.dart b/lib/pages/diary_details/diary_details_view.dart index af2f6d6..e40b594 100644 --- a/lib/pages/diary_details/diary_details_view.dart +++ b/lib/pages/diary_details/diary_details_view.dart @@ -393,7 +393,8 @@ class DiaryDetailsPage extends StatelessWidget { controller: logic.quillController, config: QuillEditorConfig( showCursor: false, - customStyles: ThemeUtil.getInstance(context), + customStyles: ThemeUtil.getInstance(context, + customColorScheme: customColorScheme), embedBuilders: [ ImageEmbedBuilder(isEdit: false), VideoEmbedBuilder(isEdit: false), diff --git a/lib/pages/edit/edit_logic.dart b/lib/pages/edit/edit_logic.dart index adb6296..34eb5a8 100644 --- a/lib/pages/edit/edit_logic.dart +++ b/lib/pages/edit/edit_logic.dart @@ -31,9 +31,6 @@ import 'edit_state.dart'; class EditLogic extends GetxController { final EditState state = EditState(); - //标签控制器 - late TextEditingController tagTextEditingController = TextEditingController(); - //标题 late TextEditingController titleTextEditingController = TextEditingController(); @@ -89,7 +86,6 @@ class EditLogic extends GetxController { @override void onClose() { keyboardObserver.stop(); - tagTextEditingController.dispose(); titleTextEditingController.dispose(); titleFocusNode.dispose(); contentFocusNode.dispose(); @@ -414,7 +410,7 @@ class EditLogic extends GetxController { lastDate: DateTime.now(), initialDatePickerMode: DatePickerMode.day, initialEntryMode: DatePickerEntryMode.calendarOnly, - firstDate: DateTime.now().subtract(const Duration(days: 31)), + firstDate: DateTime.now().subtract(const Duration(days: 365)), ); if (nowDateTime != null) { state.currentDiary.time = state.currentDiary.time.copyWith( @@ -512,18 +508,18 @@ class EditLogic extends GetxController { NoticeUtil.showToast('删除成功'); } - void cancelAddTag() { - Get.backLegacy(); - tagTextEditingController.clear(); - } - //添加一个标签 - void addTag() { - Get.backLegacy(); - if (tagTextEditingController.text.isNotEmpty) { - state.currentDiary.tags.add(tagTextEditingController.text); - tagTextEditingController.clear(); + void addTag({required String tag}) { + tag = tag.trim(); + if (tag.isNotEmpty) { + if (state.currentDiary.tags.contains(tag)) { + NoticeUtil.showToast('标签已存在'); + return; + } + state.currentDiary.tags.add(tag); update(['Tag']); + } else { + NoticeUtil.showToast('标签不能为空'); } } diff --git a/lib/pages/edit/edit_view.dart b/lib/pages/edit/edit_view.dart index 52b4a23..6c50f49 100644 --- a/lib/pages/edit/edit_view.dart +++ b/lib/pages/edit/edit_view.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:auto_size_text_field/auto_size_text_field.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; @@ -21,7 +22,6 @@ import 'package:mood_diary/utils/theme_util.dart'; import '../../common/values/diary_type.dart'; import '../../components/quill_embed/audio_embed.dart'; -import '../../main.dart'; import 'edit_logic.dart'; class EditPage extends StatelessWidget { @@ -45,10 +45,16 @@ class EditPage extends StatelessWidget { @override Widget build(BuildContext context) { final logic = Bind.find(); - final state = Bind.find().state; - final colorScheme = Theme.of(context).colorScheme; + final state = Bind + .find() + .state; + final colorScheme = Theme + .of(context) + .colorScheme; - final textStyle = Theme.of(context).textTheme; + final textStyle = Theme + .of(context) + .textTheme; // Widget buildAddContainer(Widget icon) { // return Container( @@ -67,20 +73,20 @@ class EditPage extends StatelessWidget { Widget? buildTagList() { return state.currentDiary.tags.isNotEmpty ? Wrap( - spacing: 8.0, - children: List.generate(state.currentDiary.tags.length, (index) { - return Chip( - label: Text( - state.currentDiary.tags[index], - style: TextStyle(color: colorScheme.onSecondaryContainer), - ), - backgroundColor: colorScheme.secondaryContainer, - onDeleted: () { - logic.removeTag(index); - }, - ); - }), - ) + spacing: 8.0, + children: List.generate(state.currentDiary.tags.length, (index) { + return Chip( + label: Text( + state.currentDiary.tags[index], + style: TextStyle(color: colorScheme.onSecondaryContainer), + ), + backgroundColor: colorScheme.secondaryContainer, + onDeleted: () { + logic.removeTag(index); + }, + ); + }), + ) : null; } @@ -396,7 +402,7 @@ class EditPage extends StatelessWidget { value: state.currentDiary.mood, divisions: 10, label: - '${(state.currentDiary.mood * 100).toStringAsFixed(0)}%', + '${(state.currentDiary.mood * 100).toStringAsFixed(0)}%', activeColor: Color.lerp(AppColor.emoColorList.first, AppColor.emoColorList.last, state.currentDiary.mood), onChanged: (value) { @@ -535,16 +541,17 @@ class EditPage extends StatelessWidget { title: const Text('天气'), subtitle: state.currentDiary.weather.isNotEmpty ? Text( - '${state.currentDiary.weather[2]} ${state.currentDiary.weather[1]}°C') + '${state.currentDiary.weather[2]} ${state.currentDiary + .weather[1]}°C') : null, trailing: state.isProcessing ? const CircularProgressIndicator() : IconButton.filledTonal( - onPressed: () async { - await logic.getPositionAndWeather(); - }, - icon: const Icon(Icons.location_on), - ), + onPressed: () async { + await logic.getPositionAndWeather(); + }, + icon: const Icon(Icons.location_on), + ), ); }), GetBuilder( @@ -575,39 +582,20 @@ class EditPage extends StatelessWidget { subtitle: buildTagList(), trailing: IconButton.filledTonal( icon: const Icon(Icons.tag), - onPressed: () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - content: TextField( - maxLines: 1, - controller: logic.tagTextEditingController, - decoration: InputDecoration( - fillColor: colorScheme.secondaryContainer, - border: const UnderlineInputBorder( - borderRadius: - AppBorderRadius.smallBorderRadius, - borderSide: BorderSide.none, - ), - filled: true, - labelText: '标签', - ), - ), - actions: [ - TextButton( - onPressed: () { - logic.cancelAddTag(); - }, - child: Text(l10n.cancel)), - TextButton( - onPressed: () { - logic.addTag(); - }, - child: Text(l10n.ok)) - ], - ); - }); + onPressed: () async { + var res = await showTextInputDialog( + style: AdaptiveStyle.material, + context: context, + title: '添加标签', + textFields: [ + const DialogTextField( + hintText: '标签', + ) + ], + ); + if (res != null && res.isNotEmpty) { + logic.addTag(tag: res.first); + } }, ), ); @@ -717,32 +705,42 @@ class EditPage extends StatelessWidget { } Widget buildToolBar() { - return TooltipTheme( - data: const TooltipThemeData(preferBelow: false), - child: QuillSimpleToolbar( - controller: logic.quillController, - config: QuillSimpleToolbarConfig( - showFontFamily: false, - showFontSize: false, - showBackgroundColorButton: true, - showAlignmentButtons: true, - showClipboardPaste: false, - showClipboardCut: false, - showClipboardCopy: false, - showIndent: false, - showDividers: false, - multiRowsDisplay: false, - headerStyleType: HeaderStyleType.original, - showLink: false, - embedButtons: [ - (context, embedContext) { - return _buildToolBarButton( - iconData: Icons.format_indent_increase, - tooltip: 'Text Indent', - onPressed: logic.insertNewLine, - ); - }, - ], + return ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), + child: TooltipTheme( + data: const TooltipThemeData(preferBelow: false), + child: QuillSimpleToolbar( + controller: logic.quillController, + config: QuillSimpleToolbarConfig( + showFontFamily: false, + showFontSize: false, + showBackgroundColorButton: true, + showAlignmentButtons: true, + showClipboardPaste: false, + showClipboardCut: false, + showClipboardCopy: false, + showIndent: false, + showDividers: false, + multiRowsDisplay: false, + headerStyleType: HeaderStyleType.buttons, + buttonOptions: QuillSimpleToolbarButtonOptions( + selectHeaderStyleButtons: + QuillToolbarSelectHeaderStyleButtonsOptions( + iconTheme: QuillIconTheme(iconButtonSelectedData:IconButtonData( + color: colorScheme.onPrimary, + )),) + ), + showLink: false, + embedButtons: [ + (context, embedContext) { + return _buildToolBarButton( + iconData: Icons.format_indent_increase, + tooltip: 'Text Indent', + onPressed: logic.insertNewLine, + ); + }, + ], + ), ), ), ); @@ -800,13 +798,11 @@ class EditPage extends StatelessWidget { style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap), onPressed: () { - showModalBottomSheet( + showFloatingModalBottomSheet( context: context, builder: (context) { return buildDetail(); }, - showDragHandle: true, - useSafeArea: true, ); }, ), @@ -831,9 +827,12 @@ class EditPage extends StatelessWidget { expands: true, paintCursorAboveText: true, keyboardAppearance: - CupertinoTheme.maybeBrightnessOf(context) ?? - Theme.of(context).brightness, - customStyles: ThemeUtil.getInstance(context), + CupertinoTheme.maybeBrightnessOf(context) ?? + Theme + .of(context) + .brightness, + customStyles: ThemeUtil.getInstance(context, + customColorScheme: colorScheme), embedBuilders: [ if (state.type == DiaryType.richText) ...[ ImageEmbedBuilder(isEdit: true), @@ -860,7 +859,7 @@ class EditPage extends StatelessWidget { ), ), Padding( - padding: const EdgeInsets.all(8.0), + padding: const EdgeInsets.all(16.0), child: switch (state.type) { DiaryType.text => textToolBar(), DiaryType.richText => richTextToolBar(), diff --git a/lib/pages/font/font_logic.dart b/lib/pages/font/font_logic.dart index 1b8f2db..8c46ced 100644 --- a/lib/pages/font/font_logic.dart +++ b/lib/pages/font/font_logic.dart @@ -36,8 +36,11 @@ class FontLogic extends GetxController with GetSingleTickerProviderStateMixin { state.currentFontPath.value = path; } - Future getFontList() async { - state.isFetching.value = true; + Future getFontList({bool inInit = true}) async { + if (inInit) { + state.isFetching.value = true; + } + final filePathList = await FileUtil.getDirFilePath('font'); for (var filePath in filePathList) { if (filePath.endsWith('.ttf')) { @@ -52,12 +55,15 @@ class FontLogic extends GetxController with GetSingleTickerProviderStateMixin { List> fontLoadFutures = []; // 预加载字体 for (var entry in state.fontMap.entries) { + if (loadedFonts.contains(entry.value)) { + continue; + } fontLoadFutures.add( DynamicFont.file(fontFamily: entry.value, filepath: entry.key) .load()); } await Future.wait(fontLoadFutures); - + update(); state.isFetching.value = false; } @@ -78,7 +84,7 @@ class FontLogic extends GetxController with GetSingleTickerProviderStateMixin { } var newPath = FileUtil.getRealPath('font', basename(path)); File(path).copy(newPath); - await getFontList(); + await getFontList(inInit: false); NoticeUtil.showToast('添加成功'); } else { NoticeUtil.showToast('取消文件选择'); diff --git a/lib/pages/font/font_view.dart b/lib/pages/font/font_view.dart index 05f62b0..d133fbb 100644 --- a/lib/pages/font/font_view.dart +++ b/lib/pages/font/font_view.dart @@ -366,6 +366,13 @@ class FontPage extends StatelessWidget { ); }), resizeToAvoidBottomInset: false, + floatingActionButton: size.width > 600 + ? FloatingActionButton.extended( + onPressed: logic.saveFontScale, + label: const Text('应用'), + icon: const Icon(Icons.check), + ) + : null, bottomSheet: Obx(() { return Visibility( visible: !state.isFetching.value && size.width < 600, diff --git a/lib/pages/home/calendar/calendar_logic.dart b/lib/pages/home/calendar/calendar_logic.dart index c580ebe..c8c10f0 100644 --- a/lib/pages/home/calendar/calendar_logic.dart +++ b/lib/pages/home/calendar/calendar_logic.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:mood_diary/utils/log_util.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import '../../../utils/data/isar.dart'; @@ -30,8 +31,9 @@ class CalendarLogic extends GetxController { Future getMonthDiary(DateTime value) async { state.isFetching.value = true; state.currentMonth.value = value; - state.currentMonthDiaryList.value = - await IsarUtil.getDiaryByMonth(value.year, value.month); + // state.currentMonthDiaryList.value = + // await IsarUtil.getDiaryByMonth(value.year, value.month); + state.currentMonthDiaryList.value = await IsarUtil.getAllDiariesSorted(); state.isFetching.value = false; } @@ -55,6 +57,17 @@ class CalendarLogic extends GetxController { } } + void _onVerticalDragUpdate(DragUpdateDetails details) {} + + void onVerticalDragEnd(DragEndDetails details) { + double velocity = details.velocity.pixelsPerSecond.dy; + LogUtil.printInfo(velocity); + if (velocity > state.velocityThreshold) { + LogUtil.printInfo('1'); + open(state.isUp); + } + } + // // 选中日期后重新获取日记 // Future updateDate(DateTime value) async { // state.selectedDate.value = value; @@ -68,4 +81,20 @@ class CalendarLogic extends GetxController { expansionTileController.collapse(); } } + + DateTime? findLatestDateInMonth(List dates, int year, int month) { + // 过滤出符合条件的日期 + List filteredDates = dates.where((date) { + return date.year == year && date.month == month; + }).toList(); + + // 如果没有符合条件的日期,返回 null + if (filteredDates.isEmpty) { + return null; + } + + // 找到最晚的日期 + filteredDates.sort((a, b) => b.compareTo(a)); // 降序排序 + return filteredDates.first; // 返回第一个元素,即最晚的日期 + } } diff --git a/lib/pages/home/calendar/calendar_state.dart b/lib/pages/home/calendar/calendar_state.dart index a5c7a8a..c420874 100644 --- a/lib/pages/home/calendar/calendar_state.dart +++ b/lib/pages/home/calendar/calendar_state.dart @@ -11,5 +11,9 @@ class CalendarState { late RxBool isControllerScrolling = false.obs; + double velocityThreshold = 800; + + bool isUp = false; + CalendarState(); } diff --git a/lib/pages/home/calendar/calendar_view.dart b/lib/pages/home/calendar/calendar_view.dart index c6a24c8..c7ba88c 100644 --- a/lib/pages/home/calendar/calendar_view.dart +++ b/lib/pages/home/calendar/calendar_view.dart @@ -69,6 +69,7 @@ class CalendarPage extends StatelessWidget { final state = Bind.find().state; final colorScheme = Theme.of(context).colorScheme; final textStyle = Theme.of(context).textTheme; + final size = MediaQuery.sizeOf(context); //生成日历选择器 Widget buildDatePicker() { @@ -86,6 +87,88 @@ class CalendarPage extends StatelessWidget { } final dateCountMap = ArrayUtil.countList(allDate); + return Stack( + children: [ + Card.filled( + color: colorScheme.surfaceContainerLow, + child: Obx(() { + return CalendarDatePicker2( + displayedMonthDate: state.currentMonth.value, + config: CalendarDatePicker2Config( + calendarViewMode: CalendarDatePicker2Mode.day, + calendarType: CalendarDatePicker2Type.single, + hideMonthPickerDividers: true, + hideYearPickerDividers: true, + useAbbrLabelForMonthModePicker: true, + allowSameValueSelection: true, + dayBuilder: ({ + required DateTime date, + TextStyle? textStyle, + BoxDecoration? decoration, + bool? isSelected, + bool? isDisabled, + bool? isToday, + }) { + final contains = dateWithDiaryList.contains(date); + final bgColor = contains + ? Color.lerp( + colorScheme.surfaceContainer, + colorScheme.primary, + getDayColor(count: dateCountMap[date] ?? 0)) + : null; + return Padding( + padding: const EdgeInsets.all(2.0), + child: Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: bgColor, + ), + child: Center( + child: Text( + date.day.toString(), + style: textStyle?.copyWith( + color: contains + ? ThemeData.estimateBrightnessForColor( + bgColor!) == + Brightness.dark + ? Colors.white + : Colors.black + : null, + ), + ), + ), + ), + ); + }, + selectableDayPredicate: (DateTime date) { + return dateWithDiaryList.contains(date); + }, + ), + onValueChanged: (value) { + logic.animateToSelectedDateWithLock(value.first); + }, + onDisplayedMonthChanged: (value) async { + var lastDate = logic.findLatestDateInMonth( + dateWithDiaryList, value.year, value.month); + if (lastDate != null) { + await logic.animateToSelectedDateWithLock(lastDate); + } + }, + value: const [], + ); + }), + ), + Positioned( + bottom: 4, + right: 4, + child: _buildActiveInfo( + lessColor: colorScheme.surfaceContainer, + moreColor: colorScheme.primary, + textStyle: textStyle.labelSmall?.copyWith( + color: colorScheme.onSurface.withValues(alpha: 0.8))), + ), + ], + ); return Theme( data: Theme.of(context).copyWith(dividerColor: Colors.transparent), child: Padding( @@ -169,7 +252,9 @@ class CalendarPage extends StatelessWidget { child: _buildActiveInfo( lessColor: colorScheme.surfaceContainer, moreColor: colorScheme.primary, - textStyle: textStyle.labelSmall), + textStyle: textStyle.labelSmall?.copyWith( + color: + colorScheme.onSurface.withValues(alpha: 0.8))), ), ], ), @@ -180,54 +265,25 @@ class CalendarPage extends StatelessWidget { } Widget buildCardList() { - double lastScrollOffset = 0.0; - return NotificationListener( - onNotification: (ScrollNotification notification) { - if (notification is ScrollUpdateNotification) { - const double baseThreshold = 200.0; // 基础阈值 - final double scrollDelta = - notification.scrollDelta ?? 0.0; // 滚动增量(速度) - - // 根据速度动态调整阈值,速度越快,阈值越高 - final double dynamicThreshold = - baseThreshold + (scrollDelta.abs() / 2); - - final currentOffset = notification.metrics.pixels; - final distance = (currentOffset - lastScrollOffset).abs(); // 滚动距离 - - if (distance > dynamicThreshold) { - if (currentOffset > lastScrollOffset) { - // 向下滚动 - if (!state.isControllerScrolling.value) logic.open(false); - } else if (currentOffset < lastScrollOffset) { - // 向上滚动 - if (!state.isControllerScrolling.value) logic.open(true); - } - lastScrollOffset = currentOffset; // 更新滚动位置 - } - } - return true; - }, - child: Obx(() { - return ScrollablePositionedList.builder( - itemBuilder: (context, index) { - return TimeLineComponent( - actionColor: Color.lerp( - AppColor.emoColorList.first, - AppColor.emoColorList.last, - state.currentMonthDiaryList[index].mood)!, - child: CalendarDiaryCardComponent( - diary: state.currentMonthDiaryList[index]), - ); - }, - itemScrollController: logic.itemScrollController, - itemPositionsListener: logic.itemPositionsListener, - scrollOffsetController: logic.scrollOffsetController, - scrollOffsetListener: logic.scrollOffsetListener, - itemCount: state.currentMonthDiaryList.length, - ); - }), - ); + return Obx(() { + return ScrollablePositionedList.builder( + itemBuilder: (context, index) { + return TimeLineComponent( + actionColor: Color.lerp( + AppColor.emoColorList.first, + AppColor.emoColorList.last, + state.currentMonthDiaryList[index].mood)!, + child: CalendarDiaryCardComponent( + diary: state.currentMonthDiaryList[index]), + ); + }, + itemScrollController: logic.itemScrollController, + itemPositionsListener: logic.itemPositionsListener, + scrollOffsetController: logic.scrollOffsetController, + scrollOffsetListener: logic.scrollOffsetListener, + itemCount: state.currentMonthDiaryList.length, + ); + }); } return GetBuilder( @@ -236,31 +292,66 @@ class CalendarPage extends StatelessWidget { return SafeArea( child: Padding( padding: const EdgeInsets.all(4.0), - child: Column( - spacing: 4.0, - children: [ - Obx(() { - return buildDatePicker(); - }), - Expanded(child: Obx(() { - return AnimatedSwitcher( - duration: const Duration(milliseconds: 400), - child: state.isFetching.value - ? const Center( - key: ValueKey('processing'), child: Processing()) - : (state.currentMonthDiaryList.isNotEmpty - ? buildCardList() - : const Center( - key: ValueKey('empty'), - child: FaIcon( - FontAwesomeIcons.boxOpen, - size: 56, - ), - )), - ); - })), - ], - ), + child: size.width > 600 + ? Row( + children: [ + Expanded( + child: Obx(() { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: state.isFetching.value + ? const Center( + key: ValueKey('processing'), + child: Processing()) + : (state.currentMonthDiaryList.isNotEmpty + ? buildCardList() + : const Center( + key: ValueKey('empty'), + child: FaIcon( + FontAwesomeIcons.boxOpen, + size: 56, + ), + )), + ); + }), + ), + Align( + alignment: Alignment.topCenter, + child: SizedBox( + width: 320, + child: Obx(() { + return buildDatePicker(); + }), + ), + ), + ], + ) + : Column( + spacing: 4.0, + children: [ + Obx(() { + return buildDatePicker(); + }), + Expanded(child: Obx(() { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: state.isFetching.value + ? const Center( + key: ValueKey('processing'), + child: Processing()) + : (state.currentMonthDiaryList.isNotEmpty + ? buildCardList() + : const Center( + key: ValueKey('empty'), + child: FaIcon( + FontAwesomeIcons.boxOpen, + size: 56, + ), + )), + ); + })), + ], + ), ), ); }, diff --git a/lib/pages/home/diary/diary_view.dart b/lib/pages/home/diary/diary_view.dart index 06e8c1b..f2ecef9 100644 --- a/lib/pages/home/diary/diary_view.dart +++ b/lib/pages/home/diary/diary_view.dart @@ -86,9 +86,7 @@ class DiaryPage extends StatelessWidget { splashFactory: NoSplash.splashFactory, dragStartBehavior: DragStartBehavior.start, unselectedLabelStyle: textStyle.labelSmall, - labelStyle: textStyle.labelMedium!.copyWith( - fontWeight: FontWeight.w500, - fontVariations: [const FontVariation('wght', 500)]), + labelStyle: textStyle.labelMedium, indicator: ShapeDecoration( shape: const StadiumBorder(), color: colorScheme.primaryContainer, @@ -168,7 +166,9 @@ class DiaryPage extends StatelessWidget { ? state.customTitleName : l10n.appName, overflow: TextOverflow.ellipsis, - style: textStyle.titleLarge, + style: textStyle.titleLarge?.copyWith( + color: colorScheme.onSurface, + ), ); }), LayoutBuilder(builder: (context, constraints) { @@ -201,14 +201,14 @@ class DiaryPage extends StatelessWidget { decelerationCurve: Curves.easeOut, style: textStyle.labelMedium?.copyWith( color: colorScheme.onSurface - .withValues(alpha: 0.9)), + .withValues(alpha: 0.8)), ), ) : Text( state.hitokoto.value, style: textStyle.labelMedium?.copyWith( color: colorScheme.onSurface - .withValues(alpha: 0.9)), + .withValues(alpha: 0.8)), ); }); }), diff --git a/lib/pages/home/home_logic.dart b/lib/pages/home/home_logic.dart index 421aa52..bc2e84a 100644 --- a/lib/pages/home/home_logic.dart +++ b/lib/pages/home/home_logic.dart @@ -34,12 +34,20 @@ class HomeLogic extends GetxController with GetTickerProviderStateMixin { late final DiaryLogic diaryLogic = Bind.find(); + late final AppLifecycleListener appLifecycleListener; + @override void onReady() { //unawaited(Utils().updateUtil.checkShouldUpdate(PrefUtil.getValue('appVersion')!.split('+')[0])); // unawaited(getHitokoto()); // Tutorial.getTutorial(targets: buildFabGuide()) // .show(context: Get.overlayContext!); + appLifecycleListener = AppLifecycleListener(onStateChange: (state) { + if (state == AppLifecycleState.inactive) { + lockPage(); + } + }); + super.onReady(); } diff --git a/lib/pages/home/media/media_view.dart b/lib/pages/home/media/media_view.dart index 415c482..d1ba6c1 100644 --- a/lib/pages/home/media/media_view.dart +++ b/lib/pages/home/media/media_view.dart @@ -122,7 +122,9 @@ class MediaPage extends StatelessWidget { child: AnimatedSwitcher( duration: const Duration(milliseconds: 400), child: state.isFetching - ? const Center(child: SearchLoading()) + ? const Center( + key: ValueKey('searching'), + child: SearchLoading()) : (state.datetimeMediaMap.isNotEmpty ? ScrollablePositionedList.builder( itemBuilder: (context, index) { @@ -153,6 +155,7 @@ class MediaPage extends StatelessWidget { logic.scrollOffsetListener, ) : const Center( + key: ValueKey('empty'), child: FaIcon( FontAwesomeIcons.boxArchive, size: 80, diff --git a/lib/pages/home/setting/setting_logic.dart b/lib/pages/home/setting/setting_logic.dart index d419700..b274ff3 100644 --- a/lib/pages/home/setting/setting_logic.dart +++ b/lib/pages/home/setting/setting_logic.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:get/get.dart'; import 'package:mood_diary/components/dashboard/dashboard_logic.dart'; @@ -17,9 +16,6 @@ class SettingLogic extends GetxController { final SettingState state = SettingState(); late final homeLogic = Bind.find(); - late TextEditingController textEditingController = - TextEditingController(text: state.customTitle); - @override void onInit() { super.onInit(); @@ -33,7 +29,6 @@ class SettingLogic extends GetxController { @override void onClose() { - textEditingController.dispose(); super.onClose(); } @@ -124,20 +119,10 @@ class SettingLogic extends GetxController { Get.toNamed(AppRoutes.backupSyncPage); } - void cancelCustomTitle() { - textEditingController.clear(); - Get.backLegacy(); - } - - Future setCustomTitle() async { - if (textEditingController.text.isNotEmpty) { - state.customTitle = textEditingController.text; - update(['CustomTitle']); - await PrefUtil.setValue( - 'customTitleName', textEditingController.text); - Get.backLegacy(); - textEditingController.clear(); - Bind.find().updateTitle(); - } + Future setCustomTitle({required String title}) async { + state.customTitle = title.trim(); + update(['CustomTitle']); + await PrefUtil.setValue('customTitleName', state.customTitle); + Bind.find().updateTitle(); } } diff --git a/lib/pages/home/setting/setting_view.dart b/lib/pages/home/setting/setting_view.dart index 8199dd0..43d0af7 100644 --- a/lib/pages/home/setting/setting_view.dart +++ b/lib/pages/home/setting/setting_view.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; @@ -44,7 +45,9 @@ class SettingPage extends StatelessWidget { icon, Text( text, - style: textStyle.labelSmall, + style: textStyle.labelSmall?.copyWith( + color: colorScheme.onSurface, + ), ) ], ), @@ -108,23 +111,23 @@ class SettingPage extends StatelessWidget { children: [ ListTile( title: Text(l10n.settingRecycle), - trailing: const Icon(Icons.chevron_right), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toRecyclePage(); }, - leading: const Icon(Icons.delete_outline), + leading: const Icon(Icons.delete_rounded), ), ListTile( title: const Text('备份与同步'), - trailing: const Icon(Icons.chevron_right), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toBackupAndSyncPage(); }, - leading: const Icon(Icons.sync), + leading: const Icon(Icons.sync_rounded), ), ListTile( title: Text(l10n.settingClean), - leading: const Icon(Icons.cleaning_services_outlined), + leading: const Icon(Icons.cleaning_services_rounded), trailing: GetBuilder( id: 'DataUsage', builder: (_) { @@ -156,15 +159,15 @@ class SettingPage extends StatelessWidget { children: [ ListTile( title: Text(l10n.settingDiary), - leading: const Icon(Icons.article_outlined), - trailing: const Icon(Icons.chevron_right), + leading: const Icon(Icons.article_rounded), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toDiarySettingPage(); }, ), ListTile( title: Text(l10n.settingThemeMode), - leading: const Icon(Icons.invert_colors), + leading: const Icon(Icons.invert_colors_rounded), trailing: Text( switch (state.themeMode) { 0 => l10n.themeModeSystem, @@ -186,7 +189,7 @@ class SettingPage extends StatelessWidget { ), ListTile( title: Text(l10n.settingColor), - leading: const Icon(Icons.color_lens_outlined), + leading: const Icon(Icons.color_lens_rounded), trailing: Text( AppColor.colorName(state.color), style: textStyle.bodySmall!.copyWith( @@ -199,24 +202,19 @@ class SettingPage extends StatelessWidget { builder: (context) { return const ColorSheetComponent(); }); - // showDialog( - // context: context, - // builder: (context) { - // return const ColorDialogComponent(); - // }); }, ), ListTile( title: Text(l10n.settingFontStyle), - leading: const Icon(Icons.format_size_outlined), - trailing: const Icon(Icons.chevron_right), + leading: const Icon(Icons.format_size_rounded), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toFontSizePage(); }, ), ListTile( - title: const Text('自定义首页名称'), - leading: const Icon(Icons.drive_file_rename_outline), + title: const Text('首页名称'), + leading: const Icon(Icons.drive_file_rename_outline_rounded), trailing: GetBuilder( id: 'CustomTitle', builder: (_) { @@ -227,39 +225,20 @@ class SettingPage extends StatelessWidget { ), ); }), - onTap: () { - showDialog( - context: context, - builder: (context) { - return AlertDialog( - content: TextField( - maxLines: 1, - controller: logic.textEditingController, - decoration: InputDecoration( - fillColor: colorScheme.secondaryContainer, - border: const UnderlineInputBorder( - borderRadius: - AppBorderRadius.smallBorderRadius, - borderSide: BorderSide.none, - ), - filled: true, - labelText: '名称', - ), - ), - actions: [ - TextButton( - onPressed: () { - logic.cancelCustomTitle(); - }, - child: Text(l10n.cancel)), - TextButton( - onPressed: () async { - await logic.setCustomTitle(); - }, - child: Text(l10n.ok)) - ], - ); - }); + onTap: () async { + var res = await showTextInputDialog( + context: context, + textFields: [ + DialogTextField( + hintText: '名称', + initialText: state.customTitle, + ) + ], + title: '首页名称', + ); + if (res != null) { + logic.setCustomTitle(title: res.first); + } }, ) ], @@ -277,17 +256,17 @@ class SettingPage extends StatelessWidget { color: colorScheme.surfaceContainerLow, child: Column( children: [ - GetBuilder( - id: 'Local', - builder: (_) { - return SwitchListTile( - value: state.local, - onChanged: null, - title: Text(l10n.settingLocal), - subtitle: Text(l10n.settingLocalDes), - secondary: const Icon(Icons.cloud_off_outlined), - ); - }), + // GetBuilder( + // id: 'Local', + // builder: (_) { + // return SwitchListTile( + // value: state.local, + // onChanged: null, + // title: Text(l10n.settingLocal), + // subtitle: Text(l10n.settingLocalDes), + // secondary: const Icon(Icons.cloud_off_rounded), + // ); + // }), GetBuilder( id: 'Lock', builder: (_) { @@ -328,7 +307,7 @@ class SettingPage extends StatelessWidget { }); }, title: Text(l10n.settingLock), - leading: const Icon(Icons.lock_outline), + leading: const Icon(Icons.lock_rounded), ); }), GetBuilder( @@ -343,7 +322,7 @@ class SettingPage extends StatelessWidget { : null, title: Text(l10n.settingLockNow), subtitle: Text(l10n.settingLockNowDes), - secondary: const Icon(Icons.lock_clock_outlined), + secondary: const Icon(Icons.lock_clock_rounded), ); }), ], @@ -363,16 +342,16 @@ class SettingPage extends StatelessWidget { children: [ ListTile( title: Text(l10n.settingAbout), - leading: const Icon(Icons.info_outline), - trailing: const Icon(Icons.chevron_right), + leading: const Icon(Icons.info_rounded), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toAboutPage(); }, ), ListTile( title: Text(l10n.settingLab), - leading: const Icon(Icons.science_outlined), - trailing: const Icon(Icons.chevron_right), + leading: const Icon(Icons.science_rounded), + trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toLaboratoryPage(); }, @@ -389,7 +368,10 @@ class SettingPage extends StatelessWidget { builder: (_) { return Column( children: [ - AppBar(title: Text(l10n.homeNavigatorSetting)), + AppBar( + title: Text(l10n.homeNavigatorSetting), + centerTitle: false, + ), Expanded( child: ListView( cacheExtent: size.height * 2, diff --git a/lib/pages/lock/lock_view.dart b/lib/pages/lock/lock_view.dart index aa4cfd6..919b5c4 100644 --- a/lib/pages/lock/lock_view.dart +++ b/lib/pages/lock/lock_view.dart @@ -60,7 +60,7 @@ class LockPage extends StatelessWidget { } }, child: const Icon( - Icons.fingerprint, + Icons.fingerprint_rounded, ), ), ); @@ -83,65 +83,63 @@ class LockPage extends StatelessWidget { }); } - return GetBuilder( - builder: (_) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - ), - body: Center( - child: Column( - spacing: 16.0, - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(Icons.lock), - Text( - '请输入密码', - style: textStyle.titleMedium, - ), - AnimatedBuilder( - animation: logic.animation, - builder: (context, child) { - return Transform.translate( - offset: - Offset(logic.interpolate(logic.animation.value), 0), - child: Wrap( - spacing: 16.0, - children: buildPasswordIndicator(), - ), - ); - }, - ), - SizedBox( - width: buttonSize * 3 + 20, - height: buttonSize * 4 + 30, - child: GridView.count( - crossAxisCount: 3, - childAspectRatio: 1.0, - crossAxisSpacing: 10, - mainAxisSpacing: 10, - physics: const NeverScrollableScrollPhysics(), - children: [ - buildNumButton('1'), - buildNumButton('2'), - buildNumButton('3'), - buildNumButton('4'), - buildNumButton('5'), - buildNumButton('6'), - buildNumButton('7'), - buildNumButton('8'), - buildNumButton('9'), - buildBiometricsButton(), - buildNumButton('0'), - buildDeleteButton() - ], - ), + return PopScope( + canPop: false, + child: Scaffold( + appBar: AppBar( + automaticallyImplyLeading: false, + ), + body: Center( + child: Column( + spacing: 16.0, + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(Icons.lock), + Text( + '请输入密码', + style: textStyle.titleMedium, + ), + AnimatedBuilder( + animation: logic.animation, + builder: (context, child) { + return Transform.translate( + offset: Offset(logic.interpolate(logic.animation.value), 0), + child: Wrap( + spacing: 16.0, + children: buildPasswordIndicator(), + ), + ); + }, + ), + SizedBox( + width: buttonSize * 3 + 20, + height: buttonSize * 4 + 30, + child: GridView.count( + crossAxisCount: 3, + childAspectRatio: 1.0, + crossAxisSpacing: 10, + mainAxisSpacing: 10, + physics: const NeverScrollableScrollPhysics(), + children: [ + buildNumButton('1'), + buildNumButton('2'), + buildNumButton('3'), + buildNumButton('4'), + buildNumButton('5'), + buildNumButton('6'), + buildNumButton('7'), + buildNumButton('8'), + buildNumButton('9'), + buildBiometricsButton(), + buildNumButton('0'), + buildDeleteButton() + ], ), - ], - ), + ), + ], ), - ); - }, + ), + ), ); } } diff --git a/lib/pages/sponsor/sponsor_logic.dart b/lib/pages/sponsor/sponsor_logic.dart new file mode 100644 index 0000000..95fb879 --- /dev/null +++ b/lib/pages/sponsor/sponsor_logic.dart @@ -0,0 +1,7 @@ +import 'package:get/get.dart'; + +class SponsorLogic extends GetxController { + + + +} diff --git a/lib/pages/sponsor/sponsor_view.dart b/lib/pages/sponsor/sponsor_view.dart new file mode 100644 index 0000000..8b27fe6 --- /dev/null +++ b/lib/pages/sponsor/sponsor_view.dart @@ -0,0 +1,41 @@ +import 'package:confetti/confetti.dart'; +import 'package:flutter/material.dart'; +import 'package:get/get.dart'; + +import 'sponsor_logic.dart'; + +class SponsorPage extends StatelessWidget { + const SponsorPage({super.key}); + + Widget _buildWechat() { + return Image.asset('res/sponsor/wechat.jpg'); + } + + @override + Widget build(BuildContext context) { + final SponsorLogic logic = Get.put(SponsorLogic()); + + return Scaffold( + appBar: AppBar( + title: const Text('捐助'), + ), + body: Center( + child: ConfettiWidget( + confettiController: + ConfettiController(duration: Duration(seconds: 1)), + blastDirectionality: BlastDirectionality.explosive, + shouldLoop: true, + colors: const [ + Colors.green, + Colors.blue, + Colors.yellow, + Colors.red, + ], + child: Container( + child: Text('庆祝一下!'), + ), + ), + ), + ); + } +} diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart index 171c2bc..d15f4c1 100644 --- a/lib/router/app_pages.dart +++ b/lib/router/app_pages.dart @@ -37,6 +37,7 @@ import 'package:mood_diary/pages/recycle/recycle_logic.dart'; import 'package:mood_diary/pages/recycle/recycle_view.dart'; import 'package:mood_diary/pages/share/share_logic.dart'; import 'package:mood_diary/pages/share/share_view.dart'; +import 'package:mood_diary/pages/sponsor/sponsor_view.dart'; import 'package:mood_diary/pages/start/start_logic.dart'; import 'package:mood_diary/pages/start/start_view.dart'; import 'package:mood_diary/pages/user/user_logic.dart'; @@ -44,6 +45,7 @@ import 'package:mood_diary/pages/user/user_view.dart'; import 'package:mood_diary/pages/video/video_logic.dart'; import 'package:mood_diary/pages/video/video_view.dart'; +import '../pages/sponsor/sponsor_logic.dart'; import 'app_routes.dart'; class AppPages { @@ -60,9 +62,7 @@ class AppPages { name: AppRoutes.homePage, page: () => const HomePage(), transition: Transition.fadeIn, - binds: [ - Bind.lazyPut(() => HomeLogic()), - ], + binds: [Bind.lazyPut(() => HomeLogic())], ), //分析 GetPage( @@ -73,7 +73,6 @@ class AppPages { //日记页路由 GetPage( name: AppRoutes.diaryPage, - //transition: Transition.topLevel, page: () => DiaryDetailsPage(), ), //图片路由 @@ -81,7 +80,6 @@ class AppPages { name: AppRoutes.photoPage, page: () => const ImagePage(), popGesture: false, - //transition: Transition.topLevel, binds: [Bind.lazyPut(() => ImageLogic())], ), //回收站 @@ -100,7 +98,6 @@ class AppPages { GetPage( name: AppRoutes.editPage, page: () => const EditPage(), - transition: Transition.fadeIn, binds: [Bind.lazyPut(() => EditLogic())], ), //分享页路由 @@ -164,7 +161,6 @@ class AppPages { name: AppRoutes.videoPage, popGesture: false, page: () => const VideoPage(), - // transition: Transition.topLevel, binds: [Bind.lazyPut(() => VideoLogic())], ), GetPage( @@ -187,5 +183,10 @@ class AppPages { page: () => const AssistantPage(), binds: [Bind.lazyPut(() => AssistantLogic())], ), + GetPage( + name: AppRoutes.sponsorPage, + page: () => const SponsorPage(), + binds: [Bind.lazyPut(() => SponsorLogic())], + ), ]; } diff --git a/lib/router/app_routes.dart b/lib/router/app_routes.dart index 07f975d..0b2c297 100644 --- a/lib/router/app_routes.dart +++ b/lib/router/app_routes.dart @@ -72,4 +72,7 @@ abstract class AppRoutes { //备份与同步页 static const backupSyncPage = '/backupSync'; + + //捐助页 + static const sponsorPage = '/sponsor'; } diff --git a/lib/src/rust/api/compress.dart b/lib/src/rust/api/compress.dart index 12e5623..6287840 100644 --- a/lib/src/rust/api/compress.dart +++ b/lib/src/rust/api/compress.dart @@ -3,10 +3,9 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - import '../frb_generated.dart'; import 'constants.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; // These functions are ignored because they are not marked as `pub`: `calculate_target_dimensions`, `load_image` diff --git a/lib/src/rust/api/constants.dart b/lib/src/rust/api/constants.dart index 0d68c66..fb5f738 100644 --- a/lib/src/rust/api/constants.dart +++ b/lib/src/rust/api/constants.dart @@ -3,9 +3,8 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - import '../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; // These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_receiver_is_total_eq`, `eq` diff --git a/lib/src/rust/api/font.dart b/lib/src/rust/api/font.dart index 7cfd04a..71a1eaa 100644 --- a/lib/src/rust/api/font.dart +++ b/lib/src/rust/api/font.dart @@ -3,13 +3,17 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - import '../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; // Rust type: RustOpaqueMoi> abstract class FontReader implements RustOpaqueInterface { static Future getFontNameFromTtf({required String ttfFilePath}) => RustLib.instance.api .crateApiFontFontReaderGetFontNameFromTtf(ttfFilePath: ttfFilePath); + + static Future> getWghtAxisFromVfFont( + {required String ttfFilePath}) => + RustLib.instance.api.crateApiFontFontReaderGetWghtAxisFromVfFont( + ttfFilePath: ttfFilePath); } diff --git a/lib/src/rust/api/kmp.dart b/lib/src/rust/api/kmp.dart index bcde6f1..cfaa03f 100644 --- a/lib/src/rust/api/kmp.dart +++ b/lib/src/rust/api/kmp.dart @@ -3,9 +3,8 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - import '../frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; Future buildPrefixTable({required List pattern}) => RustLib.instance.api.crateApiKmpBuildPrefixTable(pattern: pattern); diff --git a/lib/src/rust/frb_generated.dart b/lib/src/rust/frb_generated.dart index cf18534..0c08d64 100644 --- a/lib/src/rust/frb_generated.dart +++ b/lib/src/rust/frb_generated.dart @@ -3,18 +3,16 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; - import 'api/compress.dart'; import 'api/constants.dart'; import 'api/font.dart'; import 'api/kmp.dart'; +import 'dart:async'; +import 'dart:convert'; import 'frb_generated.dart'; import 'frb_generated.io.dart' - if (dart.library.js_interop) 'frb_generated.webated.dart'; + if (dart.library.js_interop) 'frb_generated.web.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; /// Main entrypoint of the Rust API class RustLib extends BaseEntrypoint { @@ -71,7 +69,7 @@ class RustLib extends BaseEntrypoint { String get codegenVersion => '2.7.0'; @override - int get rustContentHash => -1743857995; + int get rustContentHash => 376160798; static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig( @@ -85,6 +83,9 @@ abstract class RustLibApi extends BaseApi { Future crateApiFontFontReaderGetFontNameFromTtf( {required String ttfFilePath}); + Future> crateApiFontFontReaderGetWghtAxisFromVfFont( + {required String ttfFilePath}); + Future crateApiCompressImageCompressContain( {required String filePath, CompressFormat? compressFormat, @@ -177,6 +178,32 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { argNames: ["ttfFilePath"], ); + @override + Future> crateApiFontFontReaderGetWghtAxisFromVfFont( + {required String ttfFilePath}) { + return handler.executeNormal(NormalTask( + callFfi: (port_) { + final serializer = SseSerializer(generalizedFrbRustBinding); + sse_encode_String(ttfFilePath, serializer); + pdeCallFfi(generalizedFrbRustBinding, serializer, + funcId: 2, port: port_); + }, + codec: SseCodec( + decodeSuccessData: sse_decode_Map_String_f_32, + decodeErrorData: null, + ), + constMeta: kCrateApiFontFontReaderGetWghtAxisFromVfFontConstMeta, + argValues: [ttfFilePath], + apiImpl: this, + )); + } + + TaskConstMeta get kCrateApiFontFontReaderGetWghtAxisFromVfFontConstMeta => + const TaskConstMeta( + debugName: "FontReader_get_wght_axis_from_vf_font", + argNames: ["ttfFilePath"], + ); + @override Future crateApiCompressImageCompressContain( {required String filePath, @@ -193,7 +220,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_opt_box_autoadd_i_32(maxHeight, serializer); sse_encode_opt_box_autoadd_u_8(quality, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 2, port: port_); + funcId: 3, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_list_prim_u_8_strict, @@ -226,7 +253,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_String(text, serializer); sse_encode_list_String(patterns, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 3, port: port_); + funcId: 4, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_list_String, @@ -252,7 +279,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_String(text, serializer); sse_encode_Map_String_String(replacements, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 4, port: port_); + funcId: 5, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_String, @@ -278,7 +305,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { final serializer = SseSerializer(generalizedFrbRustBinding); sse_encode_list_Char(pattern, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 5, port: port_); + funcId: 6, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_list_prim_usize_strict, @@ -313,7 +340,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_compress_format(compressFormat, serializer); sse_encode_u_8(quality, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 6, port: port_); + funcId: 7, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_list_prim_u_8_strict, @@ -339,7 +366,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_String(text, serializer); sse_encode_String(pattern, serializer); pdeCallFfi(generalizedFrbRustBinding, serializer, - funcId: 7, port: port_); + funcId: 8, port: port_); }, codec: SseCodec( decodeSuccessData: sse_decode_list_prim_usize_strict, @@ -436,6 +463,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { .map((e) => MapEntry(e.$1, e.$2))); } + @protected + Map dco_decode_Map_String_f_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return Map.fromEntries(dco_decode_list_record_string_f_32(raw) + .map((e) => MapEntry(e.$1, e.$2))); + } + @protected DynamicImage dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -497,6 +531,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return CompressFormat.values[raw as int]; } + @protected + double dco_decode_f_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return raw as double; + } + @protected int dco_decode_i_32(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -527,6 +567,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw as Uint64List; } + @protected + List<(String, double)> dco_decode_list_record_string_f_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + return (raw as List).map(dco_decode_record_string_f_32).toList(); + } + @protected List<(String, String)> dco_decode_list_record_string_string(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -557,6 +603,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return raw == null ? null : dco_decode_box_autoadd_u_8(raw); } + @protected + (String, double) dco_decode_record_string_f_32(dynamic raw) { + // Codec=Dco (DartCObject based), see doc to use other codecs + final arr = raw as List; + if (arr.length != 2) { + throw Exception('Expected 2 elements, got ${arr.length}'); + } + return ( + dco_decode_String(arr[0]), + dco_decode_f_32(arr[1]), + ); + } + @protected (String, String) dco_decode_record_string_string(dynamic raw) { // Codec=Dco (DartCObject based), see doc to use other codecs @@ -651,6 +710,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return Map.fromEntries(inner.map((e) => MapEntry(e.$1, e.$2))); } + @protected + Map sse_decode_Map_String_f_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var inner = sse_decode_list_record_string_f_32(deserializer); + return Map.fromEntries(inner.map((e) => MapEntry(e.$1, e.$2))); + } + @protected DynamicImage sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -719,6 +785,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return CompressFormat.values[inner]; } + @protected + double sse_decode_f_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + return deserializer.buffer.getFloat32(); + } + @protected int sse_decode_i_32(SseDeserializer deserializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -763,6 +835,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { return deserializer.buffer.getUint64List(len_); } + @protected + List<(String, double)> sse_decode_list_record_string_f_32( + SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + + var len_ = sse_decode_i_32(deserializer); + var ans_ = <(String, double)>[]; + for (var idx_ = 0; idx_ < len_; ++idx_) { + ans_.add(sse_decode_record_string_f_32(deserializer)); + } + return ans_; + } + @protected List<(String, String)> sse_decode_list_record_string_string( SseDeserializer deserializer) { @@ -821,6 +906,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + (String, double) sse_decode_record_string_f_32(SseDeserializer deserializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + var var_field0 = sse_decode_String(deserializer); + var var_field1 = sse_decode_f_32(deserializer); + return (var_field0, var_field1); + } + @protected (String, String) sse_decode_record_string_string( SseDeserializer deserializer) { @@ -918,6 +1011,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { self.entries.map((e) => (e.key, e.value)).toList(), serializer); } + @protected + void sse_encode_Map_String_f_32( + Map self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_list_record_string_f_32( + self.entries.map((e) => (e.key, e.value)).toList(), serializer); + } + @protected void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -988,6 +1089,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { sse_encode_i_32(self.index, serializer); } + @protected + void sse_encode_f_32(double self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + serializer.buffer.putFloat32(self); + } + @protected void sse_encode_i_32(int self, SseSerializer serializer) { // Codec=Sse (Serialization based), see doc to use other codecs @@ -1028,6 +1135,16 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { serializer.buffer.putUint64List(self); } + @protected + void sse_encode_list_record_string_f_32( + List<(String, double)> self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_i_32(self.length, serializer); + for (final item in self) { + sse_encode_record_string_f_32(item, serializer); + } + } + @protected void sse_encode_list_record_string_string( List<(String, String)> self, SseSerializer serializer) { @@ -1079,6 +1196,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi { } } + @protected + void sse_encode_record_string_f_32( + (String, double) self, SseSerializer serializer) { + // Codec=Sse (Serialization based), see doc to use other codecs + sse_encode_String(self.$1, serializer); + sse_encode_f_32(self.$2, serializer); + } + @protected void sse_encode_record_string_string( (String, String) self, SseSerializer serializer) { diff --git a/lib/src/rust/frb_generated.io.dart b/lib/src/rust/frb_generated.io.dart index bf162ae..9a60958 100644 --- a/lib/src/rust/frb_generated.io.dart +++ b/lib/src/rust/frb_generated.io.dart @@ -3,17 +3,15 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field -import 'dart:async'; -import 'dart:convert'; -import 'dart:ffi' as ffi; - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; - import 'api/compress.dart'; import 'api/constants.dart'; import 'api/font.dart'; import 'api/kmp.dart'; +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi' as ffi; import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { RustLibApiImplPlatform({ @@ -65,6 +63,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Map dco_decode_Map_String_String(dynamic raw); + @protected + Map dco_decode_Map_String_f_32(dynamic raw); + @protected DynamicImage dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -99,6 +100,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected CompressFormat dco_decode_compress_format(dynamic raw); + @protected + double dco_decode_f_32(dynamic raw); + @protected int dco_decode_i_32(dynamic raw); @@ -114,6 +118,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint64List dco_decode_list_prim_usize_strict(dynamic raw); + @protected + List<(String, double)> dco_decode_list_record_string_f_32(dynamic raw); + @protected List<(String, String)> dco_decode_list_record_string_string(dynamic raw); @@ -129,6 +136,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int? dco_decode_opt_box_autoadd_u_8(dynamic raw); + @protected + (String, double) dco_decode_record_string_f_32(dynamic raw); + @protected (String, String) dco_decode_record_string_string(dynamic raw); @@ -173,6 +183,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { Map sse_decode_Map_String_String( SseDeserializer deserializer); + @protected + Map sse_decode_Map_String_f_32(SseDeserializer deserializer); + @protected DynamicImage sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -208,6 +221,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected CompressFormat sse_decode_compress_format(SseDeserializer deserializer); + @protected + double sse_decode_f_32(SseDeserializer deserializer); + @protected int sse_decode_i_32(SseDeserializer deserializer); @@ -223,6 +239,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint64List sse_decode_list_prim_usize_strict(SseDeserializer deserializer); + @protected + List<(String, double)> sse_decode_list_record_string_f_32( + SseDeserializer deserializer); + @protected List<(String, String)> sse_decode_list_record_string_string( SseDeserializer deserializer); @@ -240,6 +260,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int? sse_decode_opt_box_autoadd_u_8(SseDeserializer deserializer); + @protected + (String, double) sse_decode_record_string_f_32(SseDeserializer deserializer); + @protected (String, String) sse_decode_record_string_string( SseDeserializer deserializer); @@ -290,6 +313,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_Map_String_String( Map self, SseSerializer serializer); + @protected + void sse_encode_Map_String_f_32( + Map self, SseSerializer serializer); + @protected void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -327,6 +354,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_compress_format( CompressFormat self, SseSerializer serializer); + @protected + void sse_encode_f_32(double self, SseSerializer serializer); + @protected void sse_encode_i_32(int self, SseSerializer serializer); @@ -344,6 +374,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_list_prim_usize_strict( Uint64List self, SseSerializer serializer); + @protected + void sse_encode_list_record_string_f_32( + List<(String, double)> self, SseSerializer serializer); + @protected void sse_encode_list_record_string_string( List<(String, String)> self, SseSerializer serializer); @@ -361,6 +395,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_opt_box_autoadd_u_8(int? self, SseSerializer serializer); + @protected + void sse_encode_record_string_f_32( + (String, double) self, SseSerializer serializer); + @protected void sse_encode_record_string_string( (String, String) self, SseSerializer serializer); diff --git a/lib/src/rust/frb_generated.web.dart b/lib/src/rust/frb_generated.web.dart index 5d1e514..e9969af 100644 --- a/lib/src/rust/frb_generated.web.dart +++ b/lib/src/rust/frb_generated.web.dart @@ -6,16 +6,14 @@ // Static analysis wrongly picks the IO variant, thus ignore this // ignore_for_file: argument_type_not_assignable -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; - import 'api/compress.dart'; import 'api/constants.dart'; import 'api/font.dart'; import 'api/kmp.dart'; +import 'dart:async'; +import 'dart:convert'; import 'frb_generated.dart'; +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { RustLibApiImplPlatform({ @@ -67,6 +65,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Map dco_decode_Map_String_String(dynamic raw); + @protected + Map dco_decode_Map_String_f_32(dynamic raw); + @protected DynamicImage dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -101,6 +102,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected CompressFormat dco_decode_compress_format(dynamic raw); + @protected + double dco_decode_f_32(dynamic raw); + @protected int dco_decode_i_32(dynamic raw); @@ -116,6 +120,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint64List dco_decode_list_prim_usize_strict(dynamic raw); + @protected + List<(String, double)> dco_decode_list_record_string_f_32(dynamic raw); + @protected List<(String, String)> dco_decode_list_record_string_string(dynamic raw); @@ -131,6 +138,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int? dco_decode_opt_box_autoadd_u_8(dynamic raw); + @protected + (String, double) dco_decode_record_string_f_32(dynamic raw); + @protected (String, String) dco_decode_record_string_string(dynamic raw); @@ -175,6 +185,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { Map sse_decode_Map_String_String( SseDeserializer deserializer); + @protected + Map sse_decode_Map_String_f_32(SseDeserializer deserializer); + @protected DynamicImage sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -210,6 +223,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected CompressFormat sse_decode_compress_format(SseDeserializer deserializer); + @protected + double sse_decode_f_32(SseDeserializer deserializer); + @protected int sse_decode_i_32(SseDeserializer deserializer); @@ -225,6 +241,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected Uint64List sse_decode_list_prim_usize_strict(SseDeserializer deserializer); + @protected + List<(String, double)> sse_decode_list_record_string_f_32( + SseDeserializer deserializer); + @protected List<(String, String)> sse_decode_list_record_string_string( SseDeserializer deserializer); @@ -242,6 +262,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected int? sse_decode_opt_box_autoadd_u_8(SseDeserializer deserializer); + @protected + (String, double) sse_decode_record_string_f_32(SseDeserializer deserializer); + @protected (String, String) sse_decode_record_string_string( SseDeserializer deserializer); @@ -292,6 +315,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_Map_String_String( Map self, SseSerializer serializer); + @protected + void sse_encode_Map_String_f_32( + Map self, SseSerializer serializer); + @protected void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerDynamicImage( @@ -329,6 +356,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_compress_format( CompressFormat self, SseSerializer serializer); + @protected + void sse_encode_f_32(double self, SseSerializer serializer); + @protected void sse_encode_i_32(int self, SseSerializer serializer); @@ -346,6 +376,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { void sse_encode_list_prim_usize_strict( Uint64List self, SseSerializer serializer); + @protected + void sse_encode_list_record_string_f_32( + List<(String, double)> self, SseSerializer serializer); + @protected void sse_encode_list_record_string_string( List<(String, String)> self, SseSerializer serializer); @@ -363,6 +397,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl { @protected void sse_encode_opt_box_autoadd_u_8(int? self, SseSerializer serializer); + @protected + void sse_encode_record_string_f_32( + (String, double) self, SseSerializer serializer); + @protected void sse_encode_record_string_string( (String, String) self, SseSerializer serializer); diff --git a/lib/utils/data/isar.dart b/lib/utils/data/isar.dart index 069d572..4dee210 100644 --- a/lib/utils/data/isar.dart +++ b/lib/utils/data/isar.dart @@ -106,6 +106,11 @@ class IsarUtil { return await _isar.diarys.where().findAllAsync(); } + /// 获取全部日记 + static Future> getAllDiariesSorted() async { + return _isar.diarys.where().sortByTimeDesc().findAllAsync(); + } + //获取指定范围内的天气 static Future>> getWeatherByDateRange( DateTime start, DateTime end) async { diff --git a/lib/utils/http_util.dart b/lib/utils/http_util.dart index 867b98a..57ad5df 100644 --- a/lib/utils/http_util.dart +++ b/lib/utils/http_util.dart @@ -10,7 +10,7 @@ import 'notice_util.dart'; class HttpUtil { Dio? _dio; - final bool _enableLogging = kDebugMode; + final bool _enableLogging = false; Dio get dio { if (_dio == null) { diff --git a/lib/utils/package_util.dart b/lib/utils/package_util.dart index d719ed3..cac28c4 100644 --- a/lib/utils/package_util.dart +++ b/lib/utils/package_util.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:device_info_plus/device_info_plus.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -9,6 +11,21 @@ class PackageUtil { static Future getInfo() async { DeviceInfoPlugin deviceInfoPlugin = DeviceInfoPlugin(); + if (Platform.isAndroid) { + return await deviceInfoPlugin.androidInfo; + } + if (Platform.isIOS) { + return await deviceInfoPlugin.iosInfo; + } + if (Platform.isMacOS) { + return await deviceInfoPlugin.macOsInfo; + } + if (Platform.isWindows) { + return await deviceInfoPlugin.windowsInfo; + } + if (Platform.isLinux) { + return await deviceInfoPlugin.linuxInfo; + } return await deviceInfoPlugin.deviceInfo; } } diff --git a/lib/utils/theme_util.dart b/lib/utils/theme_util.dart index 8522213..a7b94e1 100644 --- a/lib/utils/theme_util.dart +++ b/lib/utils/theme_util.dart @@ -1,13 +1,16 @@ import 'package:chinese_font_library/chinese_font_library.dart'; import 'package:dynamic_color/dynamic_color.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/internal.dart'; -import 'package:mood_diary/common/values/colors.dart'; +import '../common/values/colors.dart'; import '../src/rust/api/font.dart'; import 'data/pref.dart'; +final Set loadedFonts = {}; + class ThemeUtil { static Future supportDynamicColor() async { return (await DynamicColorPlugin.getCorePalette()) != null; @@ -17,6 +20,139 @@ class ThemeUtil { return Color((await DynamicColorPlugin.getCorePalette())!.primary.get(40)); } + static Map _unifyFontWeights( + Map fontWeights) { + // 标准 + final regular = fontWeights['default'] ?? 400; + // 名称映射表:将各种名称映射到统一的标准名称 + const Map nameMapping = { + "Thin": "Thin", + "Hairline": "Thin", + "ExtraLight": "ExtraLight", + "UltraLight": "ExtraLight", + "Light": "Light", + "Normal": "Regular", + "Regular": "Regular", + "Book": "Regular", + "Medium": "Medium", + "Demibold": "SemiBold", + "DemiBold": "SemiBold", + "Semibold": "SemiBold", + "SemiBold": "SemiBold", + "Bold": "Bold", + "Heavy": "Bold", + "ExtraBold": "ExtraBold", + "UltraBold": "ExtraBold", + "Black": "Black", + "HeavyBlack": "Black", + "ExtraBlack": "Black", + }; + + Map unified = {}; + + for (var entry in fontWeights.entries) { + String originalName = entry.key; + double weight = entry.value; + String unifiedName = nameMapping[originalName] ?? originalName; + + if (unified.containsKey(unifiedName)) { + double existingWeight = unified[unifiedName]!; + unified[unifiedName] = + (weight - regular).abs() < (existingWeight - regular).abs() + ? weight + : existingWeight; + } else { + unified[unifiedName] = weight; + } + } + return unified; + } + + static TextTheme _applyFontVariations(TextTheme baseTheme, String? fontFamily, + {required Map wghtAxisMap}) { + var regularFontWeight = wghtAxisMap['Regular'] ?? 400; + var mediumFontWeight = wghtAxisMap['Medium'] ?? 500; + var semiBoldFontWeight = wghtAxisMap['SemiBold'] ?? 600; + var boldFontWeight = wghtAxisMap['Bold'] ?? 700; + return baseTheme.copyWith( + displayLarge: baseTheme.displayLarge?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + displayMedium: baseTheme.displayMedium?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + displaySmall: baseTheme.displaySmall?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + headlineLarge: baseTheme.headlineLarge?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w700, + fontVariations: [FontVariation('wght', boldFontWeight)], + ), + headlineMedium: baseTheme.headlineMedium?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w600, + fontVariations: [FontVariation('wght', semiBoldFontWeight)], + ), + headlineSmall: baseTheme.headlineSmall?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + titleLarge: baseTheme.titleLarge?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w600, + fontVariations: [FontVariation('wght', semiBoldFontWeight)], + ), + titleMedium: baseTheme.titleMedium?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + titleSmall: baseTheme.titleSmall?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + bodyLarge: baseTheme.bodyLarge?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w400, + fontVariations: [FontVariation('wght', regularFontWeight)], + ), + bodyMedium: baseTheme.bodyMedium?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w400, + fontVariations: [FontVariation('wght', regularFontWeight)], + ), + bodySmall: baseTheme.bodySmall?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w400, + fontVariations: [FontVariation('wght', regularFontWeight)], + ), + labelLarge: baseTheme.labelLarge?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + labelMedium: baseTheme.labelMedium?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w500, + fontVariations: [FontVariation('wght', mediumFontWeight)], + ), + labelSmall: baseTheme.labelSmall?.copyWith( + fontFamily: fontFamily, + fontWeight: FontWeight.w400, + fontVariations: [FontVariation('wght', regularFontWeight)], + ), + ); + } + static Future buildTheme(Brightness brightness) async { final color = PrefUtil.getValue('color')!; var seedColor = (color == -1) @@ -26,139 +162,56 @@ class ThemeUtil { final customFont = PrefUtil.getValue('customFont')!; String? fontFamily; + Map wghtAxisMap = {}; // 加载自定义字体 if (customFont.isNotEmpty) { fontFamily = await FontReader.getFontNameFromTtf(ttfFilePath: customFont); if (fontFamily != null) { - await DynamicFont.file(fontFamily: fontFamily, filepath: customFont) - .load(); + if (!loadedFonts.contains(fontFamily)) { + var res = await DynamicFont.file( + fontFamily: fontFamily, filepath: customFont) + .load(); + if (res) loadedFonts.add(fontFamily); + } + wghtAxisMap = _unifyFontWeights( + await FontReader.getWghtAxisFromVfFont(ttfFilePath: customFont)); } } - // 字体变体应用到 TextTheme 的函数 - TextTheme applyFontVariations(TextTheme baseTheme, String? fontFamily) { - const fontVariation = FontVariation('wght', 400); - return baseTheme.copyWith( - displayLarge: baseTheme.displayLarge - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - displayMedium: baseTheme.displayMedium - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - displaySmall: baseTheme.displaySmall - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - headlineLarge: baseTheme.headlineLarge?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 500)]), - headlineMedium: baseTheme.headlineMedium?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 500)]), - headlineSmall: baseTheme.headlineSmall?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 500)]), - titleLarge: baseTheme.titleLarge?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 600)]), - titleMedium: baseTheme.titleMedium?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 500)]), - titleSmall: baseTheme.titleSmall - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - bodyLarge: baseTheme.bodyLarge - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - bodyMedium: baseTheme.bodyMedium - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - bodySmall: baseTheme.bodySmall?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 300)]), - labelLarge: baseTheme.labelLarge?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 500)]), - labelMedium: baseTheme.labelMedium - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - labelSmall: baseTheme.labelSmall?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 300)]), - ); - } - TextTheme applyMiSansFontVariations( - TextTheme baseTheme, String? fontFamily) { - const fontVariation = FontVariation('wght', 330); - return baseTheme.copyWith( - displayLarge: baseTheme.displayLarge - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - displayMedium: baseTheme.displayMedium - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - displaySmall: baseTheme.displaySmall - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - headlineLarge: baseTheme.headlineLarge?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 380)]), - headlineMedium: baseTheme.headlineMedium?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 380)]), - headlineSmall: baseTheme.headlineSmall?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 380)]), - titleLarge: baseTheme.titleLarge?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 520)]), - titleMedium: baseTheme.titleMedium?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 520)]), - titleSmall: baseTheme.titleSmall - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - bodyLarge: baseTheme.bodyLarge - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - bodyMedium: baseTheme.bodyMedium - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - bodySmall: baseTheme.bodySmall?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 250)]), - labelLarge: baseTheme.labelLarge?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 380)]), - labelMedium: baseTheme.labelMedium - ?.copyWith(fontFamily: fontFamily, fontVariations: [fontVariation]), - labelSmall: baseTheme.labelSmall?.copyWith( - fontFamily: fontFamily, - fontVariations: [const FontVariation('wght', 250)]), - ); - } + // colorScheme + final colorScheme = ColorScheme.fromSeed( + seedColor: seedColor, + brightness: brightness, + dynamicSchemeVariant: color == 0 + ? DynamicSchemeVariant.monochrome + : DynamicSchemeVariant.tonalSpot, + ); + // typography + final typography = Typography.material2021( + platform: defaultTargetPlatform, colorScheme: colorScheme); + final defaultTextTheme = + brightness == Brightness.light ? typography.black : typography.white; - // 基础主题 return ThemeData( - colorScheme: ColorScheme.fromSeed( - seedColor: seedColor, - brightness: brightness, - dynamicSchemeVariant: color == 0 - ? DynamicSchemeVariant.monochrome - : DynamicSchemeVariant.tonalSpot, - ), + colorScheme: colorScheme, materialTapTargetSize: MaterialTapTargetSize.padded, brightness: brightness, - textTheme: fontFamily != 'MiSans VF' - ? applyFontVariations( - brightness == Brightness.light - ? Typography.material2021().black - : Typography.material2021().white, - fontFamily, - ) - : applyMiSansFontVariations( - brightness == Brightness.light - ? Typography.material2021().black - : Typography.material2021().white, - fontFamily, - ), + fontFamily: fontFamily, + textTheme: _applyFontVariations( + defaultTextTheme, + fontFamily, + wghtAxisMap: wghtAxisMap, + ), ); } - static DefaultStyles getInstance(BuildContext context) { + static DefaultStyles getInstance(BuildContext context, + {required ColorScheme customColorScheme}) { final themeData = Theme.of(context); final textStyle = Theme.of(context).textTheme; final baseStyle = textStyle.bodyMedium!.copyWith( - fontSize: 16, - height: 1.5, - decoration: TextDecoration.none, + color: customColorScheme.onSurface, ); const baseHorizontalSpacing = HorizontalSpacing(0, 0); const baseVerticalSpacing = VerticalSpacing(6, 0); @@ -172,82 +225,40 @@ class ThemeUtil { return DefaultStyles( h1: DefaultTextBlockStyle( - textStyle.titleLarge!.copyWith( - fontSize: 34, - color: textStyle.titleLarge!.color, - letterSpacing: -0.5, - height: 1.083, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), + textStyle.titleLarge!.copyWith(color: customColorScheme.primary), baseHorizontalSpacing, const VerticalSpacing(16, 0), VerticalSpacing.zero, null), h2: DefaultTextBlockStyle( - textStyle.titleMedium!.copyWith( - fontSize: 30, - color: textStyle.titleMedium!.color, - letterSpacing: -0.8, - height: 1.067, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), + textStyle.titleMedium!.copyWith(color: customColorScheme.secondary), baseHorizontalSpacing, const VerticalSpacing(8, 0), VerticalSpacing.zero, null), h3: DefaultTextBlockStyle( - textStyle.titleSmall!.copyWith( - fontSize: 24, - color: textStyle.titleSmall!.color, - letterSpacing: -0.5, - height: 1.083, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), + textStyle.titleSmall!.copyWith(color: customColorScheme.onSurface), baseHorizontalSpacing, const VerticalSpacing(8, 0), VerticalSpacing.zero, null, ), h4: DefaultTextBlockStyle( - textStyle.titleSmall!.copyWith( - fontSize: 20, - color: textStyle.titleSmall!.color, - letterSpacing: -0.4, - height: 1.1, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), + textStyle.titleSmall!.copyWith(color: customColorScheme.onSurface), baseHorizontalSpacing, const VerticalSpacing(6, 0), VerticalSpacing.zero, null, ), h5: DefaultTextBlockStyle( - textStyle.titleSmall!.copyWith( - fontSize: 18, - color: textStyle.titleSmall!.color, - letterSpacing: -0.2, - height: 1.11, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), + textStyle.titleSmall!.copyWith(color: customColorScheme.onSurface), baseHorizontalSpacing, const VerticalSpacing(6, 0), VerticalSpacing.zero, null, ), h6: DefaultTextBlockStyle( - textStyle.titleSmall!.copyWith( - fontSize: 16, - color: textStyle.titleSmall!.color, - letterSpacing: -0.1, - height: 1.125, - fontWeight: FontWeight.bold, - decoration: TextDecoration.none, - ), + textStyle.titleSmall!.copyWith(color: customColorScheme.onSurface), baseHorizontalSpacing, const VerticalSpacing(4, 0), VerticalSpacing.zero, diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 771228a..b1ed357 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -6,6 +6,7 @@ import FlutterMacOS import Foundation import app_links +import appkit_ui_element_colors import audioplayers_darwin import bitsdojo_window_macos import connectivity_plus @@ -18,6 +19,8 @@ import gal import geolocator_apple import isar_flutter_libs import local_auth_darwin +import macos_ui +import macos_window_utils import media_kit_libs_macos_video import media_kit_video import network_info_plus @@ -37,6 +40,7 @@ import wakelock_plus func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) + AppkitUiElementColorsPlugin.register(with: registry.registrar(forPlugin: "AppkitUiElementColorsPlugin")) AudioplayersDarwinPlugin.register(with: registry.registrar(forPlugin: "AudioplayersDarwinPlugin")) BitsdojoWindowPlugin.register(with: registry.registrar(forPlugin: "BitsdojoWindowPlugin")) ConnectivityPlusPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlusPlugin")) @@ -49,6 +53,8 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) IsarFlutterLibsPlugin.register(with: registry.registrar(forPlugin: "IsarFlutterLibsPlugin")) FLALocalAuthPlugin.register(with: registry.registrar(forPlugin: "FLALocalAuthPlugin")) + MacOSUiPlugin.register(with: registry.registrar(forPlugin: "MacOSUiPlugin")) + MacOSWindowUtilsPlugin.register(with: registry.registrar(forPlugin: "MacOSWindowUtilsPlugin")) MediaKitLibsMacosVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosVideoPlugin")) MediaKitVideoPlugin.register(with: registry.registrar(forPlugin: "MediaKitVideoPlugin")) NetworkInfoPlusPlugin.register(with: registry.registrar(forPlugin: "NetworkInfoPlusPlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index ee4e9b4..8f2d5dd 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,6 +1,8 @@ PODS: - app_links (1.0.0): - FlutterMacOS + - appkit_ui_element_colors (1.0.0): + - FlutterMacOS - audioplayers_darwin (0.0.1): - FlutterMacOS - bitsdojo_window_macos (0.0.1): @@ -30,6 +32,10 @@ PODS: - local_auth_darwin (0.0.1): - Flutter - FlutterMacOS + - macos_ui (0.1.0): + - FlutterMacOS + - macos_window_utils (1.0.0): + - FlutterMacOS - media_kit_libs_macos_video (1.0.4): - FlutterMacOS - media_kit_native_event_loop (1.0.0): @@ -77,6 +83,7 @@ PODS: DEPENDENCIES: - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) + - appkit_ui_element_colors (from `Flutter/ephemeral/.symlinks/plugins/appkit_ui_element_colors/macos`) - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`) - connectivity_plus (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus/darwin`) @@ -90,6 +97,8 @@ DEPENDENCIES: - geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/macos`) - isar_flutter_libs (from `Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos`) - local_auth_darwin (from `Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin`) + - macos_ui (from `Flutter/ephemeral/.symlinks/plugins/macos_ui/macos`) + - macos_window_utils (from `Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos`) - media_kit_libs_macos_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos`) - media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`) - media_kit_video (from `Flutter/ephemeral/.symlinks/plugins/media_kit_video/macos`) @@ -117,6 +126,8 @@ SPEC REPOS: EXTERNAL SOURCES: app_links: :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos + appkit_ui_element_colors: + :path: Flutter/ephemeral/.symlinks/plugins/appkit_ui_element_colors/macos audioplayers_darwin: :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos bitsdojo_window_macos: @@ -143,6 +154,10 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/isar_flutter_libs/macos local_auth_darwin: :path: Flutter/ephemeral/.symlinks/plugins/local_auth_darwin/darwin + macos_ui: + :path: Flutter/ephemeral/.symlinks/plugins/macos_ui/macos + macos_window_utils: + :path: Flutter/ephemeral/.symlinks/plugins/macos_window_utils/macos media_kit_libs_macos_video: :path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_video/macos media_kit_native_event_loop: @@ -184,6 +199,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: app_links: 9028728e32c83a0831d9db8cf91c526d16cc5468 + appkit_ui_element_colors: 711e7a2aa027790964e6fd90c78a666efe631432 audioplayers_darwin: 761f2948df701d05b5db603220c384fb55720012 bitsdojo_window_macos: 7959fb0ca65a3ccda30095c181ecb856fae48ea9 connectivity_plus: 2256d3e20624a7749ed21653aafe291a46446fee @@ -197,6 +213,8 @@ SPEC CHECKSUMS: geolocator_apple: ccfb79d5250de3a295f5093cd03e76aa8836a416 isar_flutter_libs: a65381780401f81ad6bf3f2e7cd0de5698fb98c4 local_auth_darwin: 553ce4f9b16d3fdfeafce9cf042e7c9f77c1c391 + macos_ui: 2047a8e6536a80491ef10684c53ca500e04f1bcf + macos_window_utils: 3bca8603c2a1cf2257351dfe6bbccc9accf739fd media_kit_libs_macos_video: 85a23e549b5f480e72cae3e5634b5514bc692f65 media_kit_native_event_loop: a80d071c835c612fd80173e79390a50ec409f1b1 media_kit_video: fa6564e3799a0a28bff39442334817088b7ca758 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index a37ed44..53171ca 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -68,7 +68,7 @@ 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* 心绪日记.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "心绪日记.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10ED2044A3C60003C045 /* Moodiary.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Moodiary.app; sourceTree = BUILT_PRODUCTS_DIR; }; 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; @@ -144,7 +144,7 @@ 33CC10EE2044A3C60003C045 /* Products */ = { isa = PBXGroup; children = ( - 33CC10ED2044A3C60003C045 /* 心绪日记.app */, + 33CC10ED2044A3C60003C045 /* Moodiary.app */, 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, ); name = Products; @@ -248,7 +248,7 @@ ); name = Runner; productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* 心绪日记.app */; + productReference = 33CC10ED2044A3C60003C045 /* Moodiary.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ @@ -269,7 +269,6 @@ 33CC10EC2044A3C60003C045 = { CreatedOnToolsVersion = 9.2; LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; SystemCapabilities = { com.apple.Sandbox = { enabled = 1; @@ -571,8 +570,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 3XA29H789G; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; LD_RUNPATH_SEARCH_PATHS = ( @@ -580,6 +582,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -705,8 +708,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 3XA29H789G; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; LD_RUNPATH_SEARCH_PATHS = ( @@ -714,6 +720,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 12.4; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -727,8 +734,11 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 3XA29H789G; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.lifestyle"; LD_RUNPATH_SEARCH_PATHS = ( @@ -737,6 +747,7 @@ ); MACOSX_DEPLOYMENT_TARGET = 12.4; ONLY_ACTIVE_ARCH = NO; + PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index b5e6c22..d855ac7 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -15,7 +15,7 @@ @@ -31,7 +31,7 @@ @@ -65,7 +65,7 @@ @@ -82,7 +82,7 @@ diff --git a/macos/Runner/Configs/AppInfo.xcconfig b/macos/Runner/Configs/AppInfo.xcconfig index 4a10d35..b63bf2f 100644 --- a/macos/Runner/Configs/AppInfo.xcconfig +++ b/macos/Runner/Configs/AppInfo.xcconfig @@ -5,10 +5,10 @@ // 'flutter create' template. // The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = 心绪日记 +PRODUCT_NAME = Moodiary // The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodDiary +PRODUCT_BUNDLE_IDENTIFIER = cn.yooss.moodiary // The copyright displayed in application information PRODUCT_COPYRIGHT = Copyright © 2024 cn.yooss. All rights reserved. diff --git a/pubspec.lock b/pubspec.lock index c0065b0..2d07d8f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -14,6 +14,14 @@ packages: description: dart source: sdk version: "0.3.3" + adaptive_dialog: + dependency: "direct main" + description: + name: adaptive_dialog + sha256: "760acece71b957dbab6f2071b84eb52b4b0236f20ba6cfb89446834ee92086dc" + url: "https://pub.dev" + source: hosted + version: "2.4.0" analyzer: dependency: transitive description: @@ -30,6 +38,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.4" + animations: + dependency: transitive + description: + name: animations + sha256: d3d6dcfb218225bbe68e87ccf6378bbb2e32a94900722c5f81611dad089911cb + url: "https://pub.dev" + source: hosted + version: "2.0.11" ansicolor: dependency: transitive description: @@ -70,6 +86,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + appkit_ui_element_colors: + dependency: transitive + description: + name: appkit_ui_element_colors + sha256: c3e50f900aae314d339de489535736238627071457c4a4a2dbbb1545b4f04f22 + url: "https://pub.dev" + source: hosted + version: "1.0.0" archive: dependency: "direct main" description: @@ -610,10 +634,10 @@ packages: dependency: "direct main" description: name: fc_native_video_thumbnail - sha256: "61836a6fd34bb0cbda48d7ba7cd7a23242468886d4c68017ae59b9791fb42d2a" + sha256: "2d22441504284ca9149fc617af138a42fa31b8847c25c357db5731b0dd189a9f" url: "https://pub.dev" source: hosted - version: "0.16.1" + version: "0.17.1" ffi: dependency: transitive description: @@ -751,10 +775,10 @@ packages: dependency: "direct main" description: name: flutter_image_compress - sha256: "45a3071868092a61b11044c70422b04d39d4d9f2ef536f3c5b11fb65a1e7dd90" + sha256: "51d23be39efc2185e72e290042a0da41aed70b14ef97db362a6b5368d0523b27" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.4.0" flutter_image_compress_common: dependency: transitive description: @@ -767,10 +791,10 @@ packages: dependency: transitive description: name: flutter_image_compress_macos - sha256: "26df6385512e92b3789dc76b613b54b55c457a7f1532e59078b04bf189782d47" + sha256: "20019719b71b743aba0ef874ed29c50747461e5e8438980dfa5c2031898f7337" url: "https://pub.dev" source: hosted - version: "1.0.2" + version: "1.0.3" flutter_image_compress_ohos: dependency: transitive description: @@ -791,10 +815,10 @@ packages: dependency: transitive description: name: flutter_image_compress_web - sha256: f02fe352b17f82b72f481de45add240db062a2585850bea1667e82cc4cd6c311 + sha256: b9b141ac7c686a2ce7bb9a98176321e1182c9074650e47bb140741a44b6f5a96 url: "https://pub.dev" source: hosted - version: "0.1.4+1" + version: "0.1.5" flutter_keyboard_visibility_linux: dependency: transitive description: @@ -892,10 +916,10 @@ packages: dependency: "direct main" description: name: flutter_markdown - sha256: "255b00afa1a7bad19727da6a7780cf3db6c3c12e68d302d85e0ff1fdf173db9e" + sha256: e37f4c69a07b07bb92622ef6b131a53c9aae48f64b176340af9e8e5238718487 url: "https://pub.dev" source: hosted - version: "0.7.4+3" + version: "0.7.5" flutter_native_splash: dependency: "direct main" description: @@ -1082,6 +1106,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.1" + gradient_borders: + dependency: transitive + description: + name: gradient_borders + sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8 + url: "https://pub.dev" + source: hosted + version: "1.0.1" graphs: dependency: transitive description: @@ -1134,10 +1166,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "76d306a1c3afb33fe82e2bbacad62a61f409b5634c915fceb0d799de1a913360" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.1.1" + version: "4.1.2" http_status_code: dependency: "direct main" description: @@ -1182,10 +1214,10 @@ packages: dependency: transitive description: name: image_picker_ios - sha256: "4f0568120c6fcc0aaa04511cb9f9f4d29fc3d0139884b1d06be88dcec7641d6b" + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" url: "https://pub.dev" source: hosted - version: "0.8.12+1" + version: "0.8.12+2" image_picker_linux: dependency: transitive description: @@ -1218,6 +1250,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1+1" + intersperse: + dependency: transitive + description: + name: intersperse + sha256: "2f8a905c96f6cbba978644a3d5b31b8d86ddc44917662df7d27a61f3df66a576" + url: "https://pub.dev" + source: hosted + version: "2.0.0" intl: dependency: "direct main" description: @@ -1394,6 +1434,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.0" + macos_ui: + dependency: transitive + description: + name: macos_ui + sha256: c524398d3db161ac52254ebc9617c3399bdcf269ce7a70e014f202b5c4da5ea4 + url: "https://pub.dev" + source: hosted + version: "2.1.4" + macos_window_utils: + dependency: transitive + description: + name: macos_window_utils + sha256: "3534f2af024f2f24112ca28789a44e6750083f8c0065414546c6593ee48a5009" + url: "https://pub.dev" + source: hosted + version: "1.6.1" macros: dependency: transitive description: @@ -2118,10 +2174,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: "3c7e73920c694a436afaf65ab60ce3453d91f84208d761fbd83fc21182134d93" + sha256: a752ce92ea7540fc35a0d19722816e04d0e72828a4200e83a98cf1a1eb524c9a url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_android: dependency: transitive description: @@ -2219,10 +2275,10 @@ packages: dependency: "direct main" description: name: slang - sha256: "4cdc3d8f4b384dbc56d94c87a5371d4a584460d82a74e18247ec690a0e369ff2" + sha256: "2778b88f05ffc23fd0a37436f607bf2a541d0b6b922e69a8ea5bbd50c2427d18" url: "https://pub.dev" source: hosted - version: "4.4.0" + version: "4.4.1" slang_build_runner: dependency: "direct main" description: @@ -2307,10 +2363,10 @@ packages: dependency: transitive description: name: sqflite_darwin - sha256: "96a698e2bc82bd770a4d6aab00b42396a7c63d9e33513a56945cbccb594c2474" + sha256: "22adfd9a2c7d634041e96d6241e6e1c8138ca6817018afc5d443fef91dcefa9c" url: "https://pub.dev" source: hosted - version: "2.4.1" + version: "2.4.1+1" sqflite_platform_interface: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index dcc3e3a..a279b36 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,7 +36,7 @@ dependencies: markdown_widget: 2.3.2+6 flutter_colorpicker: 1.1.0 geolocator: 13.0.2 - shared_preferences: 2.3.4 + shared_preferences: 2.3.5 isar: 4.0.0-dev.14 isar_flutter_libs: 4.0.0-dev.14 fluttertoast: 8.2.10 @@ -59,7 +59,7 @@ dependencies: media_kit_libs_video: 1.0.5 flutter_adaptive_scaffold: 0.3.1 cross_file: 0.3.4+2 - fc_native_video_thumbnail: 0.16.1 + fc_native_video_thumbnail: 0.17.1 flutter_map: 7.0.2 flutter_map_tile_caching: 9.1.4 flutter_map_marker_cluster: 1.4.0 @@ -83,11 +83,11 @@ dependencies: chewie: 1.8.5 http_status_code: 0.0.2 pinput: 5.0.0 - flutter_markdown: 0.7.4+3 + flutter_markdown: 0.7.5 google_fonts: 6.2.1 image_picker_platform_interface: 2.10.0 chinese_font_library: 1.2.0 - flutter_image_compress: 2.3.0 + flutter_image_compress: 2.4.0 mime: 1.0.6 auto_size_text_field: 2.2.4 webdav_client: 1.2.2 @@ -105,12 +105,14 @@ dependencies: sdk: flutter rust_lib_mood_diary: path: rust_builder - slang: 4.4.0 + slang: 4.4.1 slang_flutter: 4.4.0 slang_build_runner: 4.4.0 modal_bottom_sheet: 3.0.0 sheet: 1.0.0 tutorial_coach_mark: 1.2.12 + adaptive_dialog: 2.4.0 + dev_dependencies: flutter_test: @@ -166,6 +168,7 @@ flutter: - assets/icon/dark/ - assets/icon/light/ - assets/lottie/ + - res/sponsor/ uses-material-design: true diff --git a/rust/Cargo.lock b/rust/Cargo.lock index b180887..9fa0693 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1363,9 +1363,8 @@ dependencies = [ [[package]] name = "ttf-parser" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" +version = "0.24.1" +source = "git+https://github.com/inferiorhumanorgans/ttf-parser.git?branch=fvar-instance#0579236f23680752e6869feb917f5d30727a9f6e" [[package]] name = "typenum" diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 6b97be8..6366550 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -12,4 +12,4 @@ image = "0.25.5" fast_image_resize = { version = "5.1.0", features = ["image"] } anyhow = "1.0.94" bytemuck = "1.21.0" -ttf-parser = "0.25.1" +ttf-parser = {git = "https://github.com/inferiorhumanorgans/ttf-parser.git", branch = "fvar-instance"} diff --git a/rust/src/api/font.rs b/rust/src/api/font.rs index e71606c..39e1f71 100644 --- a/rust/src/api/font.rs +++ b/rust/src/api/font.rs @@ -1,6 +1,5 @@ use flutter_rust_bridge::frb; -use std::fs::File; -use std::io::Read; +use std::collections::HashMap; use ttf_parser::{name_id, Face}; #[frb(opaque)] @@ -8,21 +7,56 @@ pub struct FontReader; impl FontReader { pub fn get_font_name_from_ttf(ttf_file_path: String) -> Option { - let file = File::open(ttf_file_path); - match file { - Ok(mut f) => { - let mut data = Vec::new(); - if f.read_to_end(&mut data).is_ok() { - let font = Face::parse(&data, 0).ok()?; - font.names() - .into_iter() - .find(|name| name.name_id == name_id::FULL_NAME && name.is_unicode()) - .and_then(|name| name.to_string()) - } else { - None + let data = match std::fs::read(ttf_file_path) { + Ok(data) => data, + Err(_) => return None, + }; + let font = match Face::parse(&data, 0) { + Ok(font) => font, + Err(_) => return None, + }; + font.names() + .into_iter() + .find(|name| name.name_id == name_id::FULL_NAME && name.is_unicode()) + .and_then(|name| name.to_string()) + } + + pub fn get_wght_axis_from_vf_font(ttf_file_path: String) -> HashMap { + let mut result = HashMap::new(); + let data = match std::fs::read(ttf_file_path) { + Ok(data) => data, + Err(_) => return result, + }; + let font = match Face::parse(&data, 0) { + Ok(font) => font, + Err(_) => return result, + }; + let fvar = match font.tables().fvar { + Some(fvar) => fvar, + None => return result, + }; + if let Some(wght_axis) = fvar + .axes + .into_iter() + .find(|axis| axis.tag == ttf_parser::Tag::from_bytes(b"wght")) + { + result.insert("default".to_string(), wght_axis.def_value); + } + for instance in fvar.instances() { + if let Some(name) = font + .names() + .into_iter() + .find(|n| n.name_id == instance.subfamily_name_id && n.is_unicode()) + { + let subfamily = name.to_string().unwrap_or_default(); + for (axis, value) in fvar.axes.into_iter().zip(instance.user_tuples) { + if axis.tag == ttf_parser::Tag::from_bytes(b"wght") { + result.insert(subfamily, value.0); + break; + } } } - Err(_) => None, } + result } } diff --git a/rust/src/frb_generated.rs b/rust/src/frb_generated.rs index 16f34a7..243dffc 100644 --- a/rust/src/frb_generated.rs +++ b/rust/src/frb_generated.rs @@ -31,7 +31,7 @@ use crate::api::kmp::*; use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt}; use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable}; use flutter_rust_bridge::{Handler, IntoIntoDart}; -use image::DynamicImage; + // Section: boilerplate flutter_rust_bridge::frb_generated_boilerplate!( @@ -40,7 +40,7 @@ flutter_rust_bridge::frb_generated_boilerplate!( default_rust_auto_opaque = RustAutoOpaqueMoi, ); pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.7.0"; -pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -1743857995; +pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 376160798; // Section: executor @@ -83,6 +83,41 @@ fn wire__crate__api__font__FontReader_get_font_name_from_ttf_impl( }, ) } +fn wire__crate__api__font__FontReader_get_wght_axis_from_vf_font_impl( + port_: flutter_rust_bridge::for_generated::MessagePort, + ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, + rust_vec_len_: i32, + data_len_: i32, +) { + FLUTTER_RUST_BRIDGE_HANDLER.wrap_normal::( + flutter_rust_bridge::for_generated::TaskInfo { + debug_name: "FontReader_get_wght_axis_from_vf_font", + port: Some(port_), + mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal, + }, + move || { + let message = unsafe { + flutter_rust_bridge::for_generated::Dart2RustMessageSse::from_wire( + ptr_, + rust_vec_len_, + data_len_, + ) + }; + let mut deserializer = + flutter_rust_bridge::for_generated::SseDeserializer::new(message); + let api_ttf_file_path = ::sse_decode(&mut deserializer); + deserializer.end(); + move |context| { + transform_result_sse::<_, ()>((move || { + let output_ok = Result::<_, ()>::Ok( + crate::api::font::FontReader::get_wght_axis_from_vf_font(api_ttf_file_path), + )?; + Ok(output_ok) + })()) + } + }, + ) +} fn wire__crate__api__compress__ImageCompress_contain_impl( port_: flutter_rust_bridge::for_generated::MessagePort, ptr_: flutter_rust_bridge::for_generated::PlatformGeneralizedUint8ListPtr, @@ -405,6 +440,14 @@ impl SseDecode for std::collections::HashMap { } } +impl SseDecode for std::collections::HashMap { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut inner = >::sse_decode(deserializer); + return inner.into_iter().collect(); + } +} + impl SseDecode for RustOpaqueMoi> { @@ -464,6 +507,13 @@ impl SseDecode for crate::api::constants::CompressFormat { } } +impl SseDecode for f32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + deserializer.cursor.read_f32::().unwrap() + } +} + impl SseDecode for i32 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -519,6 +569,18 @@ impl SseDecode for Vec { } } +impl SseDecode for Vec<(String, f32)> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut len_ = ::sse_decode(deserializer); + let mut ans_ = vec![]; + for idx_ in 0..len_ { + ans_.push(<(String, f32)>::sse_decode(deserializer)); + } + return ans_; + } +} + impl SseDecode for Vec<(String, String)> { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -577,6 +639,15 @@ impl SseDecode for Option { } } +impl SseDecode for (String, f32) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { + let mut var_field0 = ::sse_decode(deserializer); + let mut var_field1 = ::sse_decode(deserializer); + return (var_field0, var_field1); + } +} + impl SseDecode for (String, String) { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self { @@ -634,17 +705,23 @@ fn pde_ffi_dispatcher_primary_impl( rust_vec_len, data_len, ), - 2 => wire__crate__api__compress__ImageCompress_contain_impl( + 2 => wire__crate__api__font__FontReader_get_wght_axis_from_vf_font_impl( port, ptr, rust_vec_len, data_len, ), - 3 => wire__crate__api__kmp__Kmp_find_matches_impl(port, ptr, rust_vec_len, data_len), - 4 => wire__crate__api__kmp__Kmp_replace_with_kmp_impl(port, ptr, rust_vec_len, data_len), - 5 => wire__crate__api__kmp__build_prefix_table_impl(port, ptr, rust_vec_len, data_len), - 6 => wire__crate__api__compress__compress_impl(port, ptr, rust_vec_len, data_len), - 7 => wire__crate__api__kmp__kmp_search_impl(port, ptr, rust_vec_len, data_len), + 3 => wire__crate__api__compress__ImageCompress_contain_impl( + port, + ptr, + rust_vec_len, + data_len, + ), + 4 => wire__crate__api__kmp__Kmp_find_matches_impl(port, ptr, rust_vec_len, data_len), + 5 => wire__crate__api__kmp__Kmp_replace_with_kmp_impl(port, ptr, rust_vec_len, data_len), + 6 => wire__crate__api__kmp__build_prefix_table_impl(port, ptr, rust_vec_len, data_len), + 7 => wire__crate__api__compress__compress_impl(port, ptr, rust_vec_len, data_len), + 8 => wire__crate__api__kmp__kmp_search_impl(port, ptr, rust_vec_len, data_len), _ => unreachable!(), } } @@ -776,6 +853,13 @@ impl SseEncode for std::collections::HashMap { } } +impl SseEncode for std::collections::HashMap { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + >::sse_encode(self.into_iter().collect(), serializer); + } +} + impl SseEncode for RustOpaqueMoi> { @@ -842,6 +926,13 @@ impl SseEncode for crate::api::constants::CompressFormat { } } +impl SseEncode for f32 { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + serializer.cursor.write_f32::(self).unwrap(); + } +} + impl SseEncode for i32 { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -889,6 +980,16 @@ impl SseEncode for Vec { } } +impl SseEncode for Vec<(String, f32)> { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.len() as _, serializer); + for item in self { + <(String, f32)>::sse_encode(item, serializer); + } + } +} + impl SseEncode for Vec<(String, String)> { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -939,6 +1040,14 @@ impl SseEncode for Option { } } +impl SseEncode for (String, f32) { + // Codec=Sse (Serialization based), see doc to use other codecs + fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { + ::sse_encode(self.0, serializer); + ::sse_encode(self.1, serializer); + } +} + impl SseEncode for (String, String) { // Codec=Sse (Serialization based), see doc to use other codecs fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) { @@ -1060,6 +1169,7 @@ mod io { MoiArc::>::decrement_strong_count(ptr as _); } } +use image::DynamicImage; #[cfg(not(target_family = "wasm"))] pub use io::*; diff --git a/windows/runner/Runner.rc b/windows/runner/Runner.rc index e1c7505..36eadb0 100644 --- a/windows/runner/Runner.rc +++ b/windows/runner/Runner.rc @@ -90,12 +90,12 @@ BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "cn.yooss" "\0" - VALUE "FileDescription", "mood_diary" "\0" + VALUE "FileDescription", "moodiary" "\0" VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "mood_diary" "\0" - VALUE "LegalCopyright", "Copyright (C) 2024 cn.yooss. All rights reserved." "\0" - VALUE "OriginalFilename", "mood_diary.exe" "\0" - VALUE "ProductName", "mood_diary" "\0" + VALUE "InternalName", "moodiary" "\0" + VALUE "LegalCopyright", "Copyright (C) 2024 Moodiary All rights reserved." "\0" + VALUE "OriginalFilename", "moodiary.exe" "\0" + VALUE "ProductName", "moodiary" "\0" VALUE "ProductVersion", VERSION_AS_STRING "\0" END END diff --git a/windows/runner/main.cpp b/windows/runner/main.cpp index 9510c03..46e2354 100644 --- a/windows/runner/main.cpp +++ b/windows/runner/main.cpp @@ -30,7 +30,7 @@ int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, FlutterWindow window(project); Win32Window::Point origin(10, 10); Win32Window::Size size(1280, 720); -if (!window.Create(L"心绪日记", origin, size)) { +if (!window.Create(L"Moodiary", origin, size)) { return EXIT_FAILURE; } window.SetQuitOnClose(true); From 67c421991dfc60dfde15d70b942f7d2bf1061660 Mon Sep 17 00:00:00 2001 From: ZhuJHua <1624109111@qq.com> Date: Mon, 6 Jan 2025 01:05:09 +0800 Subject: [PATCH 2/3] refactor(ui): improve ui --- .../category_add/category_add_logic.dart | 17 +--- .../category_add/category_add_view.dart | 46 +++-------- lib/l10n/intl_en.arb | 2 +- lib/l10n/intl_zh.arb | 2 +- lib/pages/about/about_view.dart | 79 ++++++++++--------- .../category_manager_logic.dart | 37 +++------ .../category_manager_view.dart | 70 ++++++---------- .../diary_setting/diary_setting_view.dart | 65 ++++++++++++--- lib/pages/home/setting/setting_view.dart | 48 +++++++++++ lib/pages/sponsor/sponsor_logic.dart | 14 +++- lib/pages/sponsor/sponsor_view.dart | 47 +++++++---- lib/utils/media_util.dart | 5 ++ 12 files changed, 245 insertions(+), 187 deletions(-) diff --git a/lib/components/category_add/category_add_logic.dart b/lib/components/category_add/category_add_logic.dart index 71db5c0..27fa811 100644 --- a/lib/components/category_add/category_add_logic.dart +++ b/lib/components/category_add/category_add_logic.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:mood_diary/common/models/isar/category.dart'; import 'package:mood_diary/pages/edit/edit_logic.dart'; @@ -10,7 +9,6 @@ import 'category_add_state.dart'; class CategoryAddLogic extends GetxController { final CategoryAddState state = CategoryAddState(); - late TextEditingController textEditingController = TextEditingController(); late final EditLogic editLogic = Bind.find(); late final DiaryLogic diaryLogic = Bind.find(); @@ -22,7 +20,6 @@ class CategoryAddLogic extends GetxController { @override void onClose() { - textEditingController.dispose(); super.onClose(); } @@ -30,25 +27,17 @@ class CategoryAddLogic extends GetxController { state.categoryList.value = IsarUtil.getAllCategory(); } - Future addCategory() async { - if (textEditingController.text.isNotEmpty) { - var res = await IsarUtil.insertACategory( - Category()..categoryName = textEditingController.text); - Get.backLegacy(); + Future addCategory({required String text}) async { + if (text.isNotEmpty) { + var res = await IsarUtil.insertACategory(Category()..categoryName = text); if (res == false) { NoticeUtil.showToast('已经存在同名分类,已自动重命名'); } - textEditingController.clear(); getCategory(); await diaryLogic.updateCategory(); } } - void cancelAdd() { - textEditingController.clear(); - Get.backLegacy(); - } - void selectCategory(int index) { Get.backLegacy(); editLogic.selectCategory(state.categoryList.value[index].id); diff --git a/lib/components/category_add/category_add_view.dart b/lib/components/category_add/category_add_view.dart index 4315777..2063cde 100644 --- a/lib/components/category_add/category_add_view.dart +++ b/lib/components/category_add/category_add_view.dart @@ -1,8 +1,7 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:mood_diary/common/values/border.dart'; -import '../../main.dart'; import 'category_add_logic.dart'; class CategoryAddComponent extends StatelessWidget { @@ -32,39 +31,18 @@ class CategoryAddComponent extends StatelessWidget { FilledButton.icon( icon: const Icon(Icons.add), label: const Text('添加'), - onPressed: () { - showDialog( + onPressed: () async { + var res = await showTextInputDialog( context: context, - builder: (context) { - return AlertDialog( - content: TextField( - maxLines: 1, - controller: logic.textEditingController, - decoration: InputDecoration( - fillColor: colorScheme.secondaryContainer, - border: const UnderlineInputBorder( - borderRadius: - AppBorderRadius.smallBorderRadius, - borderSide: BorderSide.none, - ), - filled: true, - labelText: '标签', - ), - ), - actions: [ - TextButton( - onPressed: () { - logic.cancelAdd(); - }, - child: Text(l10n.cancel)), - TextButton( - onPressed: () async { - await logic.addCategory(); - }, - child: Text(l10n.ok)) - ], - ); - }); + title: '输入分类名称', + textFields: [ + const DialogTextField( + hintText: '分类名称', + ) + ]); + if (res != null) { + logic.addCategory(text: res.first); + } }, ), Text(state.categoryList.length.toString()) diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 8fb9406..8a4df14 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -30,7 +30,7 @@ "settingImportDes": "Only supports files exported from this app", "settingClean": "Clear Cache", "settingDisplay": "Display and Personalization", - "settingDiary": "Diary", + "settingDiary": "Diary Settings", "settingThemeMode": "Theme Mode", "settingColor": "Color Scheme", "settingAutoPlay": "Homepage Card Auto-Play", diff --git a/lib/l10n/intl_zh.arb b/lib/l10n/intl_zh.arb index 3f69cb3..bc30522 100644 --- a/lib/l10n/intl_zh.arb +++ b/lib/l10n/intl_zh.arb @@ -30,7 +30,7 @@ "settingImportDes": "仅支持本应用导出的文件", "settingClean": "清理缓存", "settingDisplay": "显示与个性", - "settingDiary": "日记", + "settingDiary": "日记设置", "settingThemeMode": "主题模式", "settingColor": "配色方案", "settingAutoPlay": "首页卡片自动轮播", diff --git a/lib/pages/about/about_view.dart b/lib/pages/about/about_view.dart index 6ab90ac..9c02b7b 100644 --- a/lib/pages/about/about_view.dart +++ b/lib/pages/about/about_view.dart @@ -37,34 +37,27 @@ class AboutPage extends StatelessWidget { style: textStyle.titleLarge ?.copyWith(color: colorScheme.onSurface), ), - RichText( - text: TextSpan( - style: textStyle.labelMedium - ?.copyWith(color: colorScheme.onSurface), - children: [ - TextSpan( - text: 'Version: ', - style: textStyle.labelSmall - ?.copyWith(color: colorScheme.onSurface), - ), - TextSpan(text: state.appVersion), - const WidgetSpan( - child: SizedBox( - height: 12, - child: VerticalDivider( - thickness: 2, - ), - ), - alignment: PlaceholderAlignment.middle), - TextSpan( - text: 'System: ', - style: textStyle.labelSmall - ?.copyWith(color: colorScheme.onSurface), + Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + state.appVersion, + style: textStyle.labelSmall + ?.copyWith(color: colorScheme.primary), + ), + const SizedBox( + height: 10, + child: VerticalDivider( + thickness: 2, ), - TextSpan(text: state.systemVersion), - ], - ), - ) + ), + Text( + state.systemVersion, + style: textStyle.labelSmall + ?.copyWith(color: colorScheme.onSurface), + ), + ], + ), ], ), ], @@ -87,17 +80,21 @@ class AboutPage extends StatelessWidget { color: colorScheme.surfaceContainerLow, child: Column( children: [ - GetBuilder(builder: (_) { - return ListTile( - leading: const Icon(Icons.update_rounded), - title: Text(l10n.aboutUpdate), - trailing: const Icon(Icons.chevron_right_rounded), - onTap: () async { - await UpdateUtil.checkShouldUpdate(state.appVersion, - handle: true); - }, - ); - }), + ListTile( + leading: const Icon(Icons.update_rounded), + title: Text(l10n.aboutUpdate), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), + trailing: const Icon(Icons.chevron_right_rounded), + onTap: () async { + await UpdateUtil.checkShouldUpdate(state.appVersion, + handle: true); + }, + ), ListTile( leading: const Icon(Icons.source_rounded), title: Text(l10n.aboutSource), @@ -133,6 +130,12 @@ class AboutPage extends StatelessWidget { ListTile( leading: const Icon(Icons.attach_money_rounded), title: Text(l10n.aboutDonate), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), trailing: const Icon(Icons.chevron_right_rounded), onTap: logic.toSponsor, ), diff --git a/lib/pages/category_manager/category_manager_logic.dart b/lib/pages/category_manager/category_manager_logic.dart index 5db53db..e822cf2 100644 --- a/lib/pages/category_manager/category_manager_logic.dart +++ b/lib/pages/category_manager/category_manager_logic.dart @@ -1,4 +1,3 @@ -import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:mood_diary/common/models/isar/category.dart'; import 'package:mood_diary/pages/home/diary/diary_logic.dart'; @@ -10,8 +9,6 @@ import 'category_manager_state.dart'; class CategoryManagerLogic extends GetxController { final CategoryManagerState state = CategoryManagerState(); - late TextEditingController textEditingController = TextEditingController(); - late DiaryLogic diaryLogic = Bind.find(); @override @@ -20,42 +17,36 @@ class CategoryManagerLogic extends GetxController { super.onReady(); } - @override - void onClose() { - textEditingController.dispose(); - super.onClose(); - } - Future getCategory() async { state.isFetching.value = true; state.categoryList.value = await IsarUtil.getAllCategoryAsync(); state.isFetching.value = false; } - Future addCategory() async { - if (textEditingController.text.isNotEmpty) { - if (await IsarUtil.insertACategory( - Category()..categoryName = textEditingController.text)) { - Get.backLegacy(); + Future addCategory({required String text}) async { + if (text.isNotEmpty) { + if (await IsarUtil.insertACategory(Category()..categoryName = text)) { await getCategory(); await diaryLogic.updateCategory(); } else { - Get.backLegacy(); await getCategory(); await diaryLogic.updateCategory(); NoticeUtil.showToast('分类已存在,已自动添加后缀'); } + } else { + NoticeUtil.showToast('分类名称不能为空'); } } - Future editCategory(String categoryId) async { - if (textEditingController.text.isNotEmpty) { + Future editCategory(String categoryId, {required String text}) async { + if (text.isNotEmpty) { await IsarUtil.updateACategory(Category() ..id = categoryId - ..categoryName = textEditingController.text); - Get.backLegacy(); + ..categoryName = text); await getCategory(); await diaryLogic.updateCategory(); + } else { + NoticeUtil.showToast('分类名称不能为空'); } } @@ -68,12 +59,4 @@ class CategoryManagerLogic extends GetxController { NoticeUtil.showToast('删除失败,当前分类下还有日记'); } } - - void clearInput() { - textEditingController.clear(); - } - - void editInput(String value) { - textEditingController.text = value; - } } diff --git a/lib/pages/category_manager/category_manager_view.dart b/lib/pages/category_manager/category_manager_view.dart index 428acc6..594313f 100644 --- a/lib/pages/category_manager/category_manager_view.dart +++ b/lib/pages/category_manager/category_manager_view.dart @@ -1,9 +1,8 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; -import 'package:mood_diary/common/values/border.dart'; import 'package:mood_diary/components/loading/loading.dart'; -import '../../main.dart'; import 'category_manager_logic.dart'; class CategoryManagerPage extends StatelessWidget { @@ -15,32 +14,6 @@ class CategoryManagerPage extends StatelessWidget { final state = Bind.find().state; final colorScheme = Theme.of(context).colorScheme; - Widget inputDialog(Function() operate) { - return AlertDialog( - title: TextField( - maxLines: 1, - controller: logic.textEditingController, - decoration: InputDecoration( - fillColor: colorScheme.secondaryContainer, - border: const UnderlineInputBorder( - borderRadius: AppBorderRadius.smallBorderRadius, - borderSide: BorderSide.none, - ), - filled: true, - labelText: '分类', - ), - ), - actions: [ - TextButton( - onPressed: () { - Get.backLegacy(); - }, - child: Text(l10n.cancel)), - TextButton(onPressed: operate, child: Text(l10n.ok)) - ], - ); - } - return Scaffold( appBar: AppBar( title: const Text('分类管理'), @@ -62,17 +35,21 @@ class CategoryManagerPage extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ IconButton( - onPressed: () { - logic.editInput( - state.categoryList[index].categoryName); - showDialog( + onPressed: () async { + var res = await showTextInputDialog( context: context, - builder: (context) { - return inputDialog(() { - logic.editCategory( - state.categoryList[index].id); - }); - }); + title: '编辑分类', + textFields: [ + DialogTextField( + hintText: '分类名称', + initialText: state + .categoryList[index].categoryName, + ) + ]); + if (res != null) { + logic.editCategory(state.categoryList[index].id, + text: res.first); + } }, icon: const Icon(Icons.edit), ), @@ -101,14 +78,17 @@ class CategoryManagerPage extends StatelessWidget { child: !state.isFetching.value ? FloatingActionButton.extended( onPressed: () async { - logic.clearInput(); - showDialog( + var res = await showTextInputDialog( context: context, - builder: (context) { - return inputDialog(() { - logic.addCategory(); - }); - }); + title: '添加分类', + textFields: [ + const DialogTextField( + hintText: '分类名称', + ) + ]); + if (res != null) { + logic.addCategory(text: res.first); + } }, icon: const Icon(Icons.add), label: const Text('添加分类'), diff --git a/lib/pages/diary_setting/diary_setting_view.dart b/lib/pages/diary_setting/diary_setting_view.dart index 2cdab8a..3d87929 100644 --- a/lib/pages/diary_setting/diary_setting_view.dart +++ b/lib/pages/diary_setting/diary_setting_view.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:mood_diary/common/values/border.dart'; import 'package:mood_diary/components/tile/setting_tile.dart'; import '../../main.dart'; @@ -29,18 +30,24 @@ class DiarySettingPage extends StatelessWidget { Obx(() { return SwitchListTile( value: state.autoWeather.value, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), onChanged: (value) { logic.autoWeather(value); }, title: const Text('自动获取天气'), - secondary: const Icon(Icons.wb_sunny_outlined), + secondary: const Icon(Icons.wb_sunny_rounded), ); }), Obx(() { return SwitchListTile( value: state.autoCategory.value, onChanged: logic.autoCategory, - secondary: const Icon(Icons.category_outlined), + secondary: const Icon(Icons.category_rounded), title: const Text('自动设置分类'), ); }), @@ -48,7 +55,7 @@ class DiarySettingPage extends StatelessWidget { return SwitchListTile( value: state.showWriteTime.value, onChanged: logic.showWriteTime, - secondary: const Icon(Icons.timer_outlined), + secondary: const Icon(Icons.timer_rounded), title: const Text('展示写作时长'), ); }), @@ -56,7 +63,7 @@ class DiarySettingPage extends StatelessWidget { return SwitchListTile( value: state.showWordCount.value, onChanged: logic.showWordCount, - secondary: const Icon(Icons.font_download_outlined), + secondary: const Icon(Icons.font_download_rounded), title: const Text('展示字数统计'), ); }), @@ -64,7 +71,13 @@ class DiarySettingPage extends StatelessWidget { return SwitchListTile( value: state.dynamicColor.value, onChanged: logic.dynamicColor, - secondary: const Icon(Icons.color_lens_outlined), + secondary: const Icon(Icons.colorize_rounded), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), title: const Text('日记页动态配色'), subtitle: const Text('使用基于封面的配色'), ); @@ -90,7 +103,10 @@ class DiarySettingPage extends StatelessWidget { value: state.firstLineIndent.value, onChanged: logic.firstLineIndent, title: const Text('首行缩进'), - secondary: const Icon(Icons.format_indent_increase), + shape: const RoundedRectangleBorder( + borderRadius: AppBorderRadius.mediumBorderRadius, + ), + secondary: const Icon(Icons.format_indent_increase_rounded), subtitle: const Text('只对修改后的日记生效'), ); }), @@ -113,13 +129,20 @@ class DiarySettingPage extends StatelessWidget { ListTile( title: Text(l10n.settingImageQuality), subtitle: Text(l10n.settingImageQualityDes), - leading: const Icon(Icons.gradient_outlined), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), + leading: const Icon(Icons.gradient_rounded), trailing: Obx(() { return Text( switch (state.quality.value) { 0 => l10n.qualityLow, 1 => l10n.qualityMedium, 2 => l10n.qualityHigh, + 3 => '原图', int() => throw UnimplementedError(), }, style: textStyle.bodySmall!.copyWith( @@ -141,7 +164,7 @@ class DiarySettingPage extends StatelessWidget { children: [ Text(l10n.qualityLow), if (state.quality.value == 0) ...[ - const Icon(Icons.check), + const Icon(Icons.check_rounded), ], ], ), @@ -155,7 +178,7 @@ class DiarySettingPage extends StatelessWidget { children: [ Text(l10n.qualityMedium), if (state.quality.value == 1) ...[ - const Icon(Icons.check), + const Icon(Icons.check_rounded), ], ], ), @@ -169,7 +192,7 @@ class DiarySettingPage extends StatelessWidget { children: [ Text(l10n.qualityHigh), if (state.quality.value == 2) ...[ - const Icon(Icons.check), + const Icon(Icons.check_rounded), ], ], ), @@ -177,6 +200,20 @@ class DiarySettingPage extends StatelessWidget { logic.quality(2); }, ), + SimpleDialogOption( + child: Row( + spacing: 8.0, + children: [ + Text('原图'), + if (state.quality.value == 3) ...[ + const Icon(Icons.check_rounded), + ], + ], + ), + onPressed: () { + logic.quality(3); + }, + ), ], ); }); @@ -187,8 +224,14 @@ class DiarySettingPage extends StatelessWidget { return SwitchListTile( value: state.diaryHeader.value, onChanged: logic.diaryHeader, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), title: const Text('日记页展示头图'), - secondary: const Icon(Icons.broken_image_outlined), + secondary: const Icon(Icons.broken_image_rounded), ); }), ], diff --git a/lib/pages/home/setting/setting_view.dart b/lib/pages/home/setting/setting_view.dart index 43d0af7..c07b420 100644 --- a/lib/pages/home/setting/setting_view.dart +++ b/lib/pages/home/setting/setting_view.dart @@ -111,6 +111,12 @@ class SettingPage extends StatelessWidget { children: [ ListTile( title: Text(l10n.settingRecycle), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), trailing: const Icon(Icons.chevron_right_rounded), onTap: () { logic.toRecyclePage(); @@ -128,6 +134,12 @@ class SettingPage extends StatelessWidget { ListTile( title: Text(l10n.settingClean), leading: const Icon(Icons.cleaning_services_rounded), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), trailing: GetBuilder( id: 'DataUsage', builder: (_) { @@ -161,6 +173,12 @@ class SettingPage extends StatelessWidget { title: Text(l10n.settingDiary), leading: const Icon(Icons.article_rounded), trailing: const Icon(Icons.chevron_right_rounded), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), onTap: () { logic.toDiarySettingPage(); }, @@ -215,6 +233,12 @@ class SettingPage extends StatelessWidget { ListTile( title: const Text('首页名称'), leading: const Icon(Icons.drive_file_rename_outline_rounded), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), trailing: GetBuilder( id: 'CustomTitle', builder: (_) { @@ -279,6 +303,12 @@ class SettingPage extends StatelessWidget { color: colorScheme.primary, ), ), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), onTap: () { showDialog( context: context, @@ -315,6 +345,12 @@ class SettingPage extends StatelessWidget { builder: (_) { return SwitchListTile( value: state.lockNow, + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), onChanged: state.lock ? (value) { logic.lockNow(value); @@ -344,6 +380,12 @@ class SettingPage extends StatelessWidget { title: Text(l10n.settingAbout), leading: const Icon(Icons.info_rounded), trailing: const Icon(Icons.chevron_right_rounded), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(12.0), + topRight: Radius.circular(12.0), + ), + ), onTap: () { logic.toAboutPage(); }, @@ -352,6 +394,12 @@ class SettingPage extends StatelessWidget { title: Text(l10n.settingLab), leading: const Icon(Icons.science_rounded), trailing: const Icon(Icons.chevron_right_rounded), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(12.0), + bottomRight: Radius.circular(12.0), + ), + ), onTap: () { logic.toLaboratoryPage(); }, diff --git a/lib/pages/sponsor/sponsor_logic.dart b/lib/pages/sponsor/sponsor_logic.dart index 95fb879..c25a256 100644 --- a/lib/pages/sponsor/sponsor_logic.dart +++ b/lib/pages/sponsor/sponsor_logic.dart @@ -1,7 +1,19 @@ +import 'package:confetti/confetti.dart'; import 'package:get/get.dart'; class SponsorLogic extends GetxController { + late final ConfettiController confettiController = + ConfettiController(duration: const Duration(seconds: 2)); + @override + void onReady() { + confettiController.play(); + super.onReady(); + } - + @override + void onClose() { + confettiController.dispose(); + super.onClose(); + } } diff --git a/lib/pages/sponsor/sponsor_view.dart b/lib/pages/sponsor/sponsor_view.dart index 8b27fe6..98035cb 100644 --- a/lib/pages/sponsor/sponsor_view.dart +++ b/lib/pages/sponsor/sponsor_view.dart @@ -1,5 +1,8 @@ +import 'dart:math'; + import 'package:confetti/confetti.dart'; import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'sponsor_logic.dart'; @@ -19,22 +22,36 @@ class SponsorPage extends StatelessWidget { appBar: AppBar( title: const Text('捐助'), ), - body: Center( - child: ConfettiWidget( - confettiController: - ConfettiController(duration: Duration(seconds: 1)), - blastDirectionality: BlastDirectionality.explosive, - shouldLoop: true, - colors: const [ - Colors.green, - Colors.blue, - Colors.yellow, - Colors.red, - ], - child: Container( - child: Text('庆祝一下!'), + body: Stack( + children: [ + Align( + alignment: Alignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, + spacing: 16.0, + children: [ + _buildWechat(), + const Text('祝你今天愉快'), + const FaIcon(FontAwesomeIcons.weixin), + ], + ), + ), + Align( + alignment: Alignment.topCenter, + child: ConfettiWidget( + confettiController: logic.confettiController, + blastDirectionality: BlastDirectionality.directional, + blastDirection: pi / 2, + emissionFrequency: 0.1, + colors: const [ + Colors.green, + Colors.blue, + Colors.yellow, + Colors.red, + ], + ), ), - ), + ], ), ); } diff --git a/lib/utils/media_util.dart b/lib/utils/media_util.dart index 2d88d14..5e7da21 100644 --- a/lib/utils/media_util.dart +++ b/lib/utils/media_util.dart @@ -227,6 +227,11 @@ class MediaUtil { String outputPath, dynamic format, ) async { + // 如果选择了原图,则直接复制文件 + if (PrefUtil.getValue('quality') == 3) { + await imageFile.saveTo(outputPath); + return; + } if (format == CompressFormat.heic) { await _compressNative(imageFile, outputPath, format); } else { From f871cb66ee7339ad228e45eafa6584fcedd37896 Mon Sep 17 00:00:00 2001 From: ZhuJHua <1624109111@qq.com> Date: Mon, 6 Jan 2025 01:18:57 +0800 Subject: [PATCH 3/3] style(*): code clean up [skip ci] --- .../input_dialog/input_dialog_logic.dart | 4 +- .../input_dialog/input_dialog_view.dart | 1 - .../large_diary_card_view.dart | 1 - lib/pages/edit/edit_view.dart | 74 +++++++++---------- lib/pages/font/font_logic.dart | 4 +- lib/src/rust/api/compress.dart | 3 +- lib/src/rust/api/constants.dart | 3 +- lib/src/rust/api/kmp.dart | 3 +- lib/src/rust/frb_generated.dart | 10 ++- lib/src/rust/frb_generated.io.dart | 10 ++- lib/src/rust/frb_generated.web.dart | 8 +- 11 files changed, 59 insertions(+), 62 deletions(-) diff --git a/lib/components/dialog/input_dialog/input_dialog_logic.dart b/lib/components/dialog/input_dialog/input_dialog_logic.dart index ea0f4c4..4a4e5b3 100644 --- a/lib/components/dialog/input_dialog/input_dialog_logic.dart +++ b/lib/components/dialog/input_dialog/input_dialog_logic.dart @@ -1,5 +1,3 @@ import 'package:get/get.dart'; -class InputDialogLogic extends GetxController { - -} +class InputDialogLogic extends GetxController {} diff --git a/lib/components/dialog/input_dialog/input_dialog_view.dart b/lib/components/dialog/input_dialog/input_dialog_view.dart index 25fe51f..3a30b33 100644 --- a/lib/components/dialog/input_dialog/input_dialog_view.dart +++ b/lib/components/dialog/input_dialog/input_dialog_view.dart @@ -1,4 +1,3 @@ -import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; diff --git a/lib/components/diary_card/large_diary_card/large_diary_card_view.dart b/lib/components/diary_card/large_diary_card/large_diary_card_view.dart index 3f75f83..06b719e 100644 --- a/lib/components/diary_card/large_diary_card/large_diary_card_view.dart +++ b/lib/components/diary_card/large_diary_card/large_diary_card_view.dart @@ -6,7 +6,6 @@ import 'package:mood_diary/common/models/isar/diary.dart'; import 'package:mood_diary/common/values/border.dart'; import 'package:mood_diary/components/diary_card/basic_diary_card/basic_card_logic.dart'; -import '../../../common/values/colors.dart'; import '../../../utils/file_util.dart'; class LargeDiaryCardComponent extends StatelessWidget with BasicCardLogic { diff --git a/lib/pages/edit/edit_view.dart b/lib/pages/edit/edit_view.dart index 6c50f49..2532d6d 100644 --- a/lib/pages/edit/edit_view.dart +++ b/lib/pages/edit/edit_view.dart @@ -45,16 +45,10 @@ class EditPage extends StatelessWidget { @override Widget build(BuildContext context) { final logic = Bind.find(); - final state = Bind - .find() - .state; - final colorScheme = Theme - .of(context) - .colorScheme; + final state = Bind.find().state; + final colorScheme = Theme.of(context).colorScheme; - final textStyle = Theme - .of(context) - .textTheme; + final textStyle = Theme.of(context).textTheme; // Widget buildAddContainer(Widget icon) { // return Container( @@ -73,20 +67,20 @@ class EditPage extends StatelessWidget { Widget? buildTagList() { return state.currentDiary.tags.isNotEmpty ? Wrap( - spacing: 8.0, - children: List.generate(state.currentDiary.tags.length, (index) { - return Chip( - label: Text( - state.currentDiary.tags[index], - style: TextStyle(color: colorScheme.onSecondaryContainer), - ), - backgroundColor: colorScheme.secondaryContainer, - onDeleted: () { - logic.removeTag(index); - }, - ); - }), - ) + spacing: 8.0, + children: List.generate(state.currentDiary.tags.length, (index) { + return Chip( + label: Text( + state.currentDiary.tags[index], + style: TextStyle(color: colorScheme.onSecondaryContainer), + ), + backgroundColor: colorScheme.secondaryContainer, + onDeleted: () { + logic.removeTag(index); + }, + ); + }), + ) : null; } @@ -402,7 +396,7 @@ class EditPage extends StatelessWidget { value: state.currentDiary.mood, divisions: 10, label: - '${(state.currentDiary.mood * 100).toStringAsFixed(0)}%', + '${(state.currentDiary.mood * 100).toStringAsFixed(0)}%', activeColor: Color.lerp(AppColor.emoColorList.first, AppColor.emoColorList.last, state.currentDiary.mood), onChanged: (value) { @@ -541,17 +535,16 @@ class EditPage extends StatelessWidget { title: const Text('天气'), subtitle: state.currentDiary.weather.isNotEmpty ? Text( - '${state.currentDiary.weather[2]} ${state.currentDiary - .weather[1]}°C') + '${state.currentDiary.weather[2]} ${state.currentDiary.weather[1]}°C') : null, trailing: state.isProcessing ? const CircularProgressIndicator() : IconButton.filledTonal( - onPressed: () async { - await logic.getPositionAndWeather(); - }, - icon: const Icon(Icons.location_on), - ), + onPressed: () async { + await logic.getPositionAndWeather(); + }, + icon: const Icon(Icons.location_on), + ), ); }), GetBuilder( @@ -725,14 +718,15 @@ class EditPage extends StatelessWidget { headerStyleType: HeaderStyleType.buttons, buttonOptions: QuillSimpleToolbarButtonOptions( selectHeaderStyleButtons: - QuillToolbarSelectHeaderStyleButtonsOptions( - iconTheme: QuillIconTheme(iconButtonSelectedData:IconButtonData( - color: colorScheme.onPrimary, - )),) - ), + QuillToolbarSelectHeaderStyleButtonsOptions( + iconTheme: QuillIconTheme( + iconButtonSelectedData: IconButtonData( + color: colorScheme.onPrimary, + )), + )), showLink: false, embedButtons: [ - (context, embedContext) { + (context, embedContext) { return _buildToolBarButton( iconData: Icons.format_indent_increase, tooltip: 'Text Indent', @@ -827,10 +821,8 @@ class EditPage extends StatelessWidget { expands: true, paintCursorAboveText: true, keyboardAppearance: - CupertinoTheme.maybeBrightnessOf(context) ?? - Theme - .of(context) - .brightness, + CupertinoTheme.maybeBrightnessOf(context) ?? + Theme.of(context).brightness, customStyles: ThemeUtil.getInstance(context, customColorScheme: colorScheme), embedBuilders: [ diff --git a/lib/pages/font/font_logic.dart b/lib/pages/font/font_logic.dart index 8c46ced..43f9cfa 100644 --- a/lib/pages/font/font_logic.dart +++ b/lib/pages/font/font_logic.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:mood_diary/src/rust/api/font.dart'; import 'package:mood_diary/utils/file_util.dart'; -import 'package:path/path.dart'; import '../../utils/data/pref.dart'; import '../../utils/notice_util.dart'; @@ -82,13 +81,14 @@ class FontLogic extends GetxController with GetSingleTickerProviderStateMixin { NoticeUtil.showToast('字体已存在'); return; } - var newPath = FileUtil.getRealPath('font', basename(path)); + var newPath = FileUtil.getRealPath('font', '$fontName.ttf'); File(path).copy(newPath); await getFontList(inInit: false); NoticeUtil.showToast('添加成功'); } else { NoticeUtil.showToast('取消文件选择'); } + update(); } //更改字体 diff --git a/lib/src/rust/api/compress.dart b/lib/src/rust/api/compress.dart index 6287840..12e5623 100644 --- a/lib/src/rust/api/compress.dart +++ b/lib/src/rust/api/compress.dart @@ -3,9 +3,10 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + import '../frb_generated.dart'; import 'constants.dart'; -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; // These functions are ignored because they are not marked as `pub`: `calculate_target_dimensions`, `load_image` diff --git a/lib/src/rust/api/constants.dart b/lib/src/rust/api/constants.dart index fb5f738..0d68c66 100644 --- a/lib/src/rust/api/constants.dart +++ b/lib/src/rust/api/constants.dart @@ -3,9 +3,10 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import -import '../frb_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import '../frb_generated.dart'; + // These function are ignored because they are on traits that is not defined in current crate (put an empty `#[frb]` on it to unignore): `assert_receiver_is_total_eq`, `eq` enum CompressFormat { diff --git a/lib/src/rust/api/kmp.dart b/lib/src/rust/api/kmp.dart index cfaa03f..bcde6f1 100644 --- a/lib/src/rust/api/kmp.dart +++ b/lib/src/rust/api/kmp.dart @@ -3,9 +3,10 @@ // ignore_for_file: invalid_use_of_internal_member, unused_import, unnecessary_import -import '../frb_generated.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +import '../frb_generated.dart'; + Future buildPrefixTable({required List pattern}) => RustLib.instance.api.crateApiKmpBuildPrefixTable(pattern: pattern); diff --git a/lib/src/rust/frb_generated.dart b/lib/src/rust/frb_generated.dart index 0c08d64..c81af67 100644 --- a/lib/src/rust/frb_generated.dart +++ b/lib/src/rust/frb_generated.dart @@ -3,16 +3,18 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; + import 'api/compress.dart'; import 'api/constants.dart'; import 'api/font.dart'; import 'api/kmp.dart'; -import 'dart:async'; -import 'dart:convert'; import 'frb_generated.dart'; import 'frb_generated.io.dart' - if (dart.library.js_interop) 'frb_generated.web.dart'; -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart'; +if (dart.library.js_interop) 'frb_generated.webated.dart'; /// Main entrypoint of the Rust API class RustLib extends BaseEntrypoint { diff --git a/lib/src/rust/frb_generated.io.dart b/lib/src/rust/frb_generated.io.dart index 9a60958..3ff9d68 100644 --- a/lib/src/rust/frb_generated.io.dart +++ b/lib/src/rust/frb_generated.io.dart @@ -3,15 +3,17 @@ // ignore_for_file: unused_import, unused_element, unnecessary_import, duplicate_ignore, invalid_use_of_internal_member, annotate_overrides, non_constant_identifier_names, curly_braces_in_flow_control_structures, prefer_const_literals_to_create_immutables, unused_field +import 'dart:async'; +import 'dart:convert'; +import 'dart:ffi' as ffi; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; + import 'api/compress.dart'; import 'api/constants.dart'; import 'api/font.dart'; import 'api/kmp.dart'; -import 'dart:async'; -import 'dart:convert'; -import 'dart:ffi' as ffi; import 'frb_generated.dart'; -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { RustLibApiImplPlatform({ diff --git a/lib/src/rust/frb_generated.web.dart b/lib/src/rust/frb_generated.web.dart index e9969af..e587584 100644 --- a/lib/src/rust/frb_generated.web.dart +++ b/lib/src/rust/frb_generated.web.dart @@ -6,14 +6,16 @@ // Static analysis wrongly picks the IO variant, thus ignore this // ignore_for_file: argument_type_not_assignable +import 'dart:async'; +import 'dart:convert'; + +import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; + import 'api/compress.dart'; import 'api/constants.dart'; import 'api/font.dart'; import 'api/kmp.dart'; -import 'dart:async'; -import 'dart:convert'; import 'frb_generated.dart'; -import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_web.dart'; abstract class RustLibApiImplPlatform extends BaseApiImpl { RustLibApiImplPlatform({