generated from dellevin/template
基本功能完善
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import '../providers/app_provider.dart';
|
||||
import '../models/data_models.dart';
|
||||
import '../utils/toast_util.dart';
|
||||
|
||||
/// 影视海报墙页面
|
||||
class MoviePostersPage extends StatefulWidget {
|
||||
@@ -93,64 +96,96 @@ class _MoviePostersPageState extends State<MoviePostersPage> {
|
||||
}
|
||||
|
||||
Widget _buildPosterGrid() {
|
||||
return GridView.builder(
|
||||
return MasonryGridView.count(
|
||||
padding: const EdgeInsets.all(16),
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
childAspectRatio: 0.7,
|
||||
crossAxisSpacing: 12,
|
||||
mainAxisSpacing: 12,
|
||||
),
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 12,
|
||||
crossAxisSpacing: 12,
|
||||
itemCount: _posters.length,
|
||||
itemBuilder: (context, index) {
|
||||
final poster = _posters[index];
|
||||
return _buildPosterItem(poster);
|
||||
return _buildPosterItem(poster, index);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPosterItem(MoviePoster poster) {
|
||||
Widget _buildPosterItem(MoviePoster poster, int index) {
|
||||
// 根据索引生成不同的高度,实现瀑布流效果
|
||||
final heights = [180.0, 220.0, 160.0, 200.0, 240.0, 190.0];
|
||||
final height = heights[index % heights.length];
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () => _showPosterDetail(poster),
|
||||
child: Container(
|
||||
height: height,
|
||||
decoration: BoxDecoration(
|
||||
border: Border.all(color: const Color(0xFFE5E5E5)),
|
||||
),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// 海报图片
|
||||
Image.file(
|
||||
File(poster.posterPath),
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) => const Center(
|
||||
child: Icon(
|
||||
Icons.broken_image,
|
||||
color: Color(0xFFCCCCCC),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 删除按钮
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: GestureDetector(
|
||||
onTap: () => _showDeleteDialog(poster),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: const BoxDecoration(
|
||||
color: Colors.white,
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 18,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.08),
|
||||
blurRadius: 8,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
// 海报图片
|
||||
Image.file(
|
||||
File(poster.posterPath),
|
||||
fit: BoxFit.cover,
|
||||
errorBuilder: (_, __, ___) => const Center(
|
||||
child: Icon(
|
||||
Icons.broken_image,
|
||||
color: Color(0xFFCCCCCC),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 渐变遮罩(底部)
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
height: 40,
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withOpacity(0.3),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// 删除按钮
|
||||
Positioned(
|
||||
top: 8,
|
||||
right: 8,
|
||||
child: GestureDetector(
|
||||
onTap: () => _showDeleteDialog(poster),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.9),
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.close,
|
||||
size: 16,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -208,9 +243,7 @@ class _MoviePostersPageState extends State<MoviePostersPage> {
|
||||
_loadPosters();
|
||||
|
||||
if (mounted) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('添加成功')),
|
||||
);
|
||||
ToastUtil.show(context, '添加成功');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -241,9 +274,7 @@ class _MoviePostersPageState extends State<MoviePostersPage> {
|
||||
await context.read<AppProvider>().removeMoviePoster(poster.id);
|
||||
Navigator.pop(context);
|
||||
_loadPosters();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('已删除')),
|
||||
);
|
||||
ToastUtil.show(context, '已删除');
|
||||
},
|
||||
child: const Text('删除', style: TextStyle(color: Colors.red)),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user