支持录制中切换广角/主摄

This commit is contained in:
2026-07-01 09:59:21 +08:00
parent f6347e99cd
commit da2e69b014
11 changed files with 656 additions and 82 deletions
@@ -207,12 +207,14 @@ class RecordingStopResult {
required this.status,
this.fileSaved = true,
this.fileErrorMessage,
this.segmentOutputPaths = const [],
});
final String? outputPath;
final RecordingStatus status;
final bool fileSaved;
final String? fileErrorMessage;
final List<String> segmentOutputPaths;
factory RecordingStopResult.fromMap(Map<String, dynamic>? result) {
return RecordingStopResult(
@@ -222,6 +224,11 @@ class RecordingStopResult {
),
fileSaved: result?['fileSaved'] as bool? ?? true,
fileErrorMessage: result?['fileErrorMessage'] as String?,
segmentOutputPaths:
(result?['segmentOutputPaths'] as List?)?.whereType<String>().toList(
growable: false,
) ??
const [],
);
}
}
@@ -364,9 +364,10 @@ class RecordingViewModel extends Notifier<RecordingModel> {
),
);
} on PlatformException catch (error) {
_updateSession(
(s) => s.copyWith(errorMessage: error.message ?? '相机倍距设置失败'),
);
final message = error.code == 'ZOOM_FAILED'
? '切换镜头失败,请重试'
: (error.message ?? '相机倍距设置失败');
_updateSession((s) => s.copyWith(errorMessage: message));
}
}
@@ -170,7 +170,7 @@ class _HeaderPasteActions extends StatelessWidget {
return Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// _HeaderActionButton(label: 'mock', onPressed: onMockCopy),
_HeaderActionButton(label: 'mock', onPressed: onMockCopy),
_HeaderActionButton(
label: '粘贴选手信息',
onPressed: () => onPasteEventInfo(),
@@ -145,7 +145,6 @@ class RecordingHudWidget extends StatelessWidget {
right: 16.r,
bottom: _recordButtonBottom + _recordButtonSize + 14.h,
child: _ZoomPresetControl(
isRecording: isRecording,
zoomRatio: zoomRatio,
minZoomRatio: minZoomRatio,
maxZoomRatio: maxZoomRatio,
@@ -192,16 +191,12 @@ class RecordingHudWidget extends StatelessWidget {
}
List<double> _zoomPresetsForRange(double minZoomRatio) {
return [
if (minZoomRatio < 1.0) minZoomRatio,
1.0,
];
return [if (minZoomRatio < 1.0) minZoomRatio, 1.0];
}
}
class _ZoomPresetControl extends StatelessWidget {
const _ZoomPresetControl({
required this.isRecording,
required this.zoomRatio,
required this.minZoomRatio,
required this.maxZoomRatio,
@@ -209,7 +204,6 @@ class _ZoomPresetControl extends StatelessWidget {
required this.onSelected,
});
final bool isRecording;
final double zoomRatio;
final double minZoomRatio;
final double maxZoomRatio;
@@ -241,7 +235,7 @@ class _ZoomPresetControl extends StatelessWidget {
displayRatio: preset,
requestRatio: preset,
selected: _isPresetSelected(preset),
enabled: !_wouldSwitchPhysicalCamera(preset),
enabled: true,
onSelected: onSelected,
),
],
@@ -263,15 +257,6 @@ class _ZoomPresetControl extends StatelessWidget {
}
return (zoomRatio - preset).abs() < 0.05;
}
bool _wouldSwitchPhysicalCamera(double preset) {
if (!isRecording) {
return false;
}
final currentIsUltraWide = zoomRatio < 1.0;
final targetIsUltraWide = preset < 1.0;
return currentIsUltraWide != targetIsUltraWide;
}
}
class _ZoomPresetButton extends StatelessWidget {
@@ -294,7 +279,17 @@ class _ZoomPresetButton extends StatelessWidget {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 1.r),
child: TextButton(
onPressed: selected || !enabled ? null : () => onSelected(requestRatio),
onPressed: selected || !enabled
? null
: () => RateLimit.instance.debounce<void>(
key:
'recording.session.zoom.${requestRatio.toStringAsFixed(1)}',
value: null,
duration: Duration(milliseconds: 300),
onCallback: (_) async {
onSelected(requestRatio);
},
),
style: TextButton.styleFrom(
minimumSize: Size(38.r, 32.r),
padding: EdgeInsets.zero,