适配平板

This commit is contained in:
DelLevin-Home
2026-06-30 21:51:38 +08:00
parent 18cda23f2a
commit 1192f8f7e0
19 changed files with 699 additions and 377 deletions

View File

@@ -17,8 +17,9 @@ import '../epub_reader/reader_screen.dart';
/// 书籍详情页 - 极简主义设计
class BookDetailPage extends StatefulWidget {
final Book book;
final bool embedded;
const BookDetailPage({super.key, required this.book});
const BookDetailPage({super.key, required this.book, this.embedded = false});
@override
State<BookDetailPage> createState() => _BookDetailPageState();
@@ -152,8 +153,10 @@ class _BookDetailPageState extends State<BookDetailPage> {
child: Row(children: [
const SizedBox(width: 4),
IconButton(
icon: const Icon(Icons.arrow_back_ios_new, color: Colors.white, size: 18),
onPressed: () => Navigator.pop(context),
icon: Icon(widget.embedded ? Icons.close : Icons.arrow_back_ios_new, color: Colors.white, size: 18),
onPressed: widget.embedded
? () => context.read<AppProvider>().selectBook(null)
: () => Navigator.pop(context),
),
ValueListenableBuilder<bool>(
valueListenable: _showTitle,
@@ -370,8 +373,10 @@ class _BookDetailPageState extends State<BookDetailPage> {
child: Row(children: [
const SizedBox(width: 4),
IconButton(
icon: Icon(Icons.arrow_back_ios_new, color: colors.onSurface, size: 18),
onPressed: () => Navigator.pop(context),
icon: Icon(widget.embedded ? Icons.close : Icons.arrow_back_ios_new, color: colors.onSurface, size: 18),
onPressed: widget.embedded
? () => context.read<AppProvider>().selectBook(null)
: () => Navigator.pop(context),
),
const SizedBox(width: 4),
Expanded(
@@ -1228,7 +1233,11 @@ class _BookDetailPageState extends State<BookDetailPage> {
await context.read<AppProvider>().removeBook(widget.book.id);
if (!mounted) return;
Navigator.pop(context);
Navigator.pop(context);
if (widget.embedded) {
context.read<AppProvider>().selectBook(null);
} else {
Navigator.pop(context);
}
ToastUtil.show(context, '已删除');
},
style: ElevatedButton.styleFrom(

View File

@@ -2,12 +2,16 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../models/data_models.dart';
import '../../providers/app_provider.dart';
import '../../utils/responsive.dart';
import '../../utils/user_prefs.dart';
import '../../widgets/book_status_bar.dart';
import '../../widgets/book_list_item.dart';
import '../../widgets/animated_star_rating.dart';
import '../../widgets/shimmer_skeleton.dart';
import '../../widgets/fade_in_local_image.dart';
import '../../widgets/master_detail_scaffold.dart';
import '../../widgets/detail_placeholder.dart';
import 'book_detail_page.dart';
/// 阅读标签页(分页 + 触底加载)
class BookTabPage extends StatefulWidget {
@@ -30,6 +34,14 @@ class _BookTabPageState extends State<BookTabPage> {
int _lastScrollSignal = 0;
int _prevBookCount = -1;
void _onBookTap(Book book) {
if (Breakpoint.isWideContent(context)) {
context.read<AppProvider>().selectBook(book);
} else {
Navigator.pushNamed(context, '/book-detail', arguments: book);
}
}
static const _statusMap = {0: 'read', 1: 'reading', 2: 'want_to_read'};
@override
@@ -108,10 +120,22 @@ class _BookTabPageState extends State<BookTabPage> {
@override
Widget build(BuildContext context) {
return Column(children: [
final isWideContent = Breakpoint.isWideContent(context);
final provider = context.watch<AppProvider>();
final masterContent = Column(children: [
const BookStatusBar(),
Expanded(child: _buildBody(context)),
]);
if (!isWideContent) return masterContent;
final selectedBook = provider.selectedBook;
return MasterDetailScaffold(
master: masterContent,
detail: selectedBook != null
? BookDetailPage(book: selectedBook, embedded: true)
: const DetailPlaceholder(icon: Icons.menu_book_outlined, message: '选择一本书查看详情'),
);
}
Widget _buildBody(BuildContext context) {
@@ -132,15 +156,24 @@ class _BookTabPageState extends State<BookTabPage> {
}
Widget _buildGridView() {
return GridView.builder(controller: _scrollController,
padding: const EdgeInsets.fromLTRB(16, 16, 16, 100),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 3, childAspectRatio: 0.55, crossAxisSpacing: 12, mainAxisSpacing: 16),
itemCount: _items.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index >= _items.length) return _buildLoadMore();
return BookListItem(book: _items[index]);
},
);
return LayoutBuilder(builder: (context, constraints) {
final crossAxisCount = responsiveCrossAxisCount(constraints.maxWidth, minItemWidth: 110);
return GridView.builder(controller: _scrollController,
padding: const EdgeInsets.fromLTRB(16, 16, 16, 100),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: crossAxisCount, childAspectRatio: 0.55, crossAxisSpacing: 12, mainAxisSpacing: 16),
itemCount: _items.length + (_hasMore ? 1 : 0),
itemBuilder: (context, index) {
if (index >= _items.length) return _buildLoadMore();
final item = _items[index];
final provider = context.read<AppProvider>();
return BookListItem(
book: item,
selected: Breakpoint.isWideContent(context) && provider.selectedBook?.id == item.id,
onTap: () => _onBookTap(item),
);
},
);
});
}
Widget _buildListView() {
@@ -165,7 +198,7 @@ class _BookTabPageState extends State<BookTabPage> {
Widget _buildListCard(Book book) {
final colors = Theme.of(context).colorScheme;
return GestureDetector(
onTap: () => Navigator.pushNamed(context, '/book-detail', arguments: book),
onTap: () => _onBookTap(book),
onLongPress: () => _showDeleteDialog(context, book),
child: Container(margin: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: colors.surfaceContainerHigh, borderRadius: BorderRadius.circular(12)),