feat(app): crop cover & banner before upload (crop_your_image, 16:9 / 3:1)

review fixes: drop GIF from pre-sniff (package maps gif→png decode → never-ready hang); PopScope blocks back during processing

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-28 15:39:39 +08:00
parent 97db504e25
commit 683e19bdc1
10 changed files with 632 additions and 7 deletions
+31 -4
View File
@@ -31,6 +31,7 @@ import '../features/uploads/enqueue.dart';
import '../l10n/app_localizations.dart';
import '../ui/components/section_header.dart';
import '../ui/tokens.dart';
import 'image_crop_page.dart';
/// 创建([existing] 为 null)/ 编辑相册表单。
class AlbumFormPage extends ConsumerStatefulWidget {
@@ -497,17 +498,43 @@ class _AlbumFormPageState extends ConsumerState<AlbumFormPage>
],
);
/// 选图后必经裁剪:封面 16:9(表单预览区比例),输出宽 ≤1920。
Future<void> _pickCoverImage() async {
final path = await ref.read(singleImagePickerProvider)();
if (path != null) {
setState(() => _coverFilePath = path);
if (path == null || !mounted) {
return;
}
final cropped = await Navigator.of(context).push<String>(
MaterialPageRoute(
builder: (_) => ImageCropPage(
sourcePath: path,
aspectRatio: 16 / 9,
maxOutputWidth: 1920,
),
),
);
if (cropped != null && mounted) {
setState(() => _coverFilePath = cropped);
}
}
/// 选图后必经裁剪:宣传图 3:1(观众页横幅),输出宽 ≤2400。
Future<void> _pickBannerImage() async {
final path = await ref.read(singleImagePickerProvider)();
if (path != null) {
setState(() => _bannerFilePath = path);
if (path == null || !mounted) {
return;
}
final cropped = await Navigator.of(context).push<String>(
MaterialPageRoute(
builder: (_) => ImageCropPage(
sourcePath: path,
aspectRatio: 3 / 1,
maxOutputWidth: 2400,
),
),
);
if (cropped != null && mounted) {
setState(() => _bannerFilePath = cropped);
}
}