Skip to content

Commit 1f2ece4

Browse files
authored
🚸 Improve the overall experiences (#258)
1 parent 29de33c commit 1f2ece4

File tree

9 files changed

+70
-50
lines changed

9 files changed

+70
-50
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@ that can be found in the LICENSE file. -->
66

77
See the [Migration Guide](guides/migration_guide.md) for breaking changes between versions.
88

9+
## 4.3.1
10+
11+
### Improvements
12+
13+
- Downgrades the default resolution preset from `max` to `ultraHigh`.
14+
- Improves pinch zooming experiences.
15+
- Do not wait for focus mode and exposure mode to reset.
16+
- Updates the capture actions section size to compatible with more cases.
17+
918
## 4.3.0+1
1019

1120
### Fixes

README-ZH.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ final AssetEntity? entity = await CameraPicker.pickFromCamera(
195195
| minimumRecordingDuration | `Duration` | 录制视频最短时长 | `const Duration(seconds: 1)` |
196196
| theme | `ThemeData?` | 选择器的主题 | `CameraPicker.themeData(wechatThemeColor)` |
197197
| textDelegate | `CameraPickerTextDelegate?` | 控制部件中的文字实现 | `CameraPickerTextDelegate` |
198-
| resolutionPreset | `ResolutionPreset` | 相机的分辨率预设 | `ResolutionPreset.max` |
198+
| resolutionPreset | `ResolutionPreset` | 相机的分辨率预设 | `ResolutionPreset.ultraHigh` |
199199
| cameraQuarterTurns | `int` | 摄像机视图顺时针旋转次数,每次 90 度 | `0` |
200200
| imageFormatGroup | `ImageFormatGroup` | 输出图像的格式描述 | `ImageFormatGroup.unknown` |
201201
| preferredLensDirection | `CameraLensDirection` | 首次使用相机时首选的镜头方向 | `CameraLensDirection.back` |

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ Fields in `CameraPickerConfig`:
200200
| minimumRecordingDuration | `Duration` | The minimum duration of the video recording process. | `const Duration(seconds: 1)` |
201201
| theme | `ThemeData?` | Theme data for the picker. | `CameraPicker.themeData(wechatThemeColor)` |
202202
| textDelegate | `CameraPickerTextDelegate?` | Text delegate that controls text in widgets. | `CameraPickerTextDelegate` |
203-
| resolutionPreset | `ResolutionPreset` | Present resolution for the camera. | `ResolutionPreset.max` |
203+
| resolutionPreset | `ResolutionPreset` | Present resolution for the camera. | `ResolutionPreset.ultraHigh` |
204204
| cameraQuarterTurns | `int` | The number of clockwise quarter turns the camera view should be rotated. | `0` |
205205
| imageFormatGroup | `ImageFormatGroup` | Describes the output of the raw image format. | `ImageFormatGroup.unknown` |
206206
| preferredLensDirection | `CameraLensDirection` | Which lens direction is preferred when first using the camera. | `CameraLensDirection.back` |

example/lib/main.dart

+17
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ import 'pages/splash_page.dart';
1212

1313
const Color themeColor = Color(0xff00bc56);
1414

15+
/// The mock size is used for integration tests.
16+
/// Changing this requires at least a hot-restart.
17+
const Size? mockSize = null;
18+
1519
String? packageVersion;
1620

1721
void main() {
@@ -45,6 +49,19 @@ class MyApp extends StatelessWidget {
4549
home: const SplashPage(),
4650
localizationsDelegates: AppLocalizations.localizationsDelegates,
4751
supportedLocales: AppLocalizations.supportedLocales,
52+
builder: (context, child) {
53+
if (mockSize == null) {
54+
return child!;
55+
}
56+
final mq = MediaQuery.of(context).copyWith(size: mockSize);
57+
return MediaQuery(
58+
data: mq,
59+
child: Align(
60+
alignment: Alignment.topCenter,
61+
child: SizedBox.fromSize(size: mockSize, child: child),
62+
),
63+
);
64+
},
4865
);
4966
}
5067
}

example/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: wechat_camera_picker_demo
22
description: A new Flutter project.
3-
version: 4.3.0+36
3+
version: 4.3.1+37
44
publish_to: none
55

66
environment:

lib/src/constants/config.dart

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ final class CameraPickerConfig {
3131
this.theme,
3232
this.textDelegate,
3333
this.cameraQuarterTurns = 0,
34-
this.resolutionPreset = ResolutionPreset.max,
34+
this.resolutionPreset = ResolutionPreset.ultraHigh,
3535
this.imageFormatGroup = ImageFormatGroup.unknown,
3636
this.preferredLensDirection = CameraLensDirection.back,
3737
this.preferredFlashMode = FlashMode.off,

lib/src/states/camera_picker_state.dart

+36-42
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,9 @@ class CameraPickerState extends State<CameraPicker>
232232
/// The locked capture orientation of the current camera instance.
233233
DeviceOrientation? lockedCaptureOrientation;
234234

235+
/// The calculated capture actions section height.
236+
double? lastCaptureActionsEffectiveHeight;
237+
235238
@override
236239
void initState() {
237240
super.initState();
@@ -684,10 +687,10 @@ class CameraPickerState extends State<CameraPicker>
684687
/// 处理双指缩放更新
685688
Future<void> handleScaleUpdate(ScaleUpdateDetails details) async {
686689
// When there are not exactly two fingers on screen don't scale
687-
if (pointers != 2) {
690+
if (innerController == null || pointers != 2) {
688691
return;
689692
}
690-
zoom(details.scale);
693+
zoom(details.scale * 2 - 1);
691694
}
692695

693696
void restartExposurePointDisplayTimer() {
@@ -926,17 +929,16 @@ class CameraPickerState extends State<CameraPicker>
926929
Navigator.of(context).pop(entity);
927930
return;
928931
}
929-
await Future.wait(<Future<void>>[
932+
wrapControllerMethod<void>(
933+
'setFocusMode',
934+
() => controller.setFocusMode(FocusMode.auto),
935+
);
936+
if (previousExposureMode != ExposureMode.locked) {
930937
wrapControllerMethod<void>(
931-
'setFocusMode',
932-
() => controller.setFocusMode(FocusMode.auto),
933-
),
934-
if (previousExposureMode != ExposureMode.locked)
935-
wrapControllerMethod<void>(
936-
'setExposureMode',
937-
() => controller.setExposureMode(previousExposureMode),
938-
),
939-
]);
938+
'setExposureMode',
939+
() => controller.setExposureMode(previousExposureMode),
940+
);
941+
}
940942
await controller.resumePreview();
941943
} catch (e, s) {
942944
handleErrorWithHandler(e, s, pickerConfig.onError);
@@ -1283,8 +1285,9 @@ class CameraPickerState extends State<CameraPicker>
12831285
return AnimatedOpacity(
12841286
duration: recordDetectDuration,
12851287
opacity: controller?.value.isRecordingVideo ?? false ? 0 : 1,
1286-
child: Padding(
1287-
padding: const EdgeInsets.all(20),
1288+
child: Container(
1289+
height: 48.0,
1290+
alignment: Alignment.center,
12881291
child: Text(
12891292
tips,
12901293
style: const TextStyle(fontSize: 15),
@@ -1304,13 +1307,15 @@ class CameraPickerState extends State<CameraPicker>
13041307
required BoxConstraints constraints,
13051308
CameraController? controller,
13061309
}) {
1307-
const fallbackSize = 184.0;
1310+
const fallbackSize = 150.0;
13081311
final previewSize = controller?.value.previewSize;
13091312
final orientation = controller?.value.deviceOrientation ??
13101313
MediaQuery.orientationOf(context);
13111314
final isPortrait = orientation.toString().contains('portrait');
13121315
double effectiveSize;
1313-
if (previewSize != null) {
1316+
if (controller == null || pickerConfig.enableScaledPreview) {
1317+
effectiveSize = lastCaptureActionsEffectiveHeight ?? fallbackSize;
1318+
} else if (previewSize != null) {
13141319
Size constraintSize = Size(constraints.maxWidth, constraints.maxHeight);
13151320
if (isPortrait && constraintSize.aspectRatio > 1 ||
13161321
!isPortrait && constraintSize.aspectRatio < 1) {
@@ -1323,9 +1328,11 @@ class CameraPickerState extends State<CameraPicker>
13231328
effectiveSize = constraintSize.width -
13241329
constraintSize.height * previewSize.aspectRatio;
13251330
}
1331+
} else if (lastCaptureActionsEffectiveHeight != null) {
1332+
effectiveSize = lastCaptureActionsEffectiveHeight!;
13261333
} else {
13271334
// Fallback to a reasonable height.
1328-
effectiveSize = 184.0;
1335+
effectiveSize = fallbackSize;
13291336
}
13301337
if (effectiveSize <= 0) {
13311338
realDebugPrint(
@@ -1334,11 +1341,14 @@ class CameraPickerState extends State<CameraPicker>
13341341
'orientation: $orientation',
13351342
);
13361343
effectiveSize = fallbackSize;
1344+
} else if (effectiveSize < fallbackSize) {
1345+
effectiveSize = fallbackSize;
13371346
}
1338-
1339-
return SizedBox(
1347+
lastCaptureActionsEffectiveHeight = effectiveSize;
1348+
return Container(
13401349
width: isPortrait ? null : effectiveSize,
13411350
height: isPortrait ? effectiveSize : null,
1351+
padding: EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom),
13421352
child: Flex(
13431353
direction: isPortrait ? Axis.horizontal : Axis.vertical,
13441354
verticalDirection: orientation == DeviceOrientation.landscapeLeft
@@ -1670,8 +1680,8 @@ class CameraPickerState extends State<CameraPicker>
16701680
image: true,
16711681
onTap: () {
16721682
// Focus on the center point when using semantics tap.
1673-
final Size size = MediaQuery.of(context).size;
1674-
final TapUpDetails details = TapUpDetails(
1683+
final size = MediaQuery.sizeOf(context);
1684+
final details = TapUpDetails(
16751685
kind: PointerDeviceKind.touch,
16761686
globalPosition: Offset(size.width / 2, size.height / 2),
16771687
);
@@ -1752,22 +1762,6 @@ class CameraPickerState extends State<CameraPicker>
17521762
preview = Stack(
17531763
children: <Widget>[
17541764
preview,
1755-
Positioned.fill(
1756-
child: ExcludeSemantics(
1757-
child: RotatedBox(
1758-
quarterTurns: cameraQuarterTurns,
1759-
child: Align(
1760-
alignment: {
1761-
DeviceOrientation.portraitUp: Alignment.bottomCenter,
1762-
DeviceOrientation.portraitDown: Alignment.topCenter,
1763-
DeviceOrientation.landscapeLeft: Alignment.centerRight,
1764-
DeviceOrientation.landscapeRight: Alignment.centerLeft,
1765-
}[cameraValue.deviceOrientation]!,
1766-
child: buildCaptureTips(innerController),
1767-
),
1768-
),
1769-
),
1770-
),
17711765
if (pickerConfig.enableSetExposure)
17721766
buildExposureDetector(context, constraints),
17731767
buildFocusingPoint(
@@ -1827,9 +1821,10 @@ class CameraPickerState extends State<CameraPicker>
18271821
BoxConstraints constraints,
18281822
DeviceOrientation? deviceOrientation,
18291823
) {
1830-
final orientation = deviceOrientation ?? MediaQuery.of(context).orientation;
1824+
final orientation = deviceOrientation ?? MediaQuery.orientationOf(context);
18311825
final isPortrait = orientation.toString().contains('portrait');
18321826
return SafeArea(
1827+
bottom: false,
18331828
child: Flex(
18341829
direction: isPortrait ? Axis.vertical : Axis.horizontal,
18351830
textDirection: orientation == DeviceOrientation.landscapeRight
@@ -1844,8 +1839,7 @@ class CameraPickerState extends State<CameraPicker>
18441839
child: buildSettingActions(context),
18451840
),
18461841
const Spacer(),
1847-
if (enableScaledPreview)
1848-
ExcludeSemantics(child: buildCaptureTips(innerController)),
1842+
ExcludeSemantics(child: buildCaptureTips(innerController)),
18491843
Semantics(
18501844
sortKey: const OrdinalSortKey(2),
18511845
hidden: innerController == null,
@@ -1907,8 +1901,8 @@ class CameraPickerState extends State<CameraPicker>
19071901
image: true,
19081902
onTap: () {
19091903
// Focus on the center point when using semantics tap.
1910-
final Size size = MediaQuery.of(context).size;
1911-
final TapUpDetails details = TapUpDetails(
1904+
final size = MediaQuery.sizeOf(context);
1905+
final details = TapUpDetails(
19121906
kind: PointerDeviceKind.touch,
19131907
globalPosition: Offset(size.width / 2, size.height / 2),
19141908
);

lib/src/states/camera_picker_viewer_state.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,18 @@ class CameraPickerViewerState extends State<CameraPickerViewer> {
150150
try {
151151
final PermissionState ps = await PhotoManager.requestPermissionExtend();
152152
if (ps == PermissionState.authorized || ps == PermissionState.limited) {
153+
final filePath = previewFile.path;
153154
switch (widget.viewType) {
154155
case CameraPickerViewType.image:
155-
final String filePath = previewFile.path;
156156
entity = await PhotoManager.editor.saveImageWithPath(
157157
filePath,
158-
title: path.basename(previewFile.path),
158+
title: path.basename(filePath),
159159
);
160160
break;
161161
case CameraPickerViewType.video:
162162
entity = await PhotoManager.editor.saveVideo(
163163
previewFile,
164-
title: path.basename(previewFile.path),
164+
title: path.basename(filePath),
165165
);
166166
break;
167167
}

pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: wechat_camera_picker
2-
version: 4.3.0+1
2+
version: 4.3.1
33
description: |
44
A camera picker for Flutter projects based on WeChat's UI,
55
which is also a separate runnable extension to the

0 commit comments

Comments
 (0)