优化界面显示

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,
),
// 关联人物
WorkPeopleSection(workId: book.id, workType: 'book'),
WorkPeopleSection(workId: book.id, workType: 'book', isOverlay: true),
// 简介:内部已有毛玻璃卡片
if (book.summary != null && book.summary!.isNotEmpty) ...[
const SizedBox(height: 12),

View File

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

View File

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

View File

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

View File

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