diff --git a/lib/models/data_models.dart b/lib/models/data_models.dart index dac1258..d4bcbc1 100644 --- a/lib/models/data_models.dart +++ b/lib/models/data_models.dart @@ -13,6 +13,16 @@ DateTime? _safeParseDate(String? str, {DateTime? fallback}) { return DateTime.tryParse(str)?.toLocal() ?? fallback; } +/// 安全将动态值转为 double,失败时返回 fallback +double? _safeParseDouble(dynamic value, {double? fallback}) { + if (value == null) return fallback; + if (value is double) return value; + if (value is int) return value.toDouble(); + if (value is num) return value.toDouble(); + if (value is String) return double.tryParse(value) ?? fallback; + return fallback; +} + /// 解析字符串列表(通用工具函数,不限于 Movie) List parseStringListGeneric(dynamic data) { if (data == null) return []; @@ -86,14 +96,14 @@ class Movie { genres: _parseStringList(json['genres']), alternateTitles: _parseStringList(json['alternate_titles']), summary: json['summary'], - rating: json['rating']?.toDouble(), + rating: _safeParseDouble(json['rating']), status: json['status'] ?? 'want_to_watch', category: json['category'] ?? 'movie', watchDate: _safeParseDate(json['watch_date']), createdAt: _safeParseDate(json['created_at'], fallback: DateTime.now())!, updatedAt: _safeParseDate(json['updated_at'], fallback: DateTime.now())!, isDeleted: json['is_deleted'] == 1 || json['is_deleted'] == true, - coverOffset: (json['cover_offset'] ?? 0.0).toDouble(), + coverOffset: _safeParseDouble(json['cover_offset'], fallback: 0.0)!, ); } @@ -224,14 +234,14 @@ class Book { publisher: json['publisher'], genres: Movie.parseStringList(json['genres']), summary: json['summary'], - rating: json['rating']?.toDouble(), + rating: _safeParseDouble(json['rating']), status: json['status'] ?? 'want_to_read', isbn: json['isbn'], publishDate: _safeParseDate(json['publish_date']), createdAt: _safeParseDate(json['created_at'], fallback: DateTime.now())!, updatedAt: _safeParseDate(json['updated_at'], fallback: DateTime.now())!, isDeleted: json['is_deleted'] == 1 || json['is_deleted'] == true, - coverOffset: (json['cover_offset'] ?? 0.0).toDouble(), + coverOffset: _safeParseDouble(json['cover_offset'], fallback: 0.0)!, ); } diff --git a/lib/pages/profile_page.dart b/lib/pages/profile_page.dart index 2eeb870..cb7e21c 100644 --- a/lib/pages/profile_page.dart +++ b/lib/pages/profile_page.dart @@ -67,7 +67,6 @@ class _ProfilePageState extends State with RouteAware { Future _loadUserData() async { try { - await UserPrefs.init(); setState(() { _nickname = _userPrefs.nickname; _motto = _userPrefs.motto; diff --git a/lib/providers/app_provider.dart b/lib/providers/app_provider.dart index 9b40293..b9841d4 100644 --- a/lib/providers/app_provider.dart +++ b/lib/providers/app_provider.dart @@ -194,6 +194,7 @@ class AppProvider extends ChangeNotifier { void setThemeMode(ThemeMode mode) { if (_themeMode != mode) { _themeMode = mode; + UserPrefs().setThemeMode(mode.index); // 0=system, 1=light, 2=dark notifyListeners(); } } diff --git a/lib/utils/database_helper.dart b/lib/utils/database_helper.dart index 4bb74d3..803ed4f 100644 --- a/lib/utils/database_helper.dart +++ b/lib/utils/database_helper.dart @@ -9,6 +9,7 @@ class DatabaseHelper { static final DatabaseHelper instance = DatabaseHelper._init(); static Database? _database; static Completer? _reopenCompleter; + static Completer? _initCompleter; DatabaseHelper._init(); @@ -41,13 +42,28 @@ class DatabaseHelper { } Future get database async { - // 如果正在重开,等待完成(无忙等待) + // 如果正在重开,等待完成 if (_reopenCompleter != null) { await _reopenCompleter!.future; } if (_database != null) return _database!; - _database = await _initDB('mooknote.db'); - return _database!; + + // 如果已有初始化在进行,等待它完成 + if (_initCompleter != null) { + return _initCompleter!.future; + } + + _initCompleter = Completer(); + try { + _database = await _initDB('mooknote.db'); + _initCompleter!.complete(_database!); + return _database!; + } catch (e) { + _initCompleter!.completeError(e); + rethrow; + } finally { + _initCompleter = null; + } } Future _initDB(String filePath) async { diff --git a/参考/票根html/maoyan.png b/参考/票根html/maoyan.png deleted file mode 100644 index a0585d8..0000000 Binary files a/参考/票根html/maoyan.png and /dev/null differ diff --git a/参考/票根html/mookiletter.png b/参考/票根html/mookiletter.png deleted file mode 100644 index 7ab0463..0000000 Binary files a/参考/票根html/mookiletter.png and /dev/null differ diff --git a/参考/票根html/票根.html b/参考/票根html/票根.html deleted file mode 100644 index 08bfe46..0000000 --- a/参考/票根html/票根.html +++ /dev/null @@ -1,395 +0,0 @@ - - - - - -猫眼电影 · 票根 - - - - -
-
- - -
- -
猫眼电影
-
- - -
-
-
万达影城(朝阳大悦城IMAX店)
-
- -
-
流浪地球3
-
科幻 / 冒险 / 3D IMAX · 片长148分钟
-
- -
-
- - - - - - 3号IMAX厅 -
-
-
- 8排12座 - | - 2026年6月18日 19:30 -
-
- - -
- -
- - - - -
-
- - - diff --git a/参考/票根html/票根收藏版.html b/参考/票根html/票根收藏版.html deleted file mode 100644 index a95f3ee..0000000 --- a/参考/票根html/票根收藏版.html +++ /dev/null @@ -1,444 +0,0 @@ - - - - - -猫眼电影 · 票根(收藏版) - - - - -
- -
-
- - 猫眼电影 -
-
收藏纪念
PASSENGER COPY
-
- -
-
- - - - - 万达影城(朝阳大悦城IMAX店) -
- -
流浪地球3
-
- 3D IMAX - 科幻 / 冒险 - 片长148分钟 -
- -
-
- 影厅 - 3号IMAX厅 -
-
- 座位 - 8排12座 -
-
- 时间 - 2026/06/18 19:30 -
-
-
- -
-
- - - - - - -
-
- - - - - -
- - - diff --git a/参考/票根html/票根样式三.html b/参考/票根html/票根样式三.html deleted file mode 100644 index 3679ab9..0000000 --- a/参考/票根html/票根样式三.html +++ /dev/null @@ -1,386 +0,0 @@ - - - - - -电影票根 · 收藏版 - - - - -
- - -
- 猫眼电影 - 收藏纪念
COLLECTIBLE
-
- - -
-
- - - - - 万达影城(朝阳大悦城IMAX店) -
- -
流浪地球3
-
- 3D IMAX - 科幻 / 冒险 - 片长148分钟 -
- -
-
- 影厅 - 3号IMAX厅 -
-
- 座位 - 8排12座 -
-
- 时间 - 2026.06.18 19:30 -
-
-
- - -
- - -
- - -
-
-
- 二维码 -
-
- -
-
- 票价 - ¥49.90 -
-
- 服务费 - ¥5.00 -
-
-
- 出票时间 - 2026-06-18 10:32 -
-
- 淘票票 - 已出票 -
-
- 取票码 - 8602 3100 0618 7251 -
-
-
- - -
- TICKET · COLLECTIBLE - NO. MY202606181930 -
- -
- - -