generated from dellevin/template
适配深色模式
This commit is contained in:
@@ -17,7 +17,7 @@ class MovieTabPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _MovieTabPageState extends State<MovieTabPage> {
|
||||
int _layoutStyle = 0; // 0: 海报网格, 1: 列表
|
||||
int _layoutStyle = 0;
|
||||
bool _firstLoad = true;
|
||||
|
||||
@override
|
||||
@@ -31,10 +31,11 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return Column(
|
||||
children: [
|
||||
const MovieStatusBar(),
|
||||
const Divider(height: 0.5, thickness: 0.5, color: Color(0xFFE5E5E5)),
|
||||
Divider(height: 0.5, thickness: 0.5, color: colors.outline),
|
||||
Expanded(
|
||||
child: _buildMovieList(context),
|
||||
),
|
||||
@@ -43,12 +44,12 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
Widget _buildMovieList(BuildContext context) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return Consumer<AppProvider>(
|
||||
builder: (context, provider, child) {
|
||||
final statusMap = {0: 'watched', 1: 'watching', 2: 'want_to_watch'};
|
||||
final currentStatus = statusMap[provider.movieStatusIndex]!;
|
||||
final allMovies = provider.movies.where((m) => !m.isDeleted).toList();
|
||||
// 首次加载且数据为空时才显示骨架屏
|
||||
if (_firstLoad && allMovies.isEmpty) {
|
||||
return _buildSkeleton();
|
||||
}
|
||||
@@ -59,8 +60,8 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
if (movies.isEmpty) {
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async => await provider.loadMovies(),
|
||||
color: const Color(0xFF1A1A1A),
|
||||
backgroundColor: Colors.white,
|
||||
color: colors.primary,
|
||||
backgroundColor: colors.surface,
|
||||
child: ListView(
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
children: [_buildEmptyState(context, provider.movieStatusIndex)],
|
||||
@@ -77,10 +78,11 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
Widget _buildGridView(List movies, AppProvider provider) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async => await provider.loadMovies(),
|
||||
color: const Color(0xFF1A1A1A),
|
||||
backgroundColor: Colors.white,
|
||||
color: colors.primary,
|
||||
backgroundColor: colors.surface,
|
||||
child: GridView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(16, 16, 16, 100),
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
@@ -96,10 +98,11 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
Widget _buildListView(List movies, AppProvider provider) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async => await provider.loadMovies(),
|
||||
color: const Color(0xFF1A1A1A),
|
||||
backgroundColor: Colors.white,
|
||||
color: colors.primary,
|
||||
backgroundColor: colors.surface,
|
||||
child: ListView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(12, 8, 12, 100),
|
||||
itemCount: movies.length,
|
||||
@@ -109,6 +112,7 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
Widget _buildListCard(movie) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.pushNamed(context, '/movie-detail', arguments: movie),
|
||||
onLongPress: () => _showDeleteDialog(context, movie),
|
||||
@@ -116,23 +120,22 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFFAFAFA),
|
||||
color: colors.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
// 海报缩略图
|
||||
Container(
|
||||
width: 48, height: 64,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF0F0F0),
|
||||
color: colors.outlineVariant,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
clipBehavior: Clip.antiAlias,
|
||||
child: movie.posterPath != null && movie.posterPath!.isNotEmpty
|
||||
? Image.file(File(movie.posterPath!), fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) => const Icon(Icons.movie_outlined, size: 22, color: Color(0xFFCCCCCC)))
|
||||
: const Icon(Icons.movie_outlined, size: 22, color: Color(0xFFCCCCCC)),
|
||||
errorBuilder: (_, __, ___) => Icon(Icons.movie_outlined, size: 22, color: colors.onSurface.withValues(alpha: 0.25)))
|
||||
: Icon(Icons.movie_outlined, size: 22, color: colors.onSurface.withValues(alpha: 0.25)),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
@@ -140,11 +143,11 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(movie.title, maxLines: 1, overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: Color(0xFF1A1A1A))),
|
||||
style: TextStyle(fontSize: 15, fontWeight: FontWeight.w600, color: colors.onSurface)),
|
||||
if (movie.alternateTitles.isNotEmpty) ...[
|
||||
const SizedBox(height: 3),
|
||||
Text(movie.alternateTitles.take(2).join('、'), maxLines: 1, overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFFAAAAAA))),
|
||||
style: TextStyle(fontSize: 12, color: colors.onSurface.withValues(alpha: 0.35))),
|
||||
],
|
||||
const SizedBox(height: 6),
|
||||
if (movie.rating != null)
|
||||
@@ -155,7 +158,7 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Icon(Icons.chevron_right, color: Color(0xFFD0D0D0), size: 20),
|
||||
Icon(Icons.chevron_right, color: colors.onSurface.withValues(alpha: 0.2), size: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -163,19 +166,20 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
void _showDeleteDialog(BuildContext context, movie) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: colors.surface,
|
||||
elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
|
||||
title: const Text('确认删除', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600)),
|
||||
title: Text('确认删除', style: TextStyle(fontSize: 18, fontWeight: FontWeight.w600, color: colors.onSurface)),
|
||||
content: Text('确定要删除《${movie.title}》吗?删除后可在回收站恢复。',
|
||||
style: const TextStyle(fontSize: 14, color: Color(0xFF666666), height: 1.5)),
|
||||
style: TextStyle(fontSize: 14, color: colors.onSurface.withValues(alpha: 0.6), height: 1.5)),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('取消', style: TextStyle(color: Color(0xFF666666))),
|
||||
child: Text('取消', style: TextStyle(color: colors.onSurface.withValues(alpha: 0.6))),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () async {
|
||||
@@ -183,7 +187,7 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
Navigator.pop(ctx);
|
||||
},
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.red, foregroundColor: Colors.white, elevation: 0,
|
||||
backgroundColor: colors.error, foregroundColor: colors.onError, elevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||
),
|
||||
@@ -200,6 +204,7 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
Widget _buildListSkeleton() {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(12, 8, 12, 100),
|
||||
itemCount: 6,
|
||||
@@ -207,7 +212,7 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFFF8F8F8),
|
||||
color: colors.surfaceContainerHigh,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Row(
|
||||
@@ -235,6 +240,7 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
}
|
||||
|
||||
Widget _buildEmptyState(BuildContext context, int statusIndex) {
|
||||
final colors = Theme.of(context).colorScheme;
|
||||
final statusText = ['已看', '在看', '想看'][statusIndex];
|
||||
return Center(
|
||||
child: Column(
|
||||
@@ -242,11 +248,11 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
children: [
|
||||
Container(
|
||||
width: 80, height: 80,
|
||||
decoration: BoxDecoration(color: const Color(0xFFF5F5F5), borderRadius: BorderRadius.circular(20)),
|
||||
child: const Icon(Icons.movie_outlined, size: 40, color: Color(0xFFCCCCCC)),
|
||||
decoration: BoxDecoration(color: colors.surfaceContainerHighest, borderRadius: BorderRadius.circular(20)),
|
||||
child: Icon(Icons.movie_outlined, size: 40, color: colors.onSurface.withValues(alpha: 0.25)),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Text('暂无$statusText的影片', style: const TextStyle(fontSize: 16, color: Color(0xFF999999))),
|
||||
Text('暂无$statusText的影片', style: TextStyle(fontSize: 16, color: colors.onSurface.withValues(alpha: 0.4))),
|
||||
const SizedBox(height: 24),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
@@ -255,8 +261,8 @@ class _MovieTabPageState extends State<MovieTabPage> {
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
|
||||
decoration: BoxDecoration(color: const Color(0xFF1A1A1A), borderRadius: BorderRadius.circular(8)),
|
||||
child: const Text('添加记录', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white)),
|
||||
decoration: BoxDecoration(color: colors.primary, borderRadius: BorderRadius.circular(8)),
|
||||
child: Text('添加记录', style: TextStyle(fontSize: 14, fontWeight: FontWeight.w500, color: colors.onPrimary)),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user