generated from dellevin/template
优化界面显示
This commit is contained in:
@@ -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),
|
||||||
|
|||||||
@@ -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),
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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(
|
bottomNavigationBar: SafeArea(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 8, 16, 12),
|
||||||
|
child: FilledButton(
|
||||||
onPressed: _isSaving ? null : _save,
|
onPressed: _isSaving ? null : _save,
|
||||||
child: Text(_isEdit ? '保存' : '创建', style: TextStyle(
|
style: FilledButton.styleFrom(
|
||||||
color: _nameController.text.trim().isEmpty ? colors.onSurface.withValues(alpha: 0.3) : colors.primary,
|
minimumSize: const Size.fromHeight(48),
|
||||||
fontWeight: FontWeight.w600,
|
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,36 +113,45 @@ 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(
|
||||||
children: _types.map((t) {
|
padding: const EdgeInsets.all(2),
|
||||||
final (type, label, icon, color) = t;
|
decoration: BoxDecoration(
|
||||||
final selected = _selectedType == type;
|
color: colors.surfaceContainerHighest,
|
||||||
return Expanded(
|
borderRadius: BorderRadius.circular(8),
|
||||||
child: GestureDetector(
|
),
|
||||||
onTap: () => setState(() => _selectedType = type),
|
child: Row(
|
||||||
child: Container(
|
children: _types.map((t) {
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 4),
|
final (type, label, icon) = t;
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12),
|
final selected = _selectedType == type;
|
||||||
decoration: BoxDecoration(
|
return Expanded(
|
||||||
color: selected ? color.withValues(alpha: 0.1) : colors.surfaceContainerHighest,
|
child: GestureDetector(
|
||||||
borderRadius: BorderRadius.circular(10),
|
behavior: HitTestBehavior.opaque,
|
||||||
border: selected ? Border.all(color: color.withValues(alpha: 0.3)) : null,
|
onTap: () => setState(() => _selectedType = type),
|
||||||
),
|
child: AnimatedContainer(
|
||||||
child: Column(
|
duration: const Duration(milliseconds: 150),
|
||||||
children: [
|
curve: Curves.easeOut,
|
||||||
Icon(icon, size: 22, color: selected ? color : colors.onSurface.withValues(alpha: 0.4)),
|
padding: const EdgeInsets.symmetric(vertical: 12),
|
||||||
const SizedBox(height: 6),
|
decoration: BoxDecoration(
|
||||||
Text(label, style: TextStyle(
|
color: selected ? colors.surface : Colors.transparent,
|
||||||
fontSize: 12,
|
borderRadius: BorderRadius.circular(6),
|
||||||
fontWeight: selected ? FontWeight.w600 : FontWeight.normal,
|
),
|
||||||
color: selected ? color : colors.onSurface.withValues(alpha: 0.5),
|
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),
|
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: '输入片单名称',
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user