feat(app): camera preview WYSIWYG aspect + pinch zoom with double-tap reset

Preview now centers at the sensor aspect ratio (letterboxed on the dark
backdrop) instead of FittedBox cover, which cropped ~38% horizontally and
made the preview differ from the full-frame takePicture output.

Zoom capability hangs off CaptureSource as default implementations
(minZoom/maxZoom = 1, setZoom no-op) so existing fakes stay untouched;
CameraPluginSource probes getMin/MaxZoomLevel after initialize (failure
keeps 1/1 and disables the gesture). The page attaches a scale
GestureDetector only when maxZoom > 1: pinch drives setZoom (throttled at
0.05 delta, serialized to prevent out-of-order platform calls), a badge
shows the current level and hides after 1s, double-tap resets to 1.0x,
and camera flip/reopen resets zoom state. _StaticCaptureSource in
album_detail_page_test.dart switches implements -> extends to inherit the
new defaults.

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-28 16:17:07 +08:00
parent 65cd6849cc
commit ac602acf47
3 changed files with 273 additions and 23 deletions
@@ -403,8 +403,9 @@ void main() {
});
}
/// 相机源替身(详情页跳连拍页测试:仅就绪,不拍摄)。
class _StaticCaptureSource implements CaptureSource {
/// 相机源替身(详情页跳连拍页测试:仅就绪,不拍摄)。extends 继承
/// 接口默认实现(闪光灯/变焦能力默认不支持——UI 不显示开关不启用手势)。
class _StaticCaptureSource extends CaptureSource {
@override
Future<void> initialize() async {}
@@ -414,12 +415,6 @@ class _StaticCaptureSource implements CaptureSource {
@override
Widget buildPreview() => const SizedBox();
@override
bool get supportsFlash => false;
@override
Future<void> setFlashEnabled(bool enabled) async {}
@override
Future<void> dispose() async {}
}