diff --git a/lib/models/data_models.dart b/lib/models/data_models.dart index 35c4929..294c5db 100644 --- a/lib/models/data_models.dart +++ b/lib/models/data_models.dart @@ -25,6 +25,7 @@ class Movie { final DateTime createdAt; final DateTime updatedAt; final bool isDeleted; + final double coverOffset; // 封面偏移量 Movie({ required this.id, @@ -43,6 +44,7 @@ class Movie { required this.createdAt, required this.updatedAt, this.isDeleted = false, + this.coverOffset = 0.0, }); factory Movie.fromJson(Map json) { @@ -71,6 +73,7 @@ class Movie { ? DateTime.parse(json['updated_at']) : DateTime.now(), isDeleted: json['is_deleted'] == 1 || json['is_deleted'] == true, + coverOffset: (json['cover_offset'] ?? 0.0).toDouble(), ); } @@ -92,9 +95,10 @@ class Movie { 'created_at': createdAt.toUtc().toIso8601String(), 'updated_at': updatedAt.toUtc().toIso8601String(), 'is_deleted': isDeleted ? 1 : 0, + 'cover_offset': coverOffset, }; } - + /// 获取封面文件 File? get posterFile { if (posterPath == null || posterPath!.isEmpty) return null; @@ -143,6 +147,7 @@ class Movie { DateTime? createdAt, DateTime? updatedAt, bool? isDeleted, + double? coverOffset, }) { return Movie( id: id ?? this.id, @@ -161,6 +166,7 @@ class Movie { createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, isDeleted: isDeleted ?? this.isDeleted, + coverOffset: coverOffset ?? this.coverOffset, ); } } @@ -182,6 +188,7 @@ class Book { final DateTime createdAt; final DateTime updatedAt; final bool isDeleted; + final double coverOffset; // 封面偏移量 Book({ required this.id, @@ -199,6 +206,7 @@ class Book { required this.createdAt, required this.updatedAt, this.isDeleted = false, + this.coverOffset = 0.0, }); factory Book.fromJson(Map json) { @@ -224,6 +232,7 @@ class Book { ? DateTime.parse(json['updated_at']) : DateTime.now(), isDeleted: json['is_deleted'] == 1 || json['is_deleted'] == true, + coverOffset: (json['cover_offset'] ?? 0.0).toDouble(), ); } @@ -244,9 +253,10 @@ class Book { 'created_at': createdAt.toUtc().toIso8601String(), 'updated_at': updatedAt.toUtc().toIso8601String(), 'is_deleted': isDeleted ? 1 : 0, + 'cover_offset': coverOffset, }; } - + /// 获取封面文件 File? get coverFile { if (coverPath == null || coverPath!.isEmpty) return null; @@ -270,6 +280,7 @@ class Book { DateTime? createdAt, DateTime? updatedAt, bool? isDeleted, + double? coverOffset, }) { return Book( id: id ?? this.id, @@ -287,6 +298,7 @@ class Book { createdAt: createdAt ?? this.createdAt, updatedAt: updatedAt ?? this.updatedAt, isDeleted: isDeleted ?? this.isDeleted, + coverOffset: coverOffset ?? this.coverOffset, ); } } diff --git a/lib/pages/book/book_detail_page.dart b/lib/pages/book/book_detail_page.dart index 0a2d7c5..99bf901 100644 --- a/lib/pages/book/book_detail_page.dart +++ b/lib/pages/book/book_detail_page.dart @@ -42,6 +42,7 @@ class _BookDetailPageState extends State { void initState() { super.initState(); _detailStyle = UserPrefs().detailPageStyle; + _coverOffset.value = widget.book.coverOffset; } @override @@ -361,6 +362,7 @@ class _BookDetailPageState extends State { } : null, onLongPressEnd: hasCover ? (_) { setState(() => _draggingCover = false); + context.read().updateBook(book.copyWith(coverOffset: _coverOffset.value)); } : null, child: ValueListenableBuilder( valueListenable: _coverOffset, diff --git a/lib/pages/main_content_page.dart b/lib/pages/main_content_page.dart index b0e21e8..e056570 100644 --- a/lib/pages/main_content_page.dart +++ b/lib/pages/main_content_page.dart @@ -27,6 +27,7 @@ class _MainContentPageState extends State { late PageController _pageController; bool _isTabTap = false; + bool _syncScheduled = false; @override void initState() { @@ -310,6 +311,19 @@ class _MainContentPageState extends State { final tabs = _enabledTabs; final safeIndex = _mapToEnabledTabIndex(provider.mainTabIndex).clamp(0, tabs.length - 1); + // 从其他页面返回时,修正 PageView 页面与 tab 的一致性 + if (!_syncScheduled) { + _syncScheduled = true; + WidgetsBinding.instance.addPostFrameCallback((_) { + _syncScheduled = false; + if (!mounted || !_pageController.hasClients) return; + final currentPage = _pageController.page?.round() ?? 0; + if (currentPage != safeIndex) { + _pageController.jumpToPage(safeIndex); + } + }); + } + if (_isTabTap && _pageController.hasClients) { _pageController.animateToPage(safeIndex, duration: const Duration(milliseconds: 350), curve: Curves.easeInOut); } diff --git a/lib/pages/movies/movie_detail_page.dart b/lib/pages/movies/movie_detail_page.dart index 512f31a..3a40c38 100644 --- a/lib/pages/movies/movie_detail_page.dart +++ b/lib/pages/movies/movie_detail_page.dart @@ -41,6 +41,7 @@ class _MovieDetailPageState extends State { super.initState(); _showExactDate = UserPrefs().showExactReleaseDate; _detailStyle = UserPrefs().detailPageStyle; + _posterOffset.value = widget.movie.coverOffset; } void _toggleDateDisplay() { @@ -414,6 +415,7 @@ class _MovieDetailPageState extends State { } : null, onLongPressEnd: hasPoster ? (_) { setState(() => _draggingPoster = false); + context.read().updateMovie(movie.copyWith(coverOffset: _posterOffset.value)); } : null, child: ValueListenableBuilder( valueListenable: _posterOffset, diff --git a/lib/pages/stroll_page.dart b/lib/pages/stroll_page.dart index 1a68435..268f364 100644 --- a/lib/pages/stroll_page.dart +++ b/lib/pages/stroll_page.dart @@ -1,4 +1,3 @@ -import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; @@ -6,8 +5,11 @@ import '../providers/app_provider.dart'; import '../models/data_models.dart'; import '../widgets/animated_star_rating.dart'; import '../widgets/fade_in_local_image.dart'; +import 'movies/movie_detail_page.dart'; +import 'book/book_detail_page.dart'; +import 'note/note_detail_page.dart'; -/// 漫步页面 - 随机发现内容 +/// 漫步页面 - 随机发现内容(滑卡形式) class StrollPage extends StatefulWidget { const StrollPage({super.key}); @@ -15,29 +17,26 @@ class StrollPage extends StatefulWidget { State createState() => _StrollPageState(); } -class _StrollPageState extends State with SingleTickerProviderStateMixin { +class _StrollPageState extends State { final _random = Random(); - _StrollItem? _currentItem; - late AnimationController _animController; - late Animation _fadeAnim; - bool _isLoading = false; + final List<_StrollItem> _items = []; + late PageController _pageController; + int _currentIndex = 0; @override void initState() { super.initState(); - _animController = AnimationController(vsync: this, duration: const Duration(milliseconds: 500)); - _fadeAnim = CurvedAnimation(parent: _animController, curve: Curves.easeIn); - _animController.value = 1.0; - _loadRandom(); + _pageController = PageController(viewportFraction: 0.85); + _loadBatch(5); } @override void dispose() { - _animController.dispose(); + _pageController.dispose(); super.dispose(); } - void _loadRandom() { + void _loadBatch(int count) { final provider = context.read(); final movies = provider.movies.where((m) => !m.isDeleted).toList(); final books = provider.books.where((b) => !b.isDeleted).toList(); @@ -48,80 +47,79 @@ class _StrollPageState extends State with SingleTickerProviderStateM if (books.isNotEmpty) categories['book'] = books; if (notes.isNotEmpty) categories['note'] = notes; - if (categories.isEmpty) { - setState(() => _currentItem = null); - return; - } + if (categories.isEmpty) return; final categoryKeys = categories.keys.toList(); - final pickedCategory = categoryKeys[_random.nextInt(categoryKeys.length)]; - - _StrollItem item; - switch (pickedCategory) { - case 'movie': - final m = movies[_random.nextInt(movies.length)]; - item = _StrollItem( - type: 'movie', - title: m.title, - subtitle: m.alternateTitles.take(2).join(' / '), - detail: _movieDetail(m), - imagePath: m.posterPath, - icon: Icons.movie_outlined, - label: '影视', - rating: m.rating, - createdAt: m.createdAt, - color: const Color(0xFF4A90D9), - ); - break; - case 'book': - final b = books[_random.nextInt(books.length)]; - item = _StrollItem( - type: 'book', - title: b.title, - subtitle: b.authors.take(2).join(' / '), - detail: _bookDetail(b), - imagePath: b.coverPath, - icon: Icons.menu_book_outlined, - label: '书籍', - rating: b.rating, - createdAt: b.createdAt, - color: const Color(0xFF7E57C2), - ); - break; - case 'note': - final n = notes[_random.nextInt(notes.length)]; - item = _StrollItem( - type: 'note', - title: n.title.isNotEmpty ? n.title : '随手记', - subtitle: n.tags.take(3).join(' · '), - detail: n.content, - imagePath: n.images.isNotEmpty ? n.images.first : null, - icon: Icons.note_outlined, - label: '笔记', - createdAt: n.createdAt, - color: const Color(0xFF66BB6A), - ); - break; - default: - setState(() => _currentItem = null); - return; + for (int i = 0; i < count; i++) { + final pickedCategory = categoryKeys[_random.nextInt(categoryKeys.length)]; + _StrollItem? item; + switch (pickedCategory) { + case 'movie': + final m = movies[_random.nextInt(movies.length)]; + item = _StrollItem( + type: 'movie', data: m, + title: m.title, + subtitle: m.alternateTitles.take(2).join(' / '), + detail: _movieDetail(m), + imagePath: m.posterPath, + icon: Icons.movie_outlined, label: '影视', + rating: m.rating, createdAt: m.createdAt, + color: const Color(0xFF4A90D9), + ); + case 'book': + final b = books[_random.nextInt(books.length)]; + item = _StrollItem( + type: 'book', data: b, + title: b.title, + subtitle: b.authors.take(2).join(' / '), + detail: _bookDetail(b), + imagePath: b.coverPath, + icon: Icons.menu_book_outlined, label: '书籍', + rating: b.rating, createdAt: b.createdAt, + color: const Color(0xFF7E57C2), + ); + case 'note': + final n = notes[_random.nextInt(notes.length)]; + item = _StrollItem( + type: 'note', data: n, + title: n.title.isNotEmpty ? n.title : '随手记', + subtitle: n.tags.take(3).join(' · '), + detail: n.content, + imagePath: n.images.isNotEmpty ? n.images.first : null, + icon: Icons.note_outlined, label: '笔记', + createdAt: n.createdAt, + color: const Color(0xFF66BB6A), + ); + } + if (item != null) _items.add(item); } - - setState(() => _currentItem = item); } - void _refresh() async { - setState(() => _isLoading = true); - await _animController.reverse(); - _loadRandom(); - setState(() => _isLoading = false); - _animController.forward(); + void _reshuffle() { + setState(() { + _items.clear(); + _currentIndex = 0; + _loadBatch(5); + }); + } + + void _openDetail(_StrollItem item) { + switch (item.type) { + case 'movie': + Navigator.push(context, MaterialPageRoute(builder: (_) => MovieDetailPage(movie: item.data as Movie))); + case 'book': + Navigator.push(context, MaterialPageRoute(builder: (_) => BookDetailPage(book: item.data as Book))); + case 'note': + Navigator.push(context, MaterialPageRoute(builder: (_) => NoteDetailPage(note: item.data as Note))); + } } String _movieDetail(Movie m) { final parts = []; if (m.genres.isNotEmpty) parts.add(m.genres.take(3).join(' / ')); - if (m.summary != null && m.summary!.isNotEmpty) parts.add(m.summary!.length > 80 ? '${m.summary!.substring(0, 80)}...' : m.summary!); + if (m.summary != null && m.summary!.isNotEmpty) { + parts.add(m.summary!.length > 80 ? '${m.summary!.substring(0, 80)}...' : m.summary!); + } return parts.join('\n'); } @@ -129,7 +127,9 @@ class _StrollPageState extends State with SingleTickerProviderStateM final parts = []; if (b.genres.isNotEmpty) parts.add(b.genres.take(3).join(' / ')); if (b.publisher != null && b.publisher!.isNotEmpty) parts.add(b.publisher!); - if (b.summary != null && b.summary!.isNotEmpty) parts.add(b.summary!.length > 80 ? '${b.summary!.substring(0, 80)}...' : b.summary!); + if (b.summary != null && b.summary!.isNotEmpty) { + parts.add(b.summary!.length > 80 ? '${b.summary!.substring(0, 80)}...' : b.summary!); + } return parts.join('\n'); } @@ -155,17 +155,26 @@ class _StrollPageState extends State with SingleTickerProviderStateM @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; + final hasContent = _items.isNotEmpty; + return Scaffold( backgroundColor: colors.surface, appBar: AppBar( title: const Text('漫步'), actions: [ + if (hasContent) + Padding( + padding: const EdgeInsets.only(right: 4), + child: Center( + child: Text('${_currentIndex + 1}/${_items.length}', + style: TextStyle(fontSize: 12, color: colors.onSurface.withValues(alpha: 0.35))), + ), + ), Padding( padding: const EdgeInsets.only(right: 12), child: GestureDetector( - onTap: _isLoading ? null : _refresh, - child: AnimatedContainer( - duration: const Duration(milliseconds: 200), + onTap: _reshuffle, + child: Container( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 7), decoration: BoxDecoration( color: colors.primary, @@ -184,165 +193,155 @@ class _StrollPageState extends State with SingleTickerProviderStateM ), ], ), - body: _currentItem == null + body: !hasContent ? Center( child: Text('还没有任何内容\n去添加一些吧', textAlign: TextAlign.center, style: TextStyle(fontSize: 15, color: colors.onSurface.withValues(alpha: 0.3), height: 1.6))) - : Consumer(builder: (context, provider, _) { - final item = _currentItem!; - final hasImage = item.imagePath != null && item.imagePath!.isNotEmpty; + : PageView.builder( + controller: _pageController, + onPageChanged: (index) { + setState(() => _currentIndex = index); + // 接近末尾时追加新条目 + if (index >= _items.length - 2) { + setState(() => _loadBatch(3)); + } + }, + itemCount: _items.length, + itemBuilder: (context, index) { + return AnimatedBuilder( + animation: _pageController, + builder: (context, child) { + double scale = 1.0; + if (_pageController.hasClients && _pageController.page != null) { + final diff = (_pageController.page! - index).abs(); + scale = (1 - diff * 0.1).clamp(0.85, 1.0); + } + return Transform.scale(scale: scale, child: child); + }, + child: _buildCard(_items[index], colors), + ); + }, + ), + ); + } - return FadeTransition( - opacity: _fadeAnim, - child: Center( - child: SingleChildScrollView( - padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 20), - child: Column( - mainAxisSize: MainAxisSize.min, + Widget _buildCard(_StrollItem item, ColorScheme colors) { + final hasImage = item.imagePath != null && item.imagePath!.isNotEmpty; + + return GestureDetector( + onTap: () => _openDetail(item), + child: Container( + margin: const EdgeInsets.symmetric(vertical: 24, horizontal: 6), + decoration: BoxDecoration( + color: colors.surfaceContainerLowest, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow(color: Colors.black.withValues(alpha: 0.08), blurRadius: 24, offset: const Offset(0, 8)), + ], + ), + clipBehavior: Clip.antiAlias, + child: Column( + children: [ + // 封面/图片区域 + if (hasImage) + Expanded( + flex: 5, + child: SizedBox( + width: double.infinity, + child: FadeInLocalImage(path: item.imagePath, fit: BoxFit.cover), + ), + ) + else + Expanded( + flex: 3, + child: Container( + width: double.infinity, + color: colors.surfaceContainerHigh, + child: Center(child: Icon(item.icon, size: 56, color: item.color.withValues(alpha: 0.2))), + ), + ), + + // 内容区域 + Expanded( + flex: 4, + child: Padding( + padding: const EdgeInsets.fromLTRB(20, 14, 20, 16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // 类型标签 + 评分 + Row( children: [ - // 类型标签 - _buildTypeBadge(item), - const SizedBox(height: 24), - - // 封面/图片 - if (item.type != 'note') - _buildCoverCard(item, hasImage) - else - _buildNoteCard(item, hasImage), - - const SizedBox(height: 24), - - // 标题(笔记卡片已包含标题和内容,不需要重复) - if (item.type != 'note') ...[ - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - item.title, - textAlign: TextAlign.center, - style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700, color: colors.onSurface, height: 1.3), - ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), + decoration: BoxDecoration( + color: item.color.withValues(alpha: 0.08), + borderRadius: BorderRadius.circular(12), ), - - if (item.subtitle.isNotEmpty) ...[ - const SizedBox(height: 8), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Text(item.subtitle, textAlign: TextAlign.center, - style: TextStyle(fontSize: 13, color: colors.onSurface.withValues(alpha: 0.4))), - ), - ], - - // 评分 - if (item.rating != null) ...[ - const SizedBox(height: 10), - AnimatedStarRating(rating: item.rating!, starSize: 16, showNumber: true), - ], - - // 详情 - if (item.detail.isNotEmpty) ...[ - const SizedBox(height: 14), - Container( - margin: const EdgeInsets.symmetric(horizontal: 4), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: colors.surfaceContainerHigh, - borderRadius: BorderRadius.circular(12), - ), - child: Text(item.detail, - style: TextStyle(fontSize: 13, color: colors.onSurface.withValues(alpha: 0.6), height: 1.7)), - ), - ], - ], - - // 时间 - const SizedBox(height: 12), - Text(_actionText(item), style: TextStyle(fontSize: 12, color: colors.onSurface.withValues(alpha: 0.25))), - - const SizedBox(height: 40), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Icon(item.icon, size: 12, color: item.color), + const SizedBox(width: 4), + Text(item.label, style: TextStyle(fontSize: 11, fontWeight: FontWeight.w600, color: item.color)), + ], + ), + ), + const Spacer(), + if (item.rating != null) + AnimatedStarRating(rating: item.rating!, starSize: 14, showNumber: true), ], ), - ), + + const SizedBox(height: 10), + + // 标题 + Text(item.title, + maxLines: 2, overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700, color: colors.onSurface, height: 1.3)), + + // 副标题 + if (item.subtitle.isNotEmpty) ...[ + const SizedBox(height: 4), + Text(item.subtitle, + maxLines: 1, overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 13, color: colors.onSurface.withValues(alpha: 0.4))), + ], + + const SizedBox(height: 8), + + // 详情 + if (item.detail.isNotEmpty) + Expanded( + child: Container( + width: double.infinity, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: colors.surfaceContainerHigh, + borderRadius: BorderRadius.circular(12), + ), + child: Text(item.detail, maxLines: 3, overflow: TextOverflow.ellipsis, + style: TextStyle(fontSize: 13, color: colors.onSurface.withValues(alpha: 0.6), height: 1.7)), + ), + ), + + const SizedBox(height: 8), + + // 时间 + 点击提示 + Row( + children: [ + Text(_actionText(item), style: TextStyle(fontSize: 12, color: colors.onSurface.withValues(alpha: 0.25))), + const Spacer(), + Icon(Icons.arrow_forward_ios, size: 12, color: colors.onSurface.withValues(alpha: 0.15)), + ], + ), + ], ), - ); - }), - ); - } - - Widget _buildTypeBadge(_StrollItem item) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 5), - decoration: BoxDecoration( - color: item.color.withValues(alpha: 0.08), - borderRadius: BorderRadius.circular(14), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Icon(item.icon, size: 14, color: item.color), - const SizedBox(width: 5), - Text(item.label, style: TextStyle(fontSize: 12, fontWeight: FontWeight.w600, color: item.color)), - ], - ), - ); - } - - Widget _buildCoverCard(_StrollItem item, bool hasImage) { - return Container( - width: 220, - height: 290, - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow(color: item.color.withValues(alpha: 0.15), blurRadius: 20, offset: const Offset(0, 8)), - ], - ), - clipBehavior: Clip.antiAlias, - child: hasImage - ? FadeInLocalImage(path: item.imagePath, fit: BoxFit.cover) - : _buildPlaceholder(item), - ); - } - - Widget _buildNoteCard(_StrollItem item, bool hasImage) { - final colors = Theme.of(context).colorScheme; - return Container( - width: double.infinity, - constraints: const BoxConstraints(maxWidth: 360), - decoration: BoxDecoration( - color: colors.surface, - borderRadius: BorderRadius.circular(16), - boxShadow: [ - BoxShadow(color: Colors.black.withValues(alpha: 0.06), blurRadius: 16, offset: const Offset(0, 6)), - ], - ), - clipBehavior: Clip.antiAlias, - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (hasImage) - FadeInLocalImage(path: item.imagePath, fit: BoxFit.cover, height: 200, width: double.infinity), - Padding( - padding: const EdgeInsets.all(20), - child: Text(item.detail.isEmpty ? '(无内容)' : item.detail, - style: TextStyle(fontSize: 14, color: colors.onSurface.withValues(alpha: 0.73), height: 1.8)), - ), - Divider(height: 1, color: colors.outlineVariant), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), - child: Text('${item.detail.length} 字 · Mooknote', style: TextStyle(fontSize: 11, color: colors.onSurface.withValues(alpha: 0.3))), - ), - ], - ), - ); - } - - Widget _buildPlaceholder(_StrollItem item) { - final colors = Theme.of(context).colorScheme; - return Container( - color: colors.surfaceContainerHigh, - child: Center( - child: Icon(item.icon, size: 48, color: item.color.withValues(alpha: 0.2)), + ), + ), + ], + ), ), ); } @@ -350,6 +349,7 @@ class _StrollPageState extends State with SingleTickerProviderStateM class _StrollItem { final String type; + final dynamic data; final String title; final String subtitle; final String detail; @@ -362,6 +362,7 @@ class _StrollItem { _StrollItem({ required this.type, + required this.data, required this.title, required this.subtitle, required this.detail, diff --git a/lib/utils/database_helper.dart b/lib/utils/database_helper.dart index 2b2f9e1..97de5f7 100644 --- a/lib/utils/database_helper.dart +++ b/lib/utils/database_helper.dart @@ -57,7 +57,7 @@ class DatabaseHelper { return await openDatabase( path, - version: 14, + version: 15, onCreate: _createDB, onUpgrade: _onUpgrade, ); @@ -118,6 +118,10 @@ class DatabaseHelper { if (oldVersion < 14) { await _createReaderBooksTable(db); } + if (oldVersion < 15) { + await db.execute('ALTER TABLE movies ADD COLUMN cover_offset REAL DEFAULT 0'); + await db.execute('ALTER TABLE books ADD COLUMN cover_offset REAL DEFAULT 0'); + } } /// 升级books表到V11(添加ISBN和出版时间字段) @@ -501,7 +505,8 @@ class DatabaseHelper { watch_date TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - is_deleted INTEGER DEFAULT 0 + is_deleted INTEGER DEFAULT 0, + cover_offset REAL DEFAULT 0 ) '''); @@ -522,7 +527,8 @@ class DatabaseHelper { publish_date TEXT, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, - is_deleted INTEGER DEFAULT 0 + is_deleted INTEGER DEFAULT 0, + cover_offset REAL DEFAULT 0 ) '''); diff --git a/lib/utils/user_prefs.dart b/lib/utils/user_prefs.dart index 7b5409f..a4a9362 100644 --- a/lib/utils/user_prefs.dart +++ b/lib/utils/user_prefs.dart @@ -61,12 +61,6 @@ class UserPrefs { int get detailPageStyle => prefs.getInt('detailPageStyle') ?? 0; Future setDetailPageStyle(int value) => prefs.setInt('detailPageStyle', value); - // ========== 封面位置 ========== - - /// 获取封面偏移量(-1.0 到 1.0,0 = 居中) - double getCoverOffset(String itemId) => prefs.getDouble('coverOffset_$itemId') ?? 0.0; - Future setCoverOffset(String itemId, double value) => prefs.setDouble('coverOffset_$itemId', value); - // ========== 主界面显示设置 ========== /// 是否启用底部导航栏滚动隐藏(默认开启) diff --git a/pubspec.lock b/pubspec.lock index 398a7fb..264a401 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -6,7 +6,7 @@ packages: description: name: archive sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.6.1" args: @@ -14,7 +14,7 @@ packages: description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.7.0" async: @@ -22,7 +22,7 @@ packages: description: name: async sha256: e2eb0491ba5ddb6177742d2da23904574082139b07c1e33b8503b9f46f3e1a37 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.13.1" boolean_selector: @@ -30,7 +30,7 @@ packages: description: name: boolean_selector sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.2" characters: @@ -38,7 +38,7 @@ packages: description: name: characters sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.1" checked_yaml: @@ -46,7 +46,7 @@ packages: description: name: checked_yaml sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.4" cli_util: @@ -54,7 +54,7 @@ packages: description: name: cli_util sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.4.2" clock: @@ -62,7 +62,7 @@ packages: description: name: clock sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" code_assets: @@ -70,7 +70,7 @@ packages: description: name: code_assets sha256: bf394f466ba9205f1812a0433b392d6af280f155f56651eda7c18cc32ed493b8 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.1" collection: @@ -78,7 +78,7 @@ packages: description: name: collection sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.19.1" cross_file: @@ -86,7 +86,7 @@ packages: description: name: cross_file sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.3.5+2" crypto: @@ -94,7 +94,7 @@ packages: description: name: crypto sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.7" cupertino_icons: @@ -102,7 +102,7 @@ packages: description: name: cupertino_icons sha256: "41e005c33bd814be4d3096aff55b1908d419fde52ca656c8c47719ec745873cd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.9" dbus: @@ -110,7 +110,7 @@ packages: description: name: dbus sha256: "0ce9b0a839e6dee59a37a623d2fc26a35bbbe6404213e419b0d6411023d62645" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.7.14" equatable: @@ -118,7 +118,7 @@ packages: description: name: equatable sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.8" extended_text_field: @@ -126,7 +126,7 @@ packages: description: name: extended_text_field sha256: "3996195c117c6beb734026a7bc0ba80d7e4e84e4edd4728caa544d8209ab4d7d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "16.0.2" extended_text_library: @@ -134,7 +134,7 @@ packages: description: name: extended_text_library sha256: "13d99f8a10ead472d5e2cf4770d3d047203fe5054b152e9eb5dc692a71befbba" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "12.0.1" fake_async: @@ -142,7 +142,7 @@ packages: description: name: fake_async sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.3" ffi: @@ -150,7 +150,7 @@ packages: description: name: ffi sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" file: @@ -158,7 +158,7 @@ packages: description: name: file sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.1" file_picker: @@ -166,7 +166,7 @@ packages: description: name: file_picker sha256: ab13ae8ef5580a411c458d6207b6774a6c237d77ac37011b13994879f68a8810 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "8.3.7" file_selector_linux: @@ -174,7 +174,7 @@ packages: description: name: file_selector_linux sha256: "2567f398e06ac72dcf2e98a0c95df2a9edd03c2c2e0cacd4780f20cdf56263a0" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.4" file_selector_macos: @@ -182,7 +182,7 @@ packages: description: name: file_selector_macos sha256: "5e0bbe9c312416f1787a68259ea1505b52f258c587f12920422671807c4d618a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.5" file_selector_platform_interface: @@ -190,7 +190,7 @@ packages: description: name: file_selector_platform_interface sha256: "35e0bd61ebcdb91a3505813b055b09b79dfdc7d0aee9c09a7ba59ae4bb13dc85" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.7.0" file_selector_windows: @@ -198,7 +198,7 @@ packages: description: name: file_selector_windows sha256: "62197474ae75893a62df75939c777763d39c2bc5f73ce5b88497208bc269abfd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.9.3+5" fixnum: @@ -206,7 +206,7 @@ packages: description: name: fixnum sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.1" fl_chart: @@ -214,7 +214,7 @@ packages: description: name: fl_chart sha256: "74959b99b92b9eebeed1a4049426fd67c4abc3c5a0f4d12e2877097d6a11ae08" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.69.2" flutter: @@ -227,7 +227,7 @@ packages: description: name: flutter_inappwebview sha256: "80092d13d3e29b6227e25b67973c67c7210bd5e35c4b747ca908e31eb71a46d5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.1.5" flutter_inappwebview_android: @@ -235,7 +235,7 @@ packages: description: name: flutter_inappwebview_android sha256: "62557c15a5c2db5d195cb3892aab74fcaec266d7b86d59a6f0027abd672cddba" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.3" flutter_inappwebview_internal_annotations: @@ -243,7 +243,7 @@ packages: description: name: flutter_inappwebview_internal_annotations sha256: e30fba942e3debea7b7e6cdd4f0f59ce89dd403a9865193e3221293b6d1544c6 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.0" flutter_inappwebview_ios: @@ -251,7 +251,7 @@ packages: description: name: flutter_inappwebview_ios sha256: "5818cf9b26cf0cbb0f62ff50772217d41ea8d3d9cc00279c45f8aabaa1b4025d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_macos: @@ -259,7 +259,7 @@ packages: description: name: flutter_inappwebview_macos sha256: c1fbb86af1a3738e3541364d7d1866315ffb0468a1a77e34198c9be571287da1 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_platform_interface: @@ -267,7 +267,7 @@ packages: description: name: flutter_inappwebview_platform_interface sha256: cf5323e194096b6ede7a1ca808c3e0a078e4b33cc3f6338977d75b4024ba2500 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.0+1" flutter_inappwebview_web: @@ -275,7 +275,7 @@ packages: description: name: flutter_inappwebview_web sha256: "55f89c83b0a0d3b7893306b3bb545ba4770a4df018204917148ebb42dc14a598" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.2" flutter_inappwebview_windows: @@ -283,7 +283,7 @@ packages: description: name: flutter_inappwebview_windows sha256: "8b4d3a46078a2cdc636c4a3d10d10f2a16882f6be607962dbfff8874d1642055" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.6.0" flutter_launcher_icons: @@ -291,7 +291,7 @@ packages: description: name: flutter_launcher_icons sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.13.1" flutter_lints: @@ -299,7 +299,7 @@ packages: description: name: flutter_lints sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.0.0" flutter_localizations: @@ -312,7 +312,7 @@ packages: description: name: flutter_markdown_plus sha256: "039177906850278e8fb1cd364115ee0a46281135932fa8ecea8455522166d2de" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.7" flutter_plugin_android_lifecycle: @@ -320,7 +320,7 @@ packages: description: name: flutter_plugin_android_lifecycle sha256: "3854fe5e3bff0b113c658f260b90c95dea17c92db0f2addeac2e343dd9969785" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.35" flutter_staggered_grid_view: @@ -328,7 +328,7 @@ packages: description: name: flutter_staggered_grid_view sha256: "19e7abb550c96fbfeb546b23f3ff356ee7c59a019a651f8f102a4ba9b7349395" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.7.0" flutter_test: @@ -346,7 +346,7 @@ packages: description: name: hooks sha256: "9a62a50b50b769a737bc0a8ff381f333529df3ab746b2f6b02e83760231455ba" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.2" http: @@ -354,7 +354,7 @@ packages: description: name: http sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.6.0" http_parser: @@ -362,7 +362,7 @@ packages: description: name: http_parser sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.1.2" image: @@ -370,7 +370,7 @@ packages: description: name: image sha256: f31d52537dc417fdcde36088fdf11d191026fd5e4fae742491ebd40e5a8bea7d - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.3.0" image_picker: @@ -378,7 +378,7 @@ packages: description: name: image_picker sha256: "91c025426c2881c551100bce834e201c835a170151545f58d17da5180ca7d9ac" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.2" image_picker_android: @@ -386,7 +386,7 @@ packages: description: name: image_picker_android sha256: d5b3e1774af29c9ab00103afb0d4614070f924d2e0057ac867ec98800114793f - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.8.13+17" image_picker_for_web: @@ -394,7 +394,7 @@ packages: description: name: image_picker_for_web sha256: "66257a3191ab360d23a55c8241c91a6e329d31e94efa7be9cf7a212e65850214" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.1" image_picker_ios: @@ -402,7 +402,7 @@ packages: description: name: image_picker_ios sha256: b9c4a438a9ff4f60808c9cf0039b93a42bb6c2211ef6ebb647394b2b3fa84588 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.8.13+6" image_picker_linux: @@ -410,7 +410,7 @@ packages: description: name: image_picker_linux sha256: "1f81c5f2046b9ab724f85523e4af65be1d47b038160a8c8deed909762c308ed4" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" image_picker_macos: @@ -418,7 +418,7 @@ packages: description: name: image_picker_macos sha256: "86f0f15a309de7e1a552c12df9ce5b59fe927e71385329355aec4776c6a8ec91" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2+1" image_picker_platform_interface: @@ -426,7 +426,7 @@ packages: description: name: image_picker_platform_interface sha256: "567e056716333a1647c64bb6bd873cff7622233a5c3f694be28a583d4715690c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.11.1" image_picker_windows: @@ -434,7 +434,7 @@ packages: description: name: image_picker_windows sha256: d248c86554a72b5495a31c56f060cf73a41c7ff541689327b1a7dbccc33adfae - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.2" intl: @@ -442,7 +442,7 @@ packages: description: name: intl sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.20.2" jni: @@ -450,7 +450,7 @@ packages: description: name: jni sha256: c2230682d5bc2362c1c9e8d3c7f406d9cbba23ab3f2e203a025dd47e0fb2e68f - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.0" jni_flutter: @@ -458,7 +458,7 @@ packages: description: name: jni_flutter sha256: "8b59e590786050b1cd866677dddaf76b1ade5e7bc751abe04b86e84d379d3ba6" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.1" json_annotation: @@ -466,7 +466,7 @@ packages: description: name: json_annotation sha256: "2a743920d81b7910627f68ee2c9ac1fc0bfee32b9fc3403587d7c6791ca12f80" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.12.0" leak_tracker: @@ -474,7 +474,7 @@ packages: description: name: leak_tracker sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "11.0.2" leak_tracker_flutter_testing: @@ -482,7 +482,7 @@ packages: description: name: leak_tracker_flutter_testing sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.10" leak_tracker_testing: @@ -490,7 +490,7 @@ packages: description: name: leak_tracker_testing sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.0.2" lints: @@ -498,7 +498,7 @@ packages: description: name: lints sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.0.0" logging: @@ -506,7 +506,7 @@ packages: description: name: logging sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.0" markdown: @@ -514,7 +514,7 @@ packages: description: name: markdown sha256: ee85086ad7698b42522c6ad42fe195f1b9898e4d974a1af4576c1a3a176cada9 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.3.1" matcher: @@ -522,7 +522,7 @@ packages: description: name: matcher sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.12.19" material_color_utilities: @@ -530,7 +530,7 @@ packages: description: name: material_color_utilities sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.13.0" meta: @@ -538,7 +538,7 @@ packages: description: name: meta sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.17.0" mime: @@ -546,7 +546,7 @@ packages: description: name: mime sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.0.0" nested: @@ -554,7 +554,7 @@ packages: description: name: nested sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.0.0" objective_c: @@ -562,7 +562,7 @@ packages: description: name: objective_c sha256: "6cb691c686fa2838c6deb34980d426145c2a5d537491cb83d463c33cdbc726ed" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "9.4.1" package_config: @@ -570,7 +570,7 @@ packages: description: name: package_config sha256: f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" package_info_plus: @@ -578,7 +578,7 @@ packages: description: name: package_info_plus sha256: "16eee997588c60225bda0488b6dcfac69280a6b7a3cf02c741895dd370a02968" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "8.3.1" package_info_plus_platform_interface: @@ -586,7 +586,7 @@ packages: description: name: package_info_plus_platform_interface sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.1" path: @@ -594,7 +594,7 @@ packages: description: name: path sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.9.1" path_provider: @@ -602,7 +602,7 @@ packages: description: name: path_provider sha256: a7f4874f987173da295a61c181b8ee71dab59b332a486b391babf26a1b884825 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.6" path_provider_android: @@ -610,7 +610,7 @@ packages: description: name: path_provider_android sha256: "69cbd515a62b94d32a7944f086b2f82b4ac40a1d45bebfc00813a430ab2dabcd" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.1" path_provider_foundation: @@ -618,7 +618,7 @@ packages: description: name: path_provider_foundation sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.6.0" path_provider_linux: @@ -626,7 +626,7 @@ packages: description: name: path_provider_linux sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.1" path_provider_platform_interface: @@ -634,7 +634,7 @@ packages: description: name: path_provider_platform_interface sha256: "484838772624c3a4b94f1e44a3e19897fee738f2d5c4ce448443b0417f7c9dda" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.3" path_provider_windows: @@ -642,7 +642,7 @@ packages: description: name: path_provider_windows sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.0" permission_handler: @@ -650,7 +650,7 @@ packages: description: name: permission_handler sha256: "59adad729136f01ea9e35a48f5d1395e25cba6cea552249ddbe9cf950f5d7849" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "11.4.0" permission_handler_android: @@ -658,7 +658,7 @@ packages: description: name: permission_handler_android sha256: d3971dcdd76182a0c198c096b5db2f0884b0d4196723d21a866fc4cdea057ebc - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "12.1.0" permission_handler_apple: @@ -666,7 +666,7 @@ packages: description: name: permission_handler_apple sha256: "79dfa1df734798aa3cfdad166d3a3698c206d8813de13516ea1071b5d7e2f420" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "9.4.10" permission_handler_html: @@ -674,7 +674,7 @@ packages: description: name: permission_handler_html sha256: "38f000e83355abb3392140f6bc3030660cfaef189e1f87824facb76300b4ff24" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.1.3+5" permission_handler_platform_interface: @@ -682,7 +682,7 @@ packages: description: name: permission_handler_platform_interface sha256: eb99b295153abce5d683cac8c02e22faab63e50679b937fa1bf67d58bb282878 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.3.0" permission_handler_windows: @@ -690,7 +690,7 @@ packages: description: name: permission_handler_windows sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.2.1" petitparser: @@ -698,7 +698,7 @@ packages: description: name: petitparser sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "7.0.2" platform: @@ -706,7 +706,7 @@ packages: description: name: platform sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.6" plugin_platform_interface: @@ -714,7 +714,7 @@ packages: description: name: plugin_platform_interface sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.8" pointer_interceptor: @@ -722,7 +722,7 @@ packages: description: name: pointer_interceptor sha256: "57210410680379aea8b1b7ed6ae0c3ad349bfd56fe845b8ea934a53344b9d523" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.10.1+2" pointer_interceptor_ios: @@ -730,7 +730,7 @@ packages: description: name: pointer_interceptor_ios sha256: "03c5fa5896080963ab4917eeffda8d28c90f22863a496fb5ba13bc10943e40e4" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.10.1+1" pointer_interceptor_platform_interface: @@ -738,7 +738,7 @@ packages: description: name: pointer_interceptor_platform_interface sha256: "0597b0560e14354baeb23f8375cd612e8bd4841bf8306ecb71fcd0bb78552506" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.10.0+1" pointer_interceptor_web: @@ -746,7 +746,7 @@ packages: description: name: pointer_interceptor_web sha256: "460b600e71de6fcea2b3d5f662c92293c049c4319e27f0829310e5a953b3ee2a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.10.3" provider: @@ -754,7 +754,7 @@ packages: description: name: provider sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.1.5+1" pub_semver: @@ -762,7 +762,7 @@ packages: description: name: pub_semver sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" record_use: @@ -770,7 +770,7 @@ packages: description: name: record_use sha256: "2551bd8eecfe95d14ae75f6021ad0248be5c27f138c2ec12fcb52b500b3ba1ed" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.6.0" share_plus: @@ -778,7 +778,7 @@ packages: description: name: share_plus sha256: fce43200aa03ea87b91ce4c3ac79f0cecd52e2a7a56c7a4185023c271fbfa6da - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "10.1.4" share_plus_platform_interface: @@ -786,7 +786,7 @@ packages: description: name: share_plus_platform_interface sha256: cc012a23fc2d479854e6c80150696c4a5f5bb62cb89af4de1c505cf78d0a5d0b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.0.2" shared_preferences: @@ -794,7 +794,7 @@ packages: description: name: shared_preferences sha256: c3025c5534b01739267eb7d76959bbc25a6d10f6988e1c2a3036940133dd10bf - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.5.5" shared_preferences_android: @@ -802,7 +802,7 @@ packages: description: name: shared_preferences_android sha256: e8d4762b1e2e8578fc4d0fd548cebf24afd24f49719c08974df92834565e2c53 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.23" shared_preferences_foundation: @@ -810,7 +810,7 @@ packages: description: name: shared_preferences_foundation sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.5.6" shared_preferences_linux: @@ -818,7 +818,7 @@ packages: description: name: shared_preferences_linux sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" shared_preferences_platform_interface: @@ -826,7 +826,7 @@ packages: description: name: shared_preferences_platform_interface sha256: "649dc798a33931919ea356c4305c2d1f81619ea6e92244070b520187b5140ef9" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.2" shared_preferences_web: @@ -834,7 +834,7 @@ packages: description: name: shared_preferences_web sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.3" shared_preferences_windows: @@ -842,7 +842,7 @@ packages: description: name: shared_preferences_windows sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.1" shelf: @@ -850,7 +850,7 @@ packages: description: name: shelf sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.2" sky_engine: @@ -863,7 +863,7 @@ packages: description: name: source_span sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.10.2" sqflite: @@ -871,7 +871,7 @@ packages: description: name: sqflite sha256: "564cfed0746fe53140c23b70b308e045c3b31f17778f2f326ccb7d804ea0250a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.2+1" sqflite_android: @@ -879,7 +879,7 @@ packages: description: name: sqflite_android sha256: "881e28efdcc9950fd8e9bb42713dcf1103e62a2e7168f23c9338d82db13dec40" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.2+3" sqflite_common: @@ -887,7 +887,7 @@ packages: description: name: sqflite_common sha256: "1581ffbf7a0e333b380d6a30737d78516b826cb35beb7fb0bf8a3ea0c678b465" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.5.8" sqflite_darwin: @@ -895,7 +895,7 @@ packages: description: name: sqflite_darwin sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.2" sqflite_platform_interface: @@ -903,7 +903,7 @@ packages: description: name: sqflite_platform_interface sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.0" stack_trace: @@ -911,7 +911,7 @@ packages: description: name: stack_trace sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.12.1" stream_channel: @@ -919,7 +919,7 @@ packages: description: name: stream_channel sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.1.4" string_scanner: @@ -927,7 +927,7 @@ packages: description: name: string_scanner sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.1" synchronized: @@ -935,7 +935,7 @@ packages: description: name: synchronized sha256: "63896c27e81b28f8cb4e69ead0d3e8f03f1d1e5fc531a3e579cabed6a2c7c9e5" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.4.0+1" term_glyph: @@ -943,7 +943,7 @@ packages: description: name: term_glyph sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.2.2" test_api: @@ -951,7 +951,7 @@ packages: description: name: test_api sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "0.7.10" typed_data: @@ -959,7 +959,7 @@ packages: description: name: typed_data sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.4.0" url_launcher: @@ -967,7 +967,7 @@ packages: description: name: url_launcher sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.3.2" url_launcher_android: @@ -975,7 +975,7 @@ packages: description: name: url_launcher_android sha256: "17bc677f0b301615530dd1d67e0a9828cafa2d0b6b6eae4cd3679b7eac4a273c" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.3.30" url_launcher_ios: @@ -983,7 +983,7 @@ packages: description: name: url_launcher_ios sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.4.1" url_launcher_linux: @@ -991,7 +991,7 @@ packages: description: name: url_launcher_linux sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.2" url_launcher_macos: @@ -999,7 +999,7 @@ packages: description: name: url_launcher_macos sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.2.5" url_launcher_platform_interface: @@ -1007,7 +1007,7 @@ packages: description: name: url_launcher_platform_interface sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.3.2" url_launcher_web: @@ -1015,7 +1015,7 @@ packages: description: name: url_launcher_web sha256: "85c81589622fbc87c1c683aaea164d3604a7777495a79d91e39ffcdec39ddb34" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.4.3" url_launcher_windows: @@ -1023,7 +1023,7 @@ packages: description: name: url_launcher_windows sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.5" uuid: @@ -1031,7 +1031,7 @@ packages: description: name: uuid sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.5.3" vector_math: @@ -1039,7 +1039,7 @@ packages: description: name: vector_math sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.2.0" vm_service: @@ -1047,7 +1047,7 @@ packages: description: name: vm_service sha256: "0016aef94fc66495ac78af5859181e3f3bf2026bd8eecc72b9565601e19ab360" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "15.2.0" wakelock_plus: @@ -1055,7 +1055,7 @@ packages: description: name: wakelock_plus sha256: "61713aa82b7f85c21c9f4cd0a148abd75f38a74ec645fcb1e446f882c82fd09b" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.3.3" wakelock_plus_platform_interface: @@ -1063,7 +1063,7 @@ packages: description: name: wakelock_plus_platform_interface sha256: b13f99e992e7ae6a152e16c5559d3c07ff445b13330192662494e614ca3e7d7b - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.5.1" web: @@ -1071,7 +1071,7 @@ packages: description: name: web sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.1" webview_flutter: @@ -1079,7 +1079,7 @@ packages: description: name: webview_flutter sha256: e4d3474277c5043f5f3100ed27d94ad693abfd5c602b0221c719a4497e4ba1e4 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.14.0" webview_flutter_android: @@ -1087,7 +1087,7 @@ packages: description: name: webview_flutter_android sha256: ad5182eff9a550925330cb9f0cb038eddfdd5712aba8b77aa0f0400e50f6e688 - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "4.12.0" webview_flutter_platform_interface: @@ -1095,7 +1095,7 @@ packages: description: name: webview_flutter_platform_interface sha256: "1221c1b12f5278791042f2ec2841743784cf25c5a644e23d6680e5d718824f04" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "2.15.1" webview_flutter_wkwebview: @@ -1103,7 +1103,7 @@ packages: description: name: webview_flutter_wkwebview sha256: "82648217f537573e1ca9ae9952d3eacedca6ab5aee69dc84445fc763766dcea2" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.25.1" win32: @@ -1111,7 +1111,7 @@ packages: description: name: win32 sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "5.15.0" xdg_directories: @@ -1119,7 +1119,7 @@ packages: description: name: xdg_directories sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "1.1.0" xml: @@ -1127,7 +1127,7 @@ packages: description: name: xml sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "6.6.1" yaml: @@ -1135,7 +1135,7 @@ packages: description: name: yaml sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.flutter-io.cn" + url: "https://pub.dev" source: hosted version: "3.1.3" sdks: