优化界面显示

This commit is contained in:
DelLevin-Home
2026-08-12 21:43:58 +08:00
parent e543618139
commit be3299a0b3
5 changed files with 79 additions and 48 deletions

View File

@@ -947,7 +947,7 @@ class _BookDetailPageState extends State<BookDetailPage> {
isOverlay: true, isOverlay: true,
), ),
// 关联人物 // 关联人物
WorkPeopleSection(workId: book.id, workType: 'book'), WorkPeopleSection(workId: book.id, workType: 'book', isOverlay: true),
// 简介:内部已有毛玻璃卡片 // 简介:内部已有毛玻璃卡片
if (book.summary != null && book.summary!.isNotEmpty) ...[ if (book.summary != null && book.summary!.isNotEmpty) ...[
const SizedBox(height: 12), const SizedBox(height: 12),

View File

@@ -1185,7 +1185,7 @@ class _GameDetailPageState extends State<GameDetailPage> {
isOverlay: true, isOverlay: true,
), ),
// 关联人物 // 关联人物
WorkPeopleSection(workId: game.id, workType: 'game'), WorkPeopleSection(workId: game.id, workType: 'game', isOverlay: true),
if (game.summary != null && game.summary!.isNotEmpty) ...[ if (game.summary != null && game.summary!.isNotEmpty) ...[
const SizedBox(height: 12), const SizedBox(height: 12),
_buildOverlaySummary(game), _buildOverlaySummary(game),

View File

@@ -1107,7 +1107,7 @@ class _MovieDetailPageState extends State<MovieDetailPage> {
isOverlay: true, isOverlay: true,
), ),
// 关联人物 // 关联人物
WorkPeopleSection(workId: movie.id, workType: 'movie'), WorkPeopleSection(workId: movie.id, workType: 'movie', isOverlay: true),
const SizedBox(height: 12), const SizedBox(height: 12),
// 简介:内部已有毛玻璃卡片 // 简介:内部已有毛玻璃卡片
if (movie.summary != null && movie.summary!.isNotEmpty) if (movie.summary != null && movie.summary!.isNotEmpty)

View File

@@ -15,15 +15,16 @@ class PlaylistCreatePage extends StatefulWidget {
class _PlaylistCreatePageState extends State<PlaylistCreatePage> { class _PlaylistCreatePageState extends State<PlaylistCreatePage> {
late final TextEditingController _nameController; late final TextEditingController _nameController;
late final TextEditingController _descController; late final TextEditingController _descController;
final FocusNode _nameFocusNode = FocusNode();
late String _selectedType; late String _selectedType;
bool _isSaving = false; bool _isSaving = false;
bool get _isEdit => widget.playlist != null; bool get _isEdit => widget.playlist != null;
static const _types = [ static const _types = [
('movie', '影视', Icons.movie_outlined, Colors.blue), ('movie', '影视', Icons.movie_outlined),
('book', '书籍', Icons.menu_book_outlined, Colors.teal), ('book', '书籍', Icons.menu_book_outlined),
('game', '游戏', Icons.sports_esports_outlined, Colors.orange), ('game', '游戏', Icons.sports_esports_outlined),
]; ];
@override @override
@@ -38,12 +39,21 @@ class _PlaylistCreatePageState extends State<PlaylistCreatePage> {
void dispose() { void dispose() {
_nameController.dispose(); _nameController.dispose();
_descController.dispose(); _descController.dispose();
_nameFocusNode.dispose();
super.dispose(); super.dispose();
} }
Future<void> _save() async { Future<void> _save() async {
final name = _nameController.text.trim(); final name = _nameController.text.trim();
if (name.isEmpty) return; if (name.isEmpty) {
_nameFocusNode.requestFocus();
if (mounted) {
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(const SnackBar(content: Text('请输入片单名称')));
}
return;
}
if (_isSaving) return; if (_isSaving) return;
setState(() => _isSaving = true); setState(() => _isSaving = true);
@@ -80,15 +90,21 @@ class _PlaylistCreatePageState extends State<PlaylistCreatePage> {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(_isEdit ? '编辑片单' : '创建片单'), title: Text(_isEdit ? '编辑片单' : '创建片单'),
actions: [
TextButton(
onPressed: _isSaving ? null : _save,
child: Text(_isEdit ? '保存' : '创建', style: TextStyle(
color: _nameController.text.trim().isEmpty ? colors.onSurface.withValues(alpha: 0.3) : colors.primary,
fontWeight: FontWeight.w600,
)),
), ),
], bottomNavigationBar: SafeArea(
child: Padding(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 12),
child: FilledButton(
onPressed: _isSaving ? null : _save,
style: FilledButton.styleFrom(
minimumSize: const Size.fromHeight(48),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
child: _isSaving
? const SizedBox(width: 22, height: 22, child: CircularProgressIndicator(strokeWidth: 2.5))
: Text(_isEdit ? '保存' : '创建', style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600)),
),
),
), ),
body: ListView( body: ListView(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
@@ -97,29 +113,37 @@ class _PlaylistCreatePageState extends State<PlaylistCreatePage> {
if (!_isEdit) ...[ if (!_isEdit) ...[
Text('片单类型', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: colors.onSurface.withValues(alpha: 0.6))), Text('片单类型', style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: colors.onSurface.withValues(alpha: 0.6))),
const SizedBox(height: 10), const SizedBox(height: 10),
Row( Container(
padding: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: colors.surfaceContainerHighest,
borderRadius: BorderRadius.circular(8),
),
child: Row(
children: _types.map((t) { children: _types.map((t) {
final (type, label, icon, color) = t; final (type, label, icon) = t;
final selected = _selectedType == type; final selected = _selectedType == type;
return Expanded( return Expanded(
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => setState(() => _selectedType = type), onTap: () => setState(() => _selectedType = type),
child: Container( child: AnimatedContainer(
margin: const EdgeInsets.symmetric(horizontal: 4), duration: const Duration(milliseconds: 150),
curve: Curves.easeOut,
padding: const EdgeInsets.symmetric(vertical: 12), padding: const EdgeInsets.symmetric(vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: selected ? color.withValues(alpha: 0.1) : colors.surfaceContainerHighest, color: selected ? colors.surface : Colors.transparent,
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(6),
border: selected ? Border.all(color: color.withValues(alpha: 0.3)) : null,
), ),
child: Column( child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(icon, size: 22, color: selected ? color : colors.onSurface.withValues(alpha: 0.4)), Icon(icon, size: 16, color: selected ? colors.primary : colors.onSurface.withValues(alpha: 0.4)),
const SizedBox(height: 6), const SizedBox(width: 6),
Text(label, style: TextStyle( Text(label, style: TextStyle(
fontSize: 12, fontSize: 13,
fontWeight: selected ? FontWeight.w600 : FontWeight.normal, fontWeight: selected ? FontWeight.w500 : FontWeight.normal,
color: selected ? color : colors.onSurface.withValues(alpha: 0.5), color: selected ? colors.onSurface : colors.onSurface.withValues(alpha: 0.4),
)), )),
], ],
), ),
@@ -128,6 +152,7 @@ class _PlaylistCreatePageState extends State<PlaylistCreatePage> {
); );
}).toList(), }).toList(),
), ),
),
const SizedBox(height: 24), const SizedBox(height: 24),
], ],
// 片单名称 // 片单名称
@@ -135,6 +160,8 @@ class _PlaylistCreatePageState extends State<PlaylistCreatePage> {
const SizedBox(height: 8), const SizedBox(height: 8),
TextField( TextField(
controller: _nameController, controller: _nameController,
focusNode: _nameFocusNode,
autofocus: !_isEdit,
maxLength: 30, maxLength: 30,
decoration: InputDecoration( decoration: InputDecoration(
hintText: '输入片单名称', hintText: '输入片单名称',

View File

@@ -11,11 +11,13 @@ import 'person_info_sheet.dart';
class WorkPeopleSection extends StatefulWidget { class WorkPeopleSection extends StatefulWidget {
final String workId; final String workId;
final String workType; // 'movie' / 'book' / 'game' final String workType; // 'movie' / 'book' / 'game'
final bool isOverlay; // 叠层模式(深色毛玻璃背景)下用白色文字
const WorkPeopleSection({ const WorkPeopleSection({
super.key, super.key,
required this.workId, required this.workId,
required this.workType, required this.workType,
this.isOverlay = false,
}); });
@override @override
@@ -170,6 +172,8 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
if (_items.isEmpty) return const SizedBox.shrink(); if (_items.isEmpty) return const SizedBox.shrink();
final colors = Theme.of(context).colorScheme; final colors = Theme.of(context).colorScheme;
final primaryColor = widget.isOverlay ? Colors.white : colors.onSurface;
final secondaryColor = widget.isOverlay ? Colors.white.withValues(alpha: 0.5) : colors.onSurface.withValues(alpha: 0.4);
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20), padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 20),
@@ -182,7 +186,7 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
width: 4, width: 4,
height: 16, height: 16,
decoration: BoxDecoration( decoration: BoxDecoration(
color: colors.onSurface, color: primaryColor,
borderRadius: BorderRadius.circular(2), borderRadius: BorderRadius.circular(2),
), ),
), ),
@@ -192,7 +196,7 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
style: TextStyle( style: TextStyle(
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: colors.onSurface, color: primaryColor,
), ),
), ),
], ],
@@ -220,7 +224,7 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
final idx = _items.indexOf(item); final idx = _items.indexOf(item);
return Padding( return Padding(
padding: EdgeInsets.only(left: idx == 0 ? 0 : 16), padding: EdgeInsets.only(left: idx == 0 ? 0 : 16),
child: _buildPersonChip(item, colors), child: _buildPersonChip(item, primaryColor, secondaryColor),
); );
}).toList(), }).toList(),
), ),
@@ -231,7 +235,7 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
); );
} }
Widget _buildPersonChip(_PersonRole item, ColorScheme colors) { Widget _buildPersonChip(_PersonRole item, Color primaryColor, Color secondaryColor) {
final person = item.person; final person = item.person;
return GestureDetector( return GestureDetector(
onTap: () => PersonInfoSheet.show(context, person), onTap: () => PersonInfoSheet.show(context, person),
@@ -248,7 +252,7 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
const SizedBox(height: 8), const SizedBox(height: 8),
Text( Text(
person.name, person.name,
style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: colors.onSurface), style: TextStyle(fontSize: 12, fontWeight: FontWeight.w500, color: primaryColor),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center, textAlign: TextAlign.center,
@@ -258,7 +262,7 @@ class _WorkPeopleSectionState extends State<WorkPeopleSection> {
_buildRoleText(item), _buildRoleText(item),
style: TextStyle( style: TextStyle(
fontSize: 10, fontSize: 10,
color: colors.onSurface.withValues(alpha: 0.4), color: secondaryColor,
height: 1.3, height: 1.3,
), ),
maxLines: 2, maxLines: 2,