From 9fd80f83c8c8cf2dd6d76436e3e954318e9347a8 Mon Sep 17 00:00:00 2001 From: DelLevin-Home Date: Tue, 30 Jun 2026 15:12:11 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 21 -- lib/models/data_models.dart | 2 +- lib/models/note_plus_models.dart | 4 +- lib/pages/book/book_detail_page.dart | 69 ++--- lib/pages/book/book_reviews_page.dart | 12 - lib/pages/epub_reader/reader_screen.dart | 32 +- lib/pages/main_content_page.dart | 1 - lib/pages/movies/douban_webview_page.dart | 2 - lib/pages/movies/movie_detail_page.dart | 82 ++---- lib/pages/movies/movie_form_page.dart | 1 - lib/pages/movies/movie_posters_page.dart | 3 - .../movies/movie_review_detail_page.dart | 1 - lib/pages/movies/movie_review_form_page.dart | 1 - lib/pages/movies/movie_reviews_page.dart | 12 - lib/pages/movies/movie_tab_page.dart | 2 - lib/pages/movies/poster_gallery_page.dart | 1 - lib/pages/note/note_detail_page.dart | 40 ++- lib/pages/note/note_share_page.dart | 1 - lib/pages/note/note_tab_page.dart | 20 +- lib/pages/online_search/search_page.dart | 1 - lib/pages/recycle_bin_page.dart | 35 ++- lib/providers/app_provider.dart | 40 +++ lib/providers/note_plus_provider.dart | 10 - lib/utils/database_helper.dart | 10 - lib/utils/epub/volume_control_service.dart | 50 ---- lib/utils/user_prefs.dart | 2 +- lib/widgets/book_list_item.dart | 1 - lib/widgets/custom_drawer.dart | 2 - lib/widgets/movie_list_item.dart | 1 - lib/widgets/note_list_item.dart | 278 ++++++++++-------- 30 files changed, 313 insertions(+), 424 deletions(-) delete mode 100644 lib/utils/epub/volume_control_service.dart diff --git a/lib/main.dart b/lib/main.dart index 7e631ef..f7dad7b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -187,8 +187,6 @@ class _MyAppState extends State with WidgetsBindingObserver { @override Widget build(BuildContext context) { - final iconName = UserPrefs().appIconName; - return MultiProvider( providers: [ ChangeNotifierProvider.value(value: widget.appProvider), @@ -221,9 +219,6 @@ class _MyAppState extends State with WidgetsBindingObserver { navigatorKey: _navigatorKey, navigatorObservers: [routeObserver], onGenerateRoute: AppRouter.generateRoute, - builder: (context, child) { - return _AppIconWrapper(iconName: iconName, child: child!); - }, ); }, ); @@ -232,19 +227,3 @@ class _MyAppState extends State with WidgetsBindingObserver { ); } } - -class _AppIconWrapper extends StatefulWidget { - final Widget child; - final String iconName; - const _AppIconWrapper({required this.child, required this.iconName}); - - @override - State<_AppIconWrapper> createState() => _AppIconWrapperState(); -} - -class _AppIconWrapperState extends State<_AppIconWrapper> { - @override - Widget build(BuildContext context) { - return widget.child; - } -} diff --git a/lib/models/data_models.dart b/lib/models/data_models.dart index b9c2a10..dac1258 100644 --- a/lib/models/data_models.dart +++ b/lib/models/data_models.dart @@ -10,7 +10,7 @@ const _copyWithNull = _CopyWithNullSentinel(); /// 安全解析日期字符串,失败时返回 fallback DateTime? _safeParseDate(String? str, {DateTime? fallback}) { if (str == null || str.isEmpty) return fallback; - return DateTime.tryParse(str) ?? fallback; + return DateTime.tryParse(str)?.toLocal() ?? fallback; } /// 解析字符串列表(通用工具函数,不限于 Movie) diff --git a/lib/models/note_plus_models.dart b/lib/models/note_plus_models.dart index e893091..c3d74ce 100644 --- a/lib/models/note_plus_models.dart +++ b/lib/models/note_plus_models.dart @@ -241,10 +241,10 @@ class NotePlusDocument { tags: _parseStringList(json['tags'] as String?), images: _parseStringList(json['images'] as String?), createdAt: json['created_at'] != null - ? DateTime.tryParse(json['created_at'] as String) ?? DateTime.now() + ? (DateTime.tryParse(json['created_at'] as String)?.toLocal() ?? DateTime.now()) : DateTime.now(), updatedAt: json['updated_at'] != null - ? DateTime.tryParse(json['updated_at'] as String) ?? DateTime.now() + ? (DateTime.tryParse(json['updated_at'] as String)?.toLocal() ?? DateTime.now()) : DateTime.now(), isDeleted: (json['is_deleted'] as int?) == 1, ); diff --git a/lib/pages/book/book_detail_page.dart b/lib/pages/book/book_detail_page.dart index da14cd1..7788018 100644 --- a/lib/pages/book/book_detail_page.dart +++ b/lib/pages/book/book_detail_page.dart @@ -4,8 +4,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import '../../widgets/fade_in_local_image.dart'; -import 'package:share_plus/share_plus.dart'; -import 'package:cross_file/cross_file.dart'; import '../../providers/app_provider.dart'; import '../../models/data_models.dart'; import '../../utils/toast_util.dart'; @@ -335,27 +333,25 @@ class _BookDetailPageState extends State { required Color backgroundColor, required Color foregroundColor, }) { - return Material( - color: Colors.transparent, - child: Ink( - width: 40, - height: 40, - decoration: BoxDecoration( - color: backgroundColor, - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: backgroundColor.withValues(alpha: 0.3), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: IconButton( - icon: Icon(icon, size: 18, color: foregroundColor), - onPressed: onPressed, - padding: EdgeInsets.zero, - tooltip: tooltip, + return Tooltip( + message: tooltip, + child: GestureDetector( + onTap: onPressed, + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: backgroundColor, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: backgroundColor.withValues(alpha: 0.3), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Icon(icon, size: 18, color: foregroundColor), ), ), ); @@ -1252,35 +1248,8 @@ class _BookDetailPageState extends State { ); } - Future _downloadCover(Book book) async { - if (book.coverPath == null || book.coverPath!.isEmpty) { - ToastUtil.show(context, '没有可下载的封面'); - return; - } - try { - final sourceFile = File(book.coverPath!); - if (!await sourceFile.exists()) { - ToastUtil.show(context, '封面文件不存在'); - return; - } - final timestamp = DateTime.now().millisecondsSinceEpoch; - final fileName = '${book.title}_${timestamp}_封面.jpg'; - - final tempDir = await Directory.systemTemp.createTemp(); - final tempFile = File('${tempDir.path}/$fileName'); - await sourceFile.copy(tempFile.path); - - await Share.shareXFiles( - [XFile(tempFile.path)], - subject: '${book.title} 封面', - text: '下载自 MookNote', - ); - } catch (e) { - ToastUtil.show(context, '下载失败: $e'); - } - } void _showSharePoster(Book book) { Navigator.push( diff --git a/lib/pages/book/book_reviews_page.dart b/lib/pages/book/book_reviews_page.dart index 5be2f86..b574187 100644 --- a/lib/pages/book/book_reviews_page.dart +++ b/lib/pages/book/book_reviews_page.dart @@ -291,18 +291,6 @@ class _BookReviewsPageState extends State { ).then((_) => _loadReviews()); } - void _navigateToEditReview(BookReview review) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => BookReviewFormPage( - bookId: widget.book.id, - review: review, - ), - ), - ).then((_) => _loadReviews()); - } - void _navigateToReviewDetail(BookReview review) { Navigator.push( context, diff --git a/lib/pages/epub_reader/reader_screen.dart b/lib/pages/epub_reader/reader_screen.dart index 27549d1..f028244 100644 --- a/lib/pages/epub_reader/reader_screen.dart +++ b/lib/pages/epub_reader/reader_screen.dart @@ -10,7 +10,6 @@ import '../../utils/epub/epub_stream_service.dart'; import '../../utils/epub/epub_parser.dart'; import '../../utils/epub/reader_settings.dart'; import '../../utils/epub/reader_models.dart'; -import '../../utils/epub/volume_control_service.dart'; import '../../utils/epub/reader_dao.dart'; import '../../utils/toast_util.dart'; import 'book_session.dart'; @@ -125,7 +124,6 @@ class _ReaderScreenState extends State final GlobalKey scaffoldKey = GlobalKey(); - StreamSubscription? volumeSubscription; bool tocDrawerOpen = false; bool styleDrawerOpen = false; AppLifecycleState? lastLifecycleState = AppLifecycleState.resumed; @@ -195,9 +193,6 @@ class _ReaderScreenState extends State progressDebouncer?.cancel(); removeFootnoteOverlay(animate: false); restoreSystemUI(); - volumeSubscription?.cancel(); - VolumeControlService.disableInterception(); - // 立即保存进度(同步写入,不被 dispose 打断) bookSession.flushProgress( currentChapterIndex: currentSpineItemIndex, currentPageInChapter: currentPageInChapter, @@ -221,31 +216,8 @@ class _ReaderScreenState extends State } void setupVolumeControl() { - final resume = readerSettings.volumeKeyTurnsPage && - !tocDrawerOpen && - !styleDrawerOpen && - lastLifecycleState == AppLifecycleState.resumed; - - if (resume) { - VolumeControlService.enableInterception(); - volumeSubscription ??= VolumeControlService.volumeKeyEvents.listen(( - event, - ) { - if (readerSettings.volumeKeyTurnsPage) { - if (footnoteOverlayEntry != null) { - removeFootnoteOverlay(); - return; - } - if (event == 'up') { - rendererController.performPreviousPageTurn(); - } else if (event == 'down') { - rendererController.performNextPageTurn(); - } - } - }); - } else { - VolumeControlService.disableInterception(); - } + // VolumeControlService removed — native implementation never existed. + // TODO: reimplement if native volume-key interception is added. } void hideBottomNavigationBar() { diff --git a/lib/pages/main_content_page.dart b/lib/pages/main_content_page.dart index 70b4034..0641883 100644 --- a/lib/pages/main_content_page.dart +++ b/lib/pages/main_content_page.dart @@ -3,7 +3,6 @@ import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../utils/user_prefs.dart'; import '../utils/sync/webdav_service.dart'; -import '../utils/toast_util.dart'; import 'movies/movie_tab_page.dart'; import 'book/book_tab_page.dart'; import 'note/note_tab_page.dart'; diff --git a/lib/pages/movies/douban_webview_page.dart b/lib/pages/movies/douban_webview_page.dart index f68a2ad..870ed06 100644 --- a/lib/pages/movies/douban_webview_page.dart +++ b/lib/pages/movies/douban_webview_page.dart @@ -15,7 +15,6 @@ class DoubanWebViewPage extends StatefulWidget { class _DoubanWebViewPageState extends State { late WebViewController _controller; bool _isLoading = true; - bool _canExtract = false; bool _isExtracting = false; // 防止重复提取 @override @@ -47,7 +46,6 @@ class _DoubanWebViewPageState extends State { if (mounted) { setState(() { _isLoading = false; - _canExtract = url.contains('douban.com/subject'); }); } }, diff --git a/lib/pages/movies/movie_detail_page.dart b/lib/pages/movies/movie_detail_page.dart index c9ee56c..bb221c9 100644 --- a/lib/pages/movies/movie_detail_page.dart +++ b/lib/pages/movies/movie_detail_page.dart @@ -3,16 +3,11 @@ import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart' as path; import '../../widgets/fade_in_local_image.dart'; -import 'package:share_plus/share_plus.dart'; -import 'package:cross_file/cross_file.dart'; -import 'package:permission_handler/permission_handler.dart'; import '../../providers/app_provider.dart'; import '../../models/data_models.dart'; -import '../../utils/toast_util.dart'; import '../../utils/user_prefs.dart'; +import '../../utils/toast_util.dart'; import 'movie_reviews_page.dart'; import 'movie_posters_page.dart'; import 'movie_share_page.dart'; @@ -113,7 +108,7 @@ class _MovieDetailPageState extends State { ), ), ), - // 导航栏 + // 详情页面的标准顶部导航栏 Positioned( top: 0, left: 0, right: 0, child: Container( @@ -387,27 +382,25 @@ class _MovieDetailPageState extends State { required Color backgroundColor, required Color foregroundColor, }) { - return Material( - color: Colors.transparent, - child: Ink( - width: 40, - height: 40, - decoration: BoxDecoration( - color: backgroundColor, - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: backgroundColor.withValues(alpha: 0.3), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: IconButton( - icon: Icon(icon, size: 18, color: foregroundColor), - onPressed: onPressed, - padding: EdgeInsets.zero, - tooltip: tooltip, + return Tooltip( + message: tooltip, + child: GestureDetector( + onTap: onPressed, + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: backgroundColor, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: backgroundColor.withValues(alpha: 0.3), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Icon(icon, size: 18, color: foregroundColor), ), ), ); @@ -1184,11 +1177,15 @@ class _MovieDetailPageState extends State { ), ElevatedButton( onPressed: () async { - await context.read().removeMovie(widget.movie.id); + final provider = context.read(); + await provider.removeMovie(widget.movie.id); if (!mounted) return; - Navigator.pop(context); - Navigator.pop(context); - ToastUtil.show(context, '已删除'); + final navigator = Navigator.of(context); + navigator.pop(); + navigator.pop(); + if (mounted) { + ToastUtil.show(context, '已删除'); + } }, style: ElevatedButton.styleFrom( backgroundColor: colors.error, @@ -1207,27 +1204,6 @@ class _MovieDetailPageState extends State { ); } - Future _requestStoragePermission() async { - if (Platform.isAndroid) { - final sdkInt = await _getAndroidSdkInt(); - if (sdkInt >= 33) { - final status = await Permission.photos.request(); - return status.isGranted; - } else { - var status = await Permission.storage.request(); - if (status.isDenied) { - status = await Permission.storage.request(); - } - return status.isGranted; - } - } - return true; - } - - Future _getAndroidSdkInt() async { - return 30; - } - void _showSharePoster(Movie movie) { Navigator.push( context, diff --git a/lib/pages/movies/movie_form_page.dart b/lib/pages/movies/movie_form_page.dart index 4c7a9ab..bb47262 100644 --- a/lib/pages/movies/movie_form_page.dart +++ b/lib/pages/movies/movie_form_page.dart @@ -3,7 +3,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as p; import 'package:provider/provider.dart'; import 'package:http/http.dart' as http; diff --git a/lib/pages/movies/movie_posters_page.dart b/lib/pages/movies/movie_posters_page.dart index b2689a7..9e88bde 100644 --- a/lib/pages/movies/movie_posters_page.dart +++ b/lib/pages/movies/movie_posters_page.dart @@ -1,8 +1,6 @@ import 'dart:io'; -import 'dart:math'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:path/path.dart' as p; import 'package:provider/provider.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; @@ -133,7 +131,6 @@ class _MoviePostersPageState extends State { } Widget _buildPosterItem(MoviePoster poster, int index) { - final colors = Theme.of(context).colorScheme; // 根据索引生成不同的高度,实现瀑布流效果 final heights = [180.0, 220.0, 160.0, 200.0, 240.0, 190.0]; final height = heights[index % heights.length]; diff --git a/lib/pages/movies/movie_review_detail_page.dart b/lib/pages/movies/movie_review_detail_page.dart index a8e5e1f..750849c 100644 --- a/lib/pages/movies/movie_review_detail_page.dart +++ b/lib/pages/movies/movie_review_detail_page.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../models/data_models.dart'; diff --git a/lib/pages/movies/movie_review_form_page.dart b/lib/pages/movies/movie_review_form_page.dart index b1e609e..f7273bf 100644 --- a/lib/pages/movies/movie_review_form_page.dart +++ b/lib/pages/movies/movie_review_form_page.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../providers/app_provider.dart'; diff --git a/lib/pages/movies/movie_reviews_page.dart b/lib/pages/movies/movie_reviews_page.dart index a3323d6..cf1cb0d 100644 --- a/lib/pages/movies/movie_reviews_page.dart +++ b/lib/pages/movies/movie_reviews_page.dart @@ -291,18 +291,6 @@ class _MovieReviewsPageState extends State { ).then((_) => _loadReviews()); } - void _navigateToEditReview(MovieReview review) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => MovieReviewFormPage( - movieId: widget.movie.id, - review: review, - ), - ), - ).then((_) => _loadReviews()); - } - void _navigateToReviewDetail(MovieReview review) { Navigator.push( context, diff --git a/lib/pages/movies/movie_tab_page.dart b/lib/pages/movies/movie_tab_page.dart index 973f6be..fead832 100644 --- a/lib/pages/movies/movie_tab_page.dart +++ b/lib/pages/movies/movie_tab_page.dart @@ -80,8 +80,6 @@ class _MovieTabPageState extends State { } } - String get _currentStatus => _statusMap[context.read().movieStatusIndex] ?? 'watched'; - Future _loadFirst() async { final provider = context.read(); final statusIdx = provider.movieStatusIndex; diff --git a/lib/pages/movies/poster_gallery_page.dart b/lib/pages/movies/poster_gallery_page.dart index dd5fee5..df80d10 100644 --- a/lib/pages/movies/poster_gallery_page.dart +++ b/lib/pages/movies/poster_gallery_page.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import '../../models/data_models.dart'; import '../../widgets/fade_in_local_image.dart'; diff --git a/lib/pages/note/note_detail_page.dart b/lib/pages/note/note_detail_page.dart index d07ee5a..483995e 100644 --- a/lib/pages/note/note_detail_page.dart +++ b/lib/pages/note/note_detail_page.dart @@ -335,27 +335,25 @@ class _NoteDetailPageState extends State { required Color backgroundColor, required Color foregroundColor, }) { - return Material( - color: Colors.transparent, - child: Ink( - width: 40, - height: 40, - decoration: BoxDecoration( - color: backgroundColor, - shape: BoxShape.circle, - boxShadow: [ - BoxShadow( - color: backgroundColor.withValues(alpha: 0.3), - blurRadius: 8, - offset: const Offset(0, 2), - ), - ], - ), - child: IconButton( - icon: Icon(icon, size: 18, color: foregroundColor), - onPressed: onPressed, - padding: EdgeInsets.zero, - tooltip: tooltip, + return Tooltip( + message: tooltip, + child: GestureDetector( + onTap: onPressed, + child: Container( + width: 40, + height: 40, + decoration: BoxDecoration( + color: backgroundColor, + shape: BoxShape.circle, + boxShadow: [ + BoxShadow( + color: backgroundColor.withValues(alpha: 0.3), + blurRadius: 8, + offset: const Offset(0, 2), + ), + ], + ), + child: Icon(icon, size: 18, color: foregroundColor), ), ), ); diff --git a/lib/pages/note/note_share_page.dart b/lib/pages/note/note_share_page.dart index 462d8db..b808c4a 100644 --- a/lib/pages/note/note_share_page.dart +++ b/lib/pages/note/note_share_page.dart @@ -1,5 +1,4 @@ import 'dart:io'; -import 'dart:typed_data'; import 'dart:ui' as ui; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; diff --git a/lib/pages/note/note_tab_page.dart b/lib/pages/note/note_tab_page.dart index e66289d..59c49a9 100644 --- a/lib/pages/note/note_tab_page.dart +++ b/lib/pages/note/note_tab_page.dart @@ -209,20 +209,17 @@ class _NoteTabPageState extends State { '${date.year}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')} ${date.hour.toString().padLeft(2, '0')}:${date.minute.toString().padLeft(2, '0')}'; Widget _buildWaterfallView() { - final colors = Theme.of(context).colorScheme; final leftItems = []; final rightItems = []; for (int i = 0; i < _items.length; i++) { (i % 2 == 0 ? leftItems : rightItems).add(_items[i]); } - return RefreshIndicator(onRefresh: _refresh, color: colors.primary, backgroundColor: colors.surface, - child: SingleChildScrollView(controller: _scrollController, padding: const EdgeInsets.fromLTRB(12, 8, 12, 100), - child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Expanded(child: Column(children: [...leftItems.map(_buildWaterfallCard), if (_hasMore) _buildLoadMore()])), - const SizedBox(width: 8), - Expanded(child: Column(children: rightItems.map(_buildWaterfallCard).toList())), - ]), - ), + return SingleChildScrollView(controller: _scrollController, padding: const EdgeInsets.fromLTRB(12, 8, 12, 80), + child: Row(crossAxisAlignment: CrossAxisAlignment.start, children: [ + Expanded(child: Column(children: leftItems.map(_buildWaterfallCard).toList())), + const SizedBox(width: 8), + Expanded(child: Column(children: rightItems.map(_buildWaterfallCard).toList())), + ]), ); } @@ -313,9 +310,10 @@ class _NoteTabPageState extends State { title: Text(note.isPinned ? '取消置顶' : '置顶', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: colors.onSurface)), subtitle: Text(note.isPinned ? '取消置顶后按时间排序' : '置顶后始终显示在最前', style: TextStyle(fontSize: 11, color: colors.onSurface.withValues(alpha: 0.4))), trailing: Icon(Icons.chevron_right, color: colors.onSurface.withValues(alpha: 0.25)), - onTap: () { + onTap: () async { Navigator.pop(ctx); - context.read().toggleNotePin(note.id, !note.isPinned); + await context.read().toggleNotePin(note.id, !note.isPinned); + _loadFirst(); }, ), Divider(height: 0.5, color: colors.outlineVariant), diff --git a/lib/pages/online_search/search_page.dart b/lib/pages/online_search/search_page.dart index 415e2b2..9eb633d 100644 --- a/lib/pages/online_search/search_page.dart +++ b/lib/pages/online_search/search_page.dart @@ -201,7 +201,6 @@ class _SearchPageState extends State { } Widget _buildFilterRow() { - final colors = Theme.of(context).colorScheme; final keyword = _searchController.text.trim(); final provider = context.read(); int movieCount = 0, bookCount = 0, noteCount = 0; diff --git a/lib/pages/recycle_bin_page.dart b/lib/pages/recycle_bin_page.dart index fa9a22b..2141ea1 100644 --- a/lib/pages/recycle_bin_page.dart +++ b/lib/pages/recycle_bin_page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; +import '../models/note_plus_models.dart'; import '../utils/toast_util.dart'; /// 回收站页面 @@ -12,7 +13,7 @@ class RecycleBinPage extends StatefulWidget { State createState() => _RecycleBinPageState(); } -enum _ItemType { movie, book, note, movieReview, bookReview } +enum _ItemType { movie, book, note, movieReview, bookReview, bookExcerpt, notePlus } class _DeletedItem { final _ItemType type; @@ -61,6 +62,22 @@ class _DeletedItem { subtitle = '删除于 ${r.updatedAt.year}.${r.updatedAt.month.toString().padLeft(2, '0')}.${r.updatedAt.day.toString().padLeft(2, '0')}', icon = Icons.rate_review_outlined, typeLabel = '书评'; + + _DeletedItem.bookExcerpt(BookExcerpt e) + : type = _ItemType.bookExcerpt, + id = e.id, + title = e.content.isNotEmpty ? e.content : '摘抄', + subtitle = '删除于 ${e.updatedAt.year}.${e.updatedAt.month.toString().padLeft(2, '0')}.${e.updatedAt.day.toString().padLeft(2, '0')}', + icon = Icons.format_quote_outlined, + typeLabel = '书摘'; + + _DeletedItem.notePlus(NotePlusDocument d) + : type = _ItemType.notePlus, + id = d.id, + title = d.title.isNotEmpty ? d.title : '未命名文档', + subtitle = '删除于 ${d.updatedAt.year}.${d.updatedAt.month.toString().padLeft(2, '0')}.${d.updatedAt.day.toString().padLeft(2, '0')}', + icon = Icons.edit_note_outlined, + typeLabel = '高级笔记'; } class _RecycleBinPageState extends State { @@ -85,6 +102,8 @@ class _RecycleBinPageState extends State { final notes = await provider.getDeletedNotes(); final movieReviews = await provider.getDeletedMovieReviews(); final bookReviews = await provider.getDeletedBookReviews(); + final bookExcerpts = await provider.getDeletedBookExcerpts(); + final notePlusDocs = await provider.getDeletedNotePlusDocs(); if (!mounted) return; setState(() { _allItems = [ @@ -93,6 +112,8 @@ class _RecycleBinPageState extends State { for (final n in notes) _DeletedItem.note(n), for (final r in movieReviews) _DeletedItem.movieReview(r), for (final r in bookReviews) _DeletedItem.bookReview(r), + for (final e in bookExcerpts) _DeletedItem.bookExcerpt(e), + for (final d in notePlusDocs) _DeletedItem.notePlus(d), ]; _isLoading = false; }); @@ -166,6 +187,8 @@ class _RecycleBinPageState extends State { _filterChip('笔记', _ItemType.note), _filterChip('影评', _ItemType.movieReview), _filterChip('书评', _ItemType.bookReview), + _filterChip('书摘', _ItemType.bookExcerpt), + _filterChip('高级笔记', _ItemType.notePlus), ], ), ); @@ -356,6 +379,12 @@ class _RecycleBinPageState extends State { case _ItemType.bookReview: await provider.restoreBookReview(item.id); if (mounted) ToastUtil.show(context, '书评已恢复'); + case _ItemType.bookExcerpt: + await provider.restoreBookExcerpt(item.id); + if (mounted) ToastUtil.show(context, '书摘已恢复'); + case _ItemType.notePlus: + await provider.restoreNotePlusDoc(item.id); + if (mounted) ToastUtil.show(context, '高级笔记已恢复'); } _loadDeletedItems(); } @@ -375,6 +404,10 @@ class _RecycleBinPageState extends State { await provider.permanentDeleteMovieReview(item.id); case _ItemType.bookReview: await provider.permanentDeleteBookReview(item.id); + case _ItemType.bookExcerpt: + await provider.permanentDeleteBookExcerpt(item.id); + case _ItemType.notePlus: + await provider.permanentDeleteNotePlusDoc(item.id); } _loadDeletedItems(); if (mounted) ToastUtil.show(context, '已彻底删除'); diff --git a/lib/providers/app_provider.dart b/lib/providers/app_provider.dart index 073a11a..9b40293 100644 --- a/lib/providers/app_provider.dart +++ b/lib/providers/app_provider.dart @@ -1,6 +1,7 @@ import 'dart:collection'; import 'package:flutter/material.dart'; import '../models/data_models.dart'; +import '../models/note_plus_models.dart'; import '../utils/movie/movie_dao.dart'; import '../utils/book/book_dao.dart'; import '../utils/note/note_dao.dart'; @@ -8,6 +9,7 @@ import '../utils/movie/movie_review_dao.dart'; import '../utils/movie/movie_poster_dao.dart'; import '../utils/book/book_review_dao.dart'; import '../utils/book/book_excerpt_dao.dart'; +import '../utils/note_plus/note_plus_dao.dart'; import '../utils/tag/tag_dao.dart'; import '../utils/database_helper.dart'; import '../utils/image_path_helper.dart'; @@ -24,6 +26,7 @@ class AppProvider extends ChangeNotifier { final MoviePosterDao _posterDao = MoviePosterDao(); final BookReviewDao _bookReviewDao = BookReviewDao(); final BookExcerptDao _bookExcerptDao = BookExcerptDao(); + final NotePlusDao _notePlusDao = NotePlusDao(); final TagDao _tagDao = TagDao(); // 数据列表 List _movies = []; @@ -325,6 +328,7 @@ class AppProvider extends ChangeNotifier { Future toggleNotePin(String id, bool isPinned) async { await _noteDao.togglePin(id, isPinned); await loadNotes(); + notifyListeners(); } // ========== 影评相关方法 ========== @@ -494,6 +498,8 @@ class AppProvider extends ChangeNotifier { final deletedNotes = await getDeletedNotes(); final deletedMovieReviews = await getDeletedMovieReviews(); final deletedBookReviews = await getDeletedBookReviews(); + final deletedBookExcerpts = await getDeletedBookExcerpts(); + final deletedNotePlusDocs = await _notePlusDao.getDeleted(); for (final movie in deletedMovies) { await permanentDeleteMovie(movie.id); @@ -510,6 +516,12 @@ class AppProvider extends ChangeNotifier { for (final review in deletedBookReviews) { await _bookReviewDao.permanentDeleteReview(review.id); } + for (final excerpt in deletedBookExcerpts) { + await _bookExcerptDao.permanentDeleteExcerpt(excerpt.id); + } + for (final doc in deletedNotePlusDocs) { + await _notePlusDao.permanentDelete(doc.id); + } await loadMovies(); await loadBooks(); @@ -542,6 +554,34 @@ class AppProvider extends ChangeNotifier { await _bookReviewDao.permanentDeleteReview(id); } + // ========== 摘抄回收站方法 ========== + + Future> getDeletedBookExcerpts() async { + return await _bookExcerptDao.getDeletedExcerpts(); + } + + Future restoreBookExcerpt(String id) async { + await _bookExcerptDao.restoreExcerpt(id); + } + + Future permanentDeleteBookExcerpt(String id) async { + await _bookExcerptDao.permanentDeleteExcerpt(id); + } + + // ========== Note Plus 回收站 ========== + + Future> getDeletedNotePlusDocs() async { + return await _notePlusDao.getDeleted(); + } + + Future restoreNotePlusDoc(String id) async { + await _notePlusDao.restore(id); + } + + Future permanentDeleteNotePlusDoc(String id) async { + await _notePlusDao.permanentDelete(id); + } + // ========== 标签管理方法 ========== Future>> getTags(String type, {bool excludeHidden = false}) async { diff --git a/lib/providers/note_plus_provider.dart b/lib/providers/note_plus_provider.dart index 52d8a34..1d21fce 100644 --- a/lib/providers/note_plus_provider.dart +++ b/lib/providers/note_plus_provider.dart @@ -201,16 +201,6 @@ class NotePlusProvider extends ChangeNotifier { notifyListeners(); } - /// 更新文档所属文件夹 - Future updateDocumentFolder(String id, String folder) async { - final idx = _documents.indexWhere((d) => d.id == id); - if (idx < 0) return; - final doc = _documents[idx].copyWith(parentId: folder, updatedAt: DateTime.now()); - await _dao.update(doc); - _documents[idx] = doc; - notifyListeners(); - } - // ========== Block 操作 ========== void setFocusedBlock(int index) { diff --git a/lib/utils/database_helper.dart b/lib/utils/database_helper.dart index 3d6344f..4bb74d3 100644 --- a/lib/utils/database_helper.dart +++ b/lib/utils/database_helper.dart @@ -580,11 +580,6 @@ class DatabaseHelper { // 创建数据库表 Future _createDB(Database db, int version) async { - const idType = 'INTEGER PRIMARY KEY AUTOINCREMENT'; - const textType = 'TEXT NOT NULL'; - const integerType = 'INTEGER NOT NULL'; - const booleanType = 'INTEGER NOT NULL'; - // 影视表 await db.execute(''' CREATE TABLE movies ( @@ -783,9 +778,4 @@ class DatabaseHelper { } } - // 重新打开(关闭后重新初始化) - Future reopen() async { - await close(); - await database; - } } diff --git a/lib/utils/epub/volume_control_service.dart b/lib/utils/epub/volume_control_service.dart deleted file mode 100644 index 920d7fd..0000000 --- a/lib/utils/epub/volume_control_service.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:flutter/services.dart'; - -/// 音量键翻页服务 -/// 注意:需要原生 Android 实现才能工作,当前为空操作 -class VolumeControlService { - static const MethodChannel _methodChannel = MethodChannel( - 'mooknote/volume_control', - ); - - static bool _available = false; - static bool _checked = false; - - static Future enableInterception() async { - if (!Platform.isAndroid) return; - if (!_checked) await _checkAvailable(); - if (!_available) return; - try { - await _methodChannel.invokeMethod('enableInterception'); - } catch (_) {} - } - - static Future disableInterception() async { - if (!Platform.isAndroid) return; - if (!_available) return; - try { - await _methodChannel.invokeMethod('disableInterception'); - } catch (_) {} - } - - static Stream get volumeKeyEvents { - if (!Platform.isAndroid || !_available) return const Stream.empty(); - // 需要原生 EventChannel 实现,当前返回空流 - return const Stream.empty(); - } - - /// 检查原生端是否实现了该 channel - static Future _checkAvailable() async { - _checked = true; - try { - await _methodChannel.invokeMethod('enableInterception'); - _available = true; - } on MissingPluginException { - _available = false; - } catch (_) { - _available = false; - } - } -} diff --git a/lib/utils/user_prefs.dart b/lib/utils/user_prefs.dart index efdb4d7..dfe63e0 100644 --- a/lib/utils/user_prefs.dart +++ b/lib/utils/user_prefs.dart @@ -35,7 +35,7 @@ class UserPrefs { /// 首次使用日期 DateTime get firstUseDate { final str = prefs.getString('firstUseDate'); - if (str != null) return DateTime.tryParse(str) ?? DateTime.now(); + if (str != null) return DateTime.tryParse(str)?.toLocal() ?? DateTime.now(); return DateTime.now(); } diff --git a/lib/widgets/book_list_item.dart b/lib/widgets/book_list_item.dart index 4911bde..34450b0 100644 --- a/lib/widgets/book_list_item.dart +++ b/lib/widgets/book_list_item.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/data_models.dart'; diff --git a/lib/widgets/custom_drawer.dart b/lib/widgets/custom_drawer.dart index 9d65f45..02afbdb 100644 --- a/lib/widgets/custom_drawer.dart +++ b/lib/widgets/custom_drawer.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -11,7 +10,6 @@ import '../pages/person_list_page.dart'; import '../pages/markdown_reader/md_reader_tab_page.dart'; import '../pages/epub_reader/epub_library_page.dart'; import '../pages/tag_management_page.dart'; -import '../pages/profile_page.dart'; import '../pages/movies/movie_detail_page.dart'; import '../pages/book/book_detail_page.dart'; import '../pages/note/note_detail_page.dart'; diff --git a/lib/widgets/movie_list_item.dart b/lib/widgets/movie_list_item.dart index c2ef078..ba81f83 100644 --- a/lib/widgets/movie_list_item.dart +++ b/lib/widgets/movie_list_item.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../models/data_models.dart'; diff --git a/lib/widgets/note_list_item.dart b/lib/widgets/note_list_item.dart index 28770ef..d17104a 100644 --- a/lib/widgets/note_list_item.dart +++ b/lib/widgets/note_list_item.dart @@ -2,9 +2,8 @@ import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../providers/app_provider.dart'; import '../models/data_models.dart'; -import 'fade_in_local_image.dart'; -/// 笔记列表项组件 - 极简主义设计 +/// 笔记列表项组件 - 卡片式设计,内容展示在卡片内 class NoteListItem extends StatelessWidget { final Note note; @@ -26,7 +25,9 @@ class _NoteListItemContent extends StatelessWidget { @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; - return InkWell( + final previewText = _getPreviewText(note); + + return GestureDetector( onTap: () async { final provider = context.read(); await Navigator.pushNamed(context, '/note-detail', arguments: note); @@ -35,123 +36,95 @@ class _NoteListItemContent extends StatelessWidget { onLongPress: () => _showActions(context), child: Container( margin: const EdgeInsets.only(bottom: 8), - padding: const EdgeInsets.fromLTRB(12, 10, 12, 10), + padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: colors.surfaceContainerHigh, - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ - // 日期行 - Row( - children: [ - Text( - _formatDate(note.createdAt), - style: TextStyle( - fontSize: 11, - color: colors.onSurface.withValues(alpha: 0.4), - ), - ), - const SizedBox(width: 8), - Container( - padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1), - decoration: BoxDecoration( - color: colors.surface, - borderRadius: BorderRadius.circular(3), - ), - child: Text( - 'MD', - style: TextStyle( - fontSize: 9, - fontWeight: FontWeight.w600, - color: colors.onSurface.withValues(alpha: 0.4), - ), - ), - ), - if (note.isPinned) ...[ - const SizedBox(width: 6), - Icon(Icons.push_pin, size: 12, color: colors.primary), - ], - ], - ), - - const SizedBox(height: 6), - + // 标题(带置顶图标) if (note.title.isNotEmpty) ...[ - Text( - note.title, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.w600, - color: colors.onSurface, - height: 1.4, - ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - ], - - if (_collapseBlankLines(_cleanMarkdown(note.content).trim()).isNotEmpty) - Text( - _collapseBlankLines(_cleanMarkdown(note.content).trim()), - style: TextStyle( - fontSize: 13, - color: colors.onSurface.withValues(alpha: 0.6), - height: 1.5, - ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - - // 图片缩略图(最多3张,超出显示 +N) - if (note.images.isNotEmpty) ...[ - const SizedBox(height: 8), + const SizedBox(height: 6), Row( children: [ - for (int i = 0; i < note.images.length.clamp(0, 3); i++) ...[ - if (i > 0) const SizedBox(width: 6), - ClipRRect( - borderRadius: BorderRadius.circular(6), - child: Stack( - children: [ - FadeInLocalImage( - path: note.images[i], - width: 56, height: 56, - fit: BoxFit.cover, - errorWidget: Container(width: 56, height: 56, color: colors.surfaceContainerHighest), - ), - // 第3张且有更多时显示 +N - if (i == 2 && note.images.length > 3) - Positioned.fill( - child: Container( - decoration: BoxDecoration( - color: Colors.black.withValues(alpha: 0.45), - borderRadius: BorderRadius.circular(6), - ), - alignment: Alignment.center, - child: Text('+${note.images.length - 3}', - style: const TextStyle(fontSize: 13, color: Colors.white, fontWeight: FontWeight.w600)), - ), - ), - ], + if (note.isPinned) + Padding( + padding: const EdgeInsets.only(right: 4), + child: Icon(Icons.push_pin, size: 14, color: colors.primary), + ), + Expanded( + child: Text( + note.title, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.w600, + color: colors.onSurface, + height: 1.3, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(width: 12), + Text( + _formatDate(note.createdAt), + style: TextStyle( + fontSize: 11, + color: colors.onSurface.withValues(alpha: 0.35), + ), + ), + ], + ), + ], + + // 内容预览(无标题时才显示置顶和时间,替换原本只有置顶的逻辑) + if (previewText.isNotEmpty) ...[ + const SizedBox(height: 6), + if (note.title.isEmpty) + Row( + children: [ + if (note.isPinned) + Padding( + padding: const EdgeInsets.only(right: 4), + child: Icon(Icons.push_pin, size: 14, color: colors.primary), + ), + const Spacer(), + Text( + _formatDate(note.createdAt), + style: TextStyle( + fontSize: 11, + color: colors.onSurface.withValues(alpha: 0.35), ), ), ], - ], + ), + if (note.title.isEmpty) + const SizedBox(height: 2), + Text( + previewText, + style: TextStyle( + fontSize: 13, + color: colors.onSurface.withValues(alpha: 0.5), + height: 1.5, + ), + maxLines: 3, + overflow: TextOverflow.ellipsis, ), ], + // 标签(换行显示) if (note.tags.isNotEmpty) ...[ - const SizedBox(height: 6), + const SizedBox(height: 8), Wrap( spacing: 6, runSpacing: 4, children: note.tags.map((tag) { return Container( - padding: const EdgeInsets.symmetric(horizontal: 7, vertical: 2), + padding: const EdgeInsets.symmetric( + horizontal: 7, vertical: 2), decoration: BoxDecoration( color: colors.surface, borderRadius: BorderRadius.circular(4), @@ -173,37 +146,82 @@ class _NoteListItemContent extends StatelessWidget { ); } + String _getPreviewText(Note note) { + return _collapseBlankLines(_cleanMarkdown(note.content).trim()); + } + void _showActions(BuildContext context) { final colors = Theme.of(context).colorScheme; showModalBottomSheet( context: context, backgroundColor: colors.surface, - shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(16))), + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.vertical(top: Radius.circular(16))), builder: (ctx) => Padding( padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), child: Column(mainAxisSize: MainAxisSize.min, children: [ - Container(width: 36, height: 4, decoration: BoxDecoration(color: colors.onSurface.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(2))), + Container( + width: 36, + height: 4, + decoration: BoxDecoration( + color: colors.onSurface.withValues(alpha: 0.15), + borderRadius: BorderRadius.circular(2))), const SizedBox(height: 16), ListTile( contentPadding: EdgeInsets.zero, - leading: Container(width: 36, height: 36, decoration: BoxDecoration(color: colors.surfaceContainerHighest, borderRadius: BorderRadius.circular(10)), - child: Icon(note.isPinned ? Icons.push_pin_outlined : Icons.push_pin, size: 20, color: colors.onSurface.withValues(alpha: 0.6))), - title: Text(note.isPinned ? '取消置顶' : '置顶', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: colors.onSurface)), - subtitle: Text(note.isPinned ? '取消置顶后按时间排序' : '置顶后始终显示在最前', style: TextStyle(fontSize: 11, color: colors.onSurface.withValues(alpha: 0.4))), - trailing: Icon(Icons.chevron_right, color: colors.onSurface.withValues(alpha: 0.25)), + leading: Container( + width: 36, + height: 36, + decoration: BoxDecoration( + color: colors.surfaceContainerHighest, + borderRadius: BorderRadius.circular(10)), + child: Icon( + note.isPinned + ? Icons.push_pin_outlined + : Icons.push_pin, + size: 20, + color: colors.onSurface.withValues(alpha: 0.6))), + title: Text(note.isPinned ? '取消置顶' : '置顶', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: colors.onSurface)), + subtitle: Text( + note.isPinned ? '取消置顶后按时间排序' : '置顶后始终显示在最前', + style: TextStyle( + fontSize: 11, + color: colors.onSurface.withValues(alpha: 0.4))), + trailing: Icon(Icons.chevron_right, + color: colors.onSurface.withValues(alpha: 0.25)), onTap: () { Navigator.pop(ctx); - context.read().toggleNotePin(note.id, !note.isPinned); + context + .read() + .toggleNotePin(note.id, !note.isPinned); }, ), Divider(height: 0.5, color: colors.outlineVariant), ListTile( contentPadding: EdgeInsets.zero, - leading: Container(width: 36, height: 36, decoration: BoxDecoration(color: colors.surfaceContainerHighest, borderRadius: BorderRadius.circular(10)), - child: Icon(Icons.delete_outline, size: 20, color: colors.error)), - title: Text('删除', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: colors.error)), - subtitle: Text('删除后可在回收站恢复', style: TextStyle(fontSize: 11, color: colors.onSurface.withValues(alpha: 0.4))), - trailing: Icon(Icons.chevron_right, color: colors.onSurface.withValues(alpha: 0.25)), + leading: Container( + width: 36, + height: 36, + decoration: BoxDecoration( + color: colors.surfaceContainerHighest, + borderRadius: BorderRadius.circular(10)), + child: Icon(Icons.delete_outline, + size: 20, color: colors.error)), + title: Text('删除', + style: TextStyle( + fontSize: 13, + fontWeight: FontWeight.w500, + color: colors.error)), + subtitle: Text('删除后可在回收站恢复', + style: TextStyle( + fontSize: 11, + color: colors.onSurface.withValues(alpha: 0.4))), + trailing: Icon(Icons.chevron_right, + color: colors.onSurface.withValues(alpha: 0.25)), onTap: () { Navigator.pop(ctx); _showDeleteConfirm(context); @@ -220,26 +238,44 @@ class _NoteListItemContent extends StatelessWidget { showDialog( context: context, builder: (ctx) => AlertDialog( - backgroundColor: colors.surface, elevation: 0, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), - title: Text('确认删除', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: colors.onSurface)), + backgroundColor: colors.surface, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12)), + title: Text('确认删除', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: colors.onSurface)), content: Text('确定要删除这条笔记吗?删除后可在回收站恢复。', - style: TextStyle(fontSize: 14, color: colors.onSurface.withValues(alpha: 0.6), height: 1.5)), + style: TextStyle( + fontSize: 14, + color: colors.onSurface.withValues(alpha: 0.6), + height: 1.5)), actions: [ - TextButton(onPressed: () => Navigator.pop(ctx), - child: Text('取消', style: TextStyle(color: colors.onSurface.withValues(alpha: 0.6)))), + TextButton( + onPressed: () => Navigator.pop(ctx), + child: Text('取消', + style: TextStyle( + color: colors.onSurface.withValues(alpha: 0.6)))), ElevatedButton( onPressed: () async { await context.read().removeNote(note.id); Navigator.pop(ctx); }, - style: ElevatedButton.styleFrom(backgroundColor: colors.error, foregroundColor: colors.onError, elevation: 0, - shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8)), + style: ElevatedButton.styleFrom( + backgroundColor: colors.error, + foregroundColor: colors.onError, + elevation: 0, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8)), + padding: const EdgeInsets.symmetric( + horizontal: 16, vertical: 8)), child: const Text('删除'), ), ], - actionsPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + actionsPadding: + const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), ); }