diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index 7c4a4e8..6744150 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher2.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher2.png index f833d7f..b35e580 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher2.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher2.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index bbfcfa2..f717c27 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher2.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher2.png index 270b6cb..c31590c 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher2.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher2.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 9de0224..b288e2d 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher2.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher2.png index 2ffd647..37e8815 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher2.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher2.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d18b10f..bf3f81a 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher2.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher2.png index dcecf72..ed9bccb 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher2.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher2.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 390a843..db0c418 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher2.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher2.png index 937d7d0..b372304 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher2.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher2.png differ diff --git a/assets/icon/app_icon.png b/assets/icon/app_icon.png index 797e9d9..72fc5bc 100644 Binary files a/assets/icon/app_icon.png and b/assets/icon/app_icon.png differ diff --git a/assets/icon/app_icon2.png b/assets/icon/app_icon2.png index 9637dd5..e23ba03 100644 Binary files a/assets/icon/app_icon2.png and b/assets/icon/app_icon2.png differ diff --git a/lib/pages/profile_page.dart b/lib/pages/profile_page.dart index df6233d..c206ed6 100644 --- a/lib/pages/profile_page.dart +++ b/lib/pages/profile_page.dart @@ -993,6 +993,18 @@ class _SettingsPageState extends State { onTap: () => launchUrl(Uri.parse('https://mooknote.iletter.top/#/')), ), + Divider( + height: 0.5, + indent: 24, + endIndent: 24, + color: colors.outlineVariant), + _buildActionItem( + icon: Icons.open_in_new_outlined, + title: '项目源码', + subtitle: '查看 GitHub 项目仓库', + onTap: () => + launchUrl(Uri.parse('https://github.com/dellevin/mooknote')), + ), Divider( height: 0.5, indent: 24, diff --git a/lib/utils/sync/backup_service.dart b/lib/utils/sync/backup_service.dart index 8ce1559..3af6fd7 100644 --- a/lib/utils/sync/backup_service.dart +++ b/lib/utils/sync/backup_service.dart @@ -7,6 +7,7 @@ import 'package:flutter/foundation.dart'; import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as path; import 'package:share_plus/share_plus.dart'; +import 'package:shared_preferences/shared_preferences.dart'; import 'package:sqflite/sqflite.dart'; import '../database_helper.dart'; import '../user_prefs.dart'; @@ -75,6 +76,7 @@ class BackupService { 'appName': 'MookNote', 'hasImages': true, 'userInfo': userInfo, + 'sharedPrefs': await _exportSharedPrefs(), 'data': { 'movies': movies, 'books': books, @@ -455,6 +457,44 @@ class BackupService { } } } + + // 恢复完整 SharedPreferences + if (backupData.containsKey('sharedPrefs')) { + await _restoreSharedPrefs(backupData['sharedPrefs'] as Map); + } + } + + /// 导出完整 SharedPreferences + Future> _exportSharedPrefs() async { + final prefs = await SharedPreferences.getInstance(); + final keys = prefs.getKeys(); + final map = {}; + for (final key in keys) { + map[key] = prefs.get(key); + } + return map; + } + + /// 恢复 SharedPreferences(保留当前 avatarPath,因为已在上面用 imagePathMap 更新过) + Future _restoreSharedPrefs(Map data) async { + final prefs = await SharedPreferences.getInstance(); + for (final entry in data.entries) { + final key = entry.key; + final value = entry.value; + // avatarPath 已单独处理,跳过 + if (key == 'avatarPath') continue; + if (value is String) { + await prefs.setString(key, value); + } else if (value is int) { + await prefs.setInt(key, value); + } else if (value is double) { + await prefs.setDouble(key, value); + } else if (value is bool) { + await prefs.setBool(key, value); + } else if (value is List) { + await prefs.setStringList(key, value.cast()); + } + } } Map _buildStats(Map data, int imageCount) { diff --git a/lib/utils/sync/webdav_service.dart b/lib/utils/sync/webdav_service.dart index 0cf3e58..50dfe0f 100644 --- a/lib/utils/sync/webdav_service.dart +++ b/lib/utils/sync/webdav_service.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; -import 'dart:typed_data'; +import 'package:flutter/foundation.dart'; import 'package:http/http.dart' as http; import 'package:path_provider/path_provider.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -227,7 +227,7 @@ class WebDAVService { if (success) { uploadedFiles = 1; uploadedImages = exportResult.imageCount; - print('[WebDAV] 备份上传成功 (影视${exportResult.movieCount} 书籍${exportResult.bookCount} 笔记${exportResult.noteCount} 图片${exportResult.imageCount})'); + debugPrint('[WebDAV] 备份上传成功 (影视${exportResult.movieCount} 书籍${exportResult.bookCount} 笔记${exportResult.noteCount} 图片${exportResult.imageCount})'); } else { return SyncResult(success: false, message: '上传备份文件失败'); } @@ -246,7 +246,7 @@ class WebDAVService { downloadedFiles = 1; downloadedImages = importResult.stats?['图片'] ?? 0; needReload = true; - print('[WebDAV] 备份恢复成功: ${importResult.statsText}'); + debugPrint('[WebDAV] 备份恢复成功: ${importResult.statsText}'); } else { return SyncResult(success: false, message: importResult.errorMessage ?? '恢复备份失败'); } @@ -268,11 +268,11 @@ class WebDAVService { downloadedFiles = 1; downloadedImages = importResult.stats?['图片'] ?? 0; needReload = true; - print('[WebDAV] 远程备份已恢复: ${importResult.statsText}'); + debugPrint('[WebDAV] 远程备份已恢复: ${importResult.statsText}'); } } else { try { await tempZip.delete(); } catch (_) {} - print('[WebDAV] 服务器无备份,仅上传本地数据'); + debugPrint('[WebDAV] 服务器无备份,仅上传本地数据'); } // 始终上传本地,确保远程是最新的 @@ -282,7 +282,7 @@ class WebDAVService { if (uploadSuccess) { uploadedFiles = 1; uploadedImages = exportResult.imageCount; - print('[WebDAV] 本地备份已上传 (影视${exportResult.movieCount} 书籍${exportResult.bookCount} 笔记${exportResult.noteCount} 图片${exportResult.imageCount})'); + debugPrint('[WebDAV] 本地备份已上传 (影视${exportResult.movieCount} 书籍${exportResult.bookCount} 笔记${exportResult.noteCount} 图片${exportResult.imageCount})'); } } } @@ -338,7 +338,7 @@ class WebDAVService { await prefs.setBool(_autoSyncKey, true); // 立即执行一次同步 - print('[WebDAV] 自动同步已启动,间隔 $_autoSyncIntervalMinutes 分钟'); + debugPrint('[WebDAV] 自动同步已启动,间隔 $_autoSyncIntervalMinutes 分钟'); await syncData(direction: SyncDirection.bidirectional); // 设置定时器 @@ -407,10 +407,10 @@ class WebDAVService { } } - print('[WebDAV] PUT $url -> ${response.statusCode}'); + debugPrint('[WebDAV] PUT $url -> ${response.statusCode}'); return response.statusCode == 200 || response.statusCode == 201 || response.statusCode == 204; } catch (e) { - print('[WebDAV] _uploadBytes error: $e'); + debugPrint('[WebDAV] _uploadBytes error: $e'); return false; } } @@ -440,13 +440,13 @@ class WebDAVService { } } - print('[WebDAV] GET $url -> ${response.statusCode}'); + debugPrint('[WebDAV] GET $url -> ${response.statusCode}'); if (response.statusCode == 200) { await localFile.parent.create(recursive: true); final bytes = await response.stream.toBytes(); await localFile.writeAsBytes(bytes); - print('[WebDAV] Downloaded ${bytes.length} bytes'); + debugPrint('[WebDAV] Downloaded ${bytes.length} bytes'); return true; } return false;