feat(app): P0 batch 1 — photo viewer zoom, camera lifecycle, image memory management

P0-2 查看器缩放:InteractiveViewer(5x max,放大后平移,1x 时穿透到
  PageView 滑动切页)
P0-3 相机后台释放:WidgetsBindingObserver——paused 时 dispose(省电+
  隐私指示灯),resumed 时重开(沿用前后摄/闪光灯偏好)
P0-6 图片内存管理:PhotoThumbnail 加 maxCacheWidth 参数——网格/列表
  缩略图限制解码宽度(600/400px),查看器大图不限

397/397 全绿、analyze 0

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-28 10:35:14 +08:00
parent 98e073d8c8
commit 9edcb3f2b1
7 changed files with 140 additions and 76 deletions
+19 -1
View File
@@ -155,7 +155,8 @@ class CapturePage extends ConsumerStatefulWidget {
enum _CameraPhase { loading, ready, denied, failed }
class _CapturePageState extends ConsumerState<CapturePage> {
class _CapturePageState extends ConsumerState<CapturePage>
with WidgetsBindingObserver {
CaptureSource? _source;
_CameraPhase _phase = _CameraPhase.loading;
@@ -181,16 +182,33 @@ class _CapturePageState extends ConsumerState<CapturePage> {
@override
void initState() {
super.initState();
// P0-3:监听 App 生命周期——后台释放相机(省电 + 隐私),回前台重开。
WidgetsBinding.instance.addObserver(this);
_initCamera();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
_feedbackTimer?.cancel();
_source?.dispose().ignore();
super.dispose();
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
super.didChangeAppLifecycleState(state);
// P0-3:后台 → 释放相机硬件(不释放则摄像头指示灯常亮 + 耗电);
// 回前台 → 重新初始化(沿用当前前后摄/闪光灯偏好)。
if (state == AppLifecycleState.paused && _source != null) {
_source?.dispose().ignore();
_source = null;
setState(() => _phase = _CameraPhase.loading);
} else if (state == AppLifecycleState.resumed && _source == null) {
_initCamera();
}
}
Future<void> _initCamera({bool? preferFront}) async {
final front = preferFront ?? _preferFront;
setState(() => _phase = _CameraPhase.loading);