diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index b906d6f..493a7d0 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -32,6 +32,13 @@ android { buildTypes { release { + // 启用代码压缩和资源缩减 + isMinifyEnabled = true + isShrinkResources = true + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. signingConfig = signingConfigs.getByName("debug") diff --git a/android/app/proguard-rules.pro b/android/app/proguard-rules.pro new file mode 100644 index 0000000..b3ec95a --- /dev/null +++ b/android/app/proguard-rules.pro @@ -0,0 +1,33 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. + +# Flutter specific rules +-keep class io.flutter.app.** { *; } +-keep class io.flutter.plugin.** { *; } +-keep class io.flutter.util.** { *; } +-keep class io.flutter.view.** { *; } +-keep class io.flutter.** { *; } +-keep class io.flutter.plugins.** { *; } + +# Keep classes used by reflection +-keep class * { @com.google.gson.annotations.SerializedName ; } + +# SQLite +-keep class net.sqlcipher.** { *; } + +# Prevent obfuscation of model classes +-keep class top.iletter.mooknote.** { *; } + +# Google Play Core - prevent R8 from removing these classes +-dontwarn com.google.android.play.core.splitcompat.SplitCompatApplication +-dontwarn com.google.android.play.core.splitinstall.SplitInstallException +-dontwarn com.google.android.play.core.splitinstall.SplitInstallManager +-dontwarn com.google.android.play.core.splitinstall.SplitInstallManagerFactory +-dontwarn com.google.android.play.core.splitinstall.SplitInstallRequest$Builder +-dontwarn com.google.android.play.core.splitinstall.SplitInstallRequest +-dontwarn com.google.android.play.core.splitinstall.SplitInstallSessionState +-dontwarn com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener +-dontwarn com.google.android.play.core.tasks.OnFailureListener +-dontwarn com.google.android.play.core.tasks.OnSuccessListener +-dontwarn com.google.android.play.core.tasks.Task diff --git a/assets/README/Screenshot_1781866417.png b/assets/README/Screenshot_1781866417.png deleted file mode 100644 index 4c851e5..0000000 Binary files a/assets/README/Screenshot_1781866417.png and /dev/null differ diff --git a/assets/README/Screenshot_1781866427-1781866809535-2.png b/assets/README/Screenshot_1781866427-1781866809535-2.png deleted file mode 100644 index 02bc7f4..0000000 Binary files a/assets/README/Screenshot_1781866427-1781866809535-2.png and /dev/null differ diff --git a/assets/README/Screenshot_1781866427.png b/assets/README/Screenshot_1781866427.png deleted file mode 100644 index 02bc7f4..0000000 Binary files a/assets/README/Screenshot_1781866427.png and /dev/null differ diff --git a/lib/pages/font_picker_page.dart b/lib/pages/font_picker_page.dart index a8e3a8a..fa3a8de 100644 --- a/lib/pages/font_picker_page.dart +++ b/lib/pages/font_picker_page.dart @@ -5,10 +5,11 @@ import 'package:path/path.dart' as path; import 'package:permission_handler/permission_handler.dart'; import '../utils/font_download_manager.dart'; import '../utils/toast_util.dart'; +import '../utils/user_prefs.dart'; /// 字体选择页面 /// -/// 用户输入或选择字体目录,遍历目录下的字体文件,点击即可加载使用。 +/// 用户选择字体目录,遍历目录下的字体文件,点击即可加载使用。 class FontPickerPage extends StatefulWidget { final String? initialFamily; const FontPickerPage({super.key, this.initialFamily}); @@ -18,27 +19,24 @@ class FontPickerPage extends StatefulWidget { } class _FontPickerPageState extends State { - final TextEditingController _pathController = TextEditingController(); final FontDownloadManager _fontManager = FontDownloadManager(); List _fonts = []; String? _loadingPath; String? _selectedFamily; bool _isScanning = false; + String? _currentDirPath; @override void initState() { super.initState(); _selectedFamily = widget.initialFamily; - // 默认填入内置字体目录 - _pathController.text = '/sdcard/Documents/mooknote/fonts'; - _checkPermissionAndScan(); - } - - @override - void dispose() { - _pathController.dispose(); - super.dispose(); + // 恢复上次选择的目录 + final savedDir = UserPrefs().lastFontDir; + if (savedDir != null && savedDir.isNotEmpty) { + _currentDirPath = savedDir; + _scanDirectory(savedDir); + } } /// 请求存储权限(Android 11+ 需要 MANAGE_EXTERNAL_STORAGE) @@ -58,18 +56,6 @@ class _FontPickerPageState extends State { return status.isGranted; } - /// 检查权限并扫描 - Future _checkPermissionAndScan() async { - final hasPermission = await _requestStoragePermission(); - if (!hasPermission) { - if (mounted) { - _showPermissionDialog(); - } - return; - } - await _scanDirectory(); - } - /// 显示权限提示弹窗 void _showPermissionDialog() { final colors = Theme.of(context).colorScheme; @@ -103,12 +89,8 @@ class _FontPickerPageState extends State { } /// 扫描目录字体 - Future _scanDirectory() async { - final dirPath = _pathController.text.trim(); - if (dirPath.isEmpty) { - if (mounted) ToastUtil.show(context, '请输入目录路径'); - return; - } + Future _scanDirectory(String dirPath) async { + if (dirPath.isEmpty) return; setState(() => _isScanning = true); try { @@ -130,18 +112,30 @@ class _FontPickerPageState extends State { } } - /// 使用 file_picker 选择目录 - Future _pickDirectory() async { + /// 扫描当前目录字体 + Future _rescanDirectory() async { + if (_currentDirPath == null || _currentDirPath!.isEmpty) { + ToastUtil.show(context, '请先选择字体目录'); + return; + } + await _scanDirectory(_currentDirPath!); + } + + /// 点击选择目录按钮 + Future _onSelectDirectory() async { final hasPermission = await _requestStoragePermission(); if (!hasPermission) { if (mounted) _showPermissionDialog(); return; } + try { final result = await FilePicker.platform.getDirectoryPath(); if (result != null && result.isNotEmpty) { - _pathController.text = result; - await _scanDirectory(); + _currentDirPath = result; + // 保存到 SharedPreferences + await UserPrefs().setLastFontDir(result); + await _scanDirectory(result); } } catch (e) { if (mounted) ToastUtil.show(context, '选择目录失败: $e'); @@ -195,7 +189,7 @@ class _FontPickerPageState extends State { ), body: Column( children: [ - // 路径输入区 + // 选择目录按钮区 Container( padding: const EdgeInsets.fromLTRB(20, 16, 20, 12), decoration: BoxDecoration( @@ -219,40 +213,49 @@ class _FontPickerPageState extends State { Row( children: [ Expanded( - child: TextField( - controller: _pathController, - style: TextStyle(fontSize: 13, color: colors.onSurface), - decoration: InputDecoration( - hintText: '输入字体目录路径', - hintStyle: TextStyle( - fontSize: 13, - color: colors.onSurface.withValues(alpha: 0.3), - ), - filled: true, - fillColor: colors.surfaceContainerHighest, - contentPadding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 10, - ), - border: OutlineInputBorder( + child: InkWell( + onTap: _onSelectDirectory, + borderRadius: BorderRadius.circular(8), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + decoration: BoxDecoration( + color: colors.surfaceContainerHighest, borderRadius: BorderRadius.circular(8), - borderSide: BorderSide.none, ), - suffixIcon: IconButton( - icon: Icon( - Icons.folder_open_outlined, - size: 18, - color: colors.onSurface.withValues(alpha: 0.5), - ), - onPressed: _pickDirectory, + child: Row( + children: [ + Icon( + Icons.folder_open_outlined, + size: 18, + color: colors.onSurface.withValues(alpha: 0.5), + ), + const SizedBox(width: 8), + Expanded( + child: Text( + _currentDirPath ?? '点击选择字体目录', + style: TextStyle( + fontSize: 13, + color: _currentDirPath != null + ? colors.onSurface + : colors.onSurface.withValues(alpha: 0.3), + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + Icon( + Icons.chevron_right, + size: 18, + color: colors.onSurface.withValues(alpha: 0.3), + ), + ], ), ), - onSubmitted: (_) => _scanDirectory(), ), ), const SizedBox(width: 8), ElevatedButton( - onPressed: _scanDirectory, + onPressed: _rescanDirectory, style: ElevatedButton.styleFrom( backgroundColor: colors.primary, foregroundColor: colors.onPrimary, diff --git a/lib/pages/sync/webdav_sync_page.dart b/lib/pages/sync/webdav_sync_page.dart index 634c4ad..f5c4c1c 100644 --- a/lib/pages/sync/webdav_sync_page.dart +++ b/lib/pages/sync/webdav_sync_page.dart @@ -112,6 +112,8 @@ class _WebDAVSyncPageState extends State { path: path, ); setState(() => _isConfigured = true); + // 保存成功后立即加载远程备份信息 + _loadRemoteInfo(); ToastUtil.show(context, result['message'] ?? '连接成功,配置已保存'); } else { ToastUtil.show(context, result['message'] ?? '连接失败,请检查配置'); diff --git a/lib/utils/user_prefs.dart b/lib/utils/user_prefs.dart index 84c6009..7ad5533 100644 --- a/lib/utils/user_prefs.dart +++ b/lib/utils/user_prefs.dart @@ -267,4 +267,10 @@ class UserPrefs { /// EPUB 句读列表视图模式: 0=瀑布流, 1=列表 int get highlightsViewMode => prefs.getInt('highlightsViewMode') ?? 0; Future setHighlightsViewMode(int value) => prefs.setInt('highlightsViewMode', value); + + // ========== 字体选择器 ========== + + /// 字体选择器上次使用的目录路径 + String? get lastFontDir => prefs.getString('lastFontDir'); + Future setLastFontDir(String value) => prefs.setString('lastFontDir', value); } diff --git a/pubspec.lock b/pubspec.lock index 39d93b1..754b9bc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1,14 +1,6 @@ # Generated by pub # See https://dart.dev/tools/pub/glossary#lockfile packages: - android_intent_plus: - dependency: "direct main" - description: - name: android_intent_plus - sha256: "2329378af63f49b985cb2e110ac784d08374f1e2b1984be77ba9325b1c8cce11" - url: "https://pub.dev" - source: hosted - version: "5.3.1" archive: dependency: "direct main" description: @@ -271,7 +263,7 @@ packages: source: sdk version: "0.0.0" flutter_colorpicker: - dependency: "direct main" + dependency: transitive description: name: flutter_colorpicker sha256: "969de5f6f9e2a570ac660fb7b501551451ea2a1ab9e2097e89475f60e07816ea" @@ -453,14 +445,6 @@ packages: description: flutter source: sdk version: "0.0.0" - gbk_codec: - dependency: "direct main" - description: - name: gbk_codec - sha256: "3af5311fc9393115e3650ae6023862adf998051a804a08fb804f042724999f61" - url: "https://pub.dev" - source: hosted - version: "0.4.0" glob: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 457d138..fb4c4c2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,17 +30,14 @@ dependencies: flutter_staggered_grid_view: ^0.7.0 http: ^1.2.0 url_launcher: ^6.2.5 - android_intent_plus: ^5.0.0 webview_flutter: ^4.8.0 flutter_inappwebview: ^6.1.5 dynamic_color: ^1.8.1 package_info_plus: ^8.0.0 extended_text_field: ^16.0.2 uuid: ^4.5.0 - gbk_codec: ^0.4.0 expandable: ^5.0.1 flutter_quill: ^11.5.0 - flutter_colorpicker: ^1.1.0 dev_dependencies: flutter_test: