代码优化,功能新增

This commit is contained in:
DelLevin-Home
2026-06-26 23:46:37 +08:00
parent f7ef50a677
commit 45137b96d6
59 changed files with 5041 additions and 4937 deletions

View File

@@ -28,7 +28,7 @@ class BookDao {
});
// 分页查询书籍记录
Future<List<Book>> getBooksPaged({String? status, int limit = 20, int offset = 0}) => _wrap('getBooksPaged', () async {
Future<List<Book>> getBooksPaged({String? status, int limit = 20, int offset = 0, int sortMode = 0}) => _wrap('getBooksPaged', () async {
final db = await _dbHelper.database;
String where = 'is_deleted = 0';
List<dynamic> whereArgs = [];
@@ -37,10 +37,18 @@ class BookDao {
whereArgs.add(status);
}
final maps = await db.query('books', where: where, whereArgs: whereArgs,
orderBy: 'created_at DESC', limit: limit, offset: offset);
orderBy: _buildBookOrderBy(sortMode), limit: limit, offset: offset);
return List.generate(maps.length, (i) => Book.fromJson(maps[i]));
});
static String _buildBookOrderBy(int sortMode) {
switch (sortMode) {
case 1: return 'created_at DESC';
case 2: return 'rating DESC NULLS LAST, updated_at DESC';
default: return 'updated_at DESC';
}
}
// 根据状态筛选书籍记录
Future<List<Book>> getBooksByStatus(String status) => _wrap('getBooksByStatus', () async {
final db = await _dbHelper.database;

View File

@@ -39,7 +39,7 @@ class DatabaseHelper {
return await openDatabase(
path,
version: 21,
version: 22,
onCreate: _createDB,
onUpgrade: _onUpgrade,
);
@@ -152,6 +152,10 @@ class DatabaseHelper {
}
} catch (_) {}
}
if (oldVersion < 22) {
// 为笔记表添加置顶字段
await _upgradeNotesTableV22(db);
}
}
/// 升级books表到V11添加ISBN和出版时间字段
@@ -191,6 +195,15 @@ class DatabaseHelper {
}
}
/// 升级notes表到V22添加置顶字段
Future<void> _upgradeNotesTableV22(Database db) async {
final columns = await db.rawQuery('PRAGMA table_info(notes)');
final hasIsPinned = columns.any((col) => col['name'] == 'is_pinned');
if (!hasIsPinned) {
await db.execute('ALTER TABLE notes ADD COLUMN is_pinned INTEGER NOT NULL DEFAULT 0');
}
}
/// 升级到V14创建阅读器书籍表
Future<void> _createReaderBooksTable(Database db) async {
await db.execute('''
@@ -574,7 +587,8 @@ class DatabaseHelper {
images TEXT,
created_at TEXT NOT NULL,
updated_at TEXT NOT NULL,
is_deleted INTEGER DEFAULT 0
is_deleted INTEGER DEFAULT 0,
is_pinned INTEGER NOT NULL DEFAULT 0
)
''');

View File

@@ -28,7 +28,7 @@ class MovieDao {
});
// 分页查询影视记录
Future<List<Movie>> getMoviesPaged({String? status, int limit = 20, int offset = 0}) => _wrap('getMoviesPaged', () async {
Future<List<Movie>> getMoviesPaged({String? status, int limit = 20, int offset = 0, int sortMode = 0}) => _wrap('getMoviesPaged', () async {
final db = await _dbHelper.database;
String where = 'is_deleted = 0';
List<dynamic> whereArgs = [];
@@ -37,10 +37,18 @@ class MovieDao {
whereArgs.add(status);
}
final maps = await db.query('movies', where: where, whereArgs: whereArgs,
orderBy: 'created_at DESC', limit: limit, offset: offset);
orderBy: _buildMovieOrderBy(sortMode), limit: limit, offset: offset);
return List.generate(maps.length, (i) => Movie.fromJson(maps[i]));
});
static String _buildMovieOrderBy(int sortMode) {
switch (sortMode) {
case 1: return 'created_at DESC';
case 2: return 'rating DESC NULLS LAST, updated_at DESC';
default: return 'updated_at DESC';
}
}
// 根据状态筛选影视记录
Future<List<Movie>> getMoviesByStatus(String status) => _wrap('getMoviesByStatus', () async {
final db = await _dbHelper.database;

View File

@@ -16,25 +16,34 @@ class NoteDao {
}
// 获取所有未删除的笔记
Future<List<Note>> getAllNotes() => _wrap('getAllNotes', () async {
Future<List<Note>> getAllNotes({int sortMode = 0}) => _wrap('getAllNotes', () async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query(
'notes',
where: 'is_deleted = ?',
whereArgs: [0],
orderBy: 'created_at DESC',
orderBy: _buildOrderBy(sortMode),
);
return List.generate(maps.length, (i) => Note.fromJson(maps[i]));
});
// 分页查询笔记
Future<List<Note>> getNotesPaged({int limit = 20, int offset = 0}) => _wrap('getNotesPaged', () async {
Future<List<Note>> getNotesPaged({int limit = 20, int offset = 0, int sortMode = 0}) => _wrap('getNotesPaged', () async {
final db = await _dbHelper.database;
final maps = await db.query('notes', where: 'is_deleted = 0',
orderBy: 'created_at DESC', limit: limit, offset: offset);
orderBy: _buildOrderBy(sortMode), limit: limit, offset: offset);
return List.generate(maps.length, (i) => Note.fromJson(maps[i]));
});
/// 根据排序模式生成 ORDER BY 子句,置顶始终排最前
static String _buildOrderBy(int sortMode) {
switch (sortMode) {
case 1: return 'is_pinned DESC, created_at DESC';
case 2: return 'is_pinned DESC, title COLLATE NOCASE ASC';
default: return 'is_pinned DESC, updated_at DESC';
}
}
// 根据ID获取笔记
Future<Note?> getNoteById(String id) => _wrap('getNoteById', () async {
final db = await _dbHelper.database;
@@ -75,6 +84,17 @@ class NoteDao {
);
});
// 切换笔记置顶状态
Future<int> togglePin(String id, bool isPinned) => _wrap('togglePin', () async {
final db = await _dbHelper.database;
return await db.update(
'notes',
{'is_pinned': isPinned ? 1 : 0, 'updated_at': DateTime.now().toIso8601String()},
where: 'id = ?',
whereArgs: [id],
);
});
// ========== 回收站相关方法 ==========
// 获取已删除的笔记

View File

@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as path;
import 'package:shared_preferences/shared_preferences.dart';
@@ -67,7 +68,7 @@ class AutoBackupService {
try {
final backupDir = await _getBackupDirectory();
if (backupDir == null) {
print('AutoBackup: 无法获取备份目录');
debugPrint('AutoBackup: 无法获取备份目录');
return;
}
@@ -80,7 +81,7 @@ class AutoBackupService {
final result = await BackupService.instance.exportDataForAutoBackup();
if (!result.success) {
print('AutoBackup: 导出失败 - ${result.errorMessage}');
debugPrint('AutoBackup: 导出失败 - ${result.errorMessage}');
return;
}
@@ -91,13 +92,13 @@ class AutoBackupService {
// 写入备份文件
await backupFile.writeAsBytes(result.zipBytes!);
print('AutoBackup: 备份成功 - ${backupFile.path}');
debugPrint('AutoBackup: 备份成功 - ${backupFile.path}');
// 清理旧备份,只保留最新的10
// 清理旧备份,只保留最新的5
await _cleanupOldBackups(backupDir);
} catch (e) {
print('AutoBackup: 备份失败 - $e');
debugPrint('AutoBackup: 备份失败 - $e');
}
}
@@ -134,12 +135,12 @@ class AutoBackupService {
return downloadDir;
} catch (e) {
print('AutoBackup: 获取备份目录失败 - $e');
debugPrint('AutoBackup: 获取备份目录失败 - $e');
return null;
}
}
/// 清理旧备份,只保留最新的10
/// 清理旧备份,只保留最新的5
Future<void> _cleanupOldBackups(Directory backupDir) async {
try {
final files = await backupDir
@@ -160,14 +161,14 @@ class AutoBackupService {
for (var i = _maxBackups; i < files.length; i++) {
try {
await files[i].delete();
print('AutoBackup: 删除旧备份 - ${files[i].path}');
debugPrint('AutoBackup: 删除旧备份 - ${files[i].path}');
} catch (e) {
print('AutoBackup: 删除旧备份失败 - $e');
debugPrint('AutoBackup: 删除旧备份失败 - $e');
}
}
}
} catch (e) {
print('AutoBackup: 清理旧备份失败 - $e');
debugPrint('AutoBackup: 清理旧备份失败 - $e');
}
}
@@ -194,7 +195,7 @@ class AutoBackupService {
return files;
} catch (e) {
print('AutoBackup: 获取备份列表失败 - $e');
debugPrint('AutoBackup: 获取备份列表失败 - $e');
return [];
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -26,8 +26,9 @@ class AppTheme {
static const Color wantToReadColor = Color(0xFF999999); // 想读 - 浅灰
static const Color readingColor = Color(0xFF666666); // 在读 - 中灰
// 字体配置
static const String _fontFamily = 'Inter';
// 字体配置(空字符串 = 系统默认)
static String _fontFamily = '';
static void setFontFamily(String value) => _fontFamily = value;
// 字重
static const FontWeight _regular = FontWeight.w400;
@@ -46,8 +47,18 @@ class AppTheme {
static const List<String> colorSchemeNames = ['经典', '靛蓝', '薄荷', '琥珀', '玫瑰', '紫罗兰'];
/// 根据配色索引获取浅色主题
static ThemeData getLightTheme(int index) {
// 莫奈动态取色
static Color? _monetColor;
static void setMonetColor(Color? color) => _monetColor = color;
static Color? get monetColor => _monetColor;
/// 根据配色索引获取浅色主题index -1 = 莫奈自动取色)
static ThemeData getLightTheme(int index, {Color? monetColor}) {
if (index == -1) {
final c = monetColor ?? _monetColor;
if (c != null) return _buildColoredLightTheme(c);
return lightTheme;
}
if (index <= 0) return lightTheme;
return _buildColoredLightTheme(seedColors[index]);
}
@@ -114,7 +125,7 @@ class AppTheme {
selectedItemColor: scheme.primary,
unselectedItemColor: scheme.onSurfaceVariant,
elevation: 0, type: BottomNavigationBarType.fixed,
selectedLabelStyle: const TextStyle(fontFamily: _fontFamily, fontSize: 11, fontWeight: _medium),
selectedLabelStyle: TextStyle(fontFamily: _fontFamily, fontSize: 11, fontWeight: _medium),
unselectedLabelStyle: TextStyle(fontFamily: _fontFamily, fontSize: 11, fontWeight: _regular, color: scheme.onSurfaceVariant),
),
);
@@ -144,7 +155,7 @@ class AppTheme {
),
// AppBar - 极简无边框
appBarTheme: const AppBarTheme(
appBarTheme: AppBarTheme(
backgroundColor: _white,
foregroundColor: _black,
elevation: 0,
@@ -244,7 +255,7 @@ class AppTheme {
),
// 底部导航
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: _white,
selectedItemColor: _black,
unselectedItemColor: _lightGray,
@@ -263,7 +274,7 @@ class AppTheme {
),
// 文字主题
textTheme: const TextTheme(
textTheme: TextTheme(
// 大标题
headlineLarge: TextStyle(
fontFamily: _fontFamily,
@@ -357,7 +368,7 @@ class AppTheme {
outlineVariant: _darkGray,
),
appBarTheme: const AppBarTheme(
appBarTheme: AppBarTheme(
backgroundColor: _black,
foregroundColor: _white,
elevation: 0,
@@ -442,7 +453,7 @@ class AppTheme {
),
),
bottomNavigationBarTheme: const BottomNavigationBarThemeData(
bottomNavigationBarTheme: BottomNavigationBarThemeData(
backgroundColor: _black,
selectedItemColor: _white,
unselectedItemColor: _gray,
@@ -460,7 +471,7 @@ class AppTheme {
),
),
textTheme: const TextTheme(
textTheme: TextTheme(
headlineLarge: TextStyle(
fontFamily: _fontFamily,
fontSize: 32,

View File

@@ -51,6 +51,10 @@ class UserPrefs {
int get colorSchemeIndex => prefs.getInt('colorSchemeIndex') ?? 0;
Future<bool> setColorSchemeIndex(int value) => prefs.setInt('colorSchemeIndex', value);
/// 字体: 空字符串=系统默认
String get fontFamily => prefs.getString('fontFamily') ?? '';
Future<bool> setFontFamily(String value) => prefs.setString('fontFamily', value);
/// 上映日期显示到日true/ 显示到月false
bool get showExactReleaseDate => prefs.getBool('showExactReleaseDate') ?? true;
Future<bool> setShowExactReleaseDate(bool value) => prefs.setBool('showExactReleaseDate', value);
@@ -101,6 +105,18 @@ class UserPrefs {
int get noteLayoutStyle => prefs.getInt('noteLayoutStyle') ?? 0;
Future<bool> setNoteLayoutStyle(int value) => prefs.setInt('noteLayoutStyle', value);
/// 笔记排序方式 (0: 更新时间, 1: 创建时间)
int get noteSortMode => prefs.getInt('noteSortMode') ?? 0;
Future<bool> setNoteSortMode(int value) => prefs.setInt('noteSortMode', value);
/// 影视排序方式 (0: 更新时间, 1: 创建时间, 2: 评分)
int get movieSortMode => prefs.getInt('movieSortMode') ?? 0;
Future<bool> setMovieSortMode(int value) => prefs.setInt('movieSortMode', value);
/// 书籍排序方式 (0: 更新时间, 1: 创建时间, 2: 评分)
int get bookSortMode => prefs.getInt('bookSortMode') ?? 0;
Future<bool> setBookSortMode(int value) => prefs.setInt('bookSortMode', value);
/// 影视布局样式 (0: 海报网格, 1: 列表)
int get movieLayoutStyle => prefs.getInt('movieLayoutStyle') ?? 0;
Future<bool> setMovieLayoutStyle(int value) => prefs.setInt('movieLayoutStyle', value);