Skip to content

Commit

Permalink
🚸 Improve the overall experiences (#258)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexV525 authored Jun 26, 2024
1 parent 29de33c commit 1f2ece4
Show file tree
Hide file tree
Showing 9 changed files with 70 additions and 50 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ that can be found in the LICENSE file. -->

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

## 4.3.1

### Improvements

- Downgrades the default resolution preset from `max` to `ultraHigh`.
- Improves pinch zooming experiences.
- Do not wait for focus mode and exposure mode to reset.
- Updates the capture actions section size to compatible with more cases.

## 4.3.0+1

### Fixes
Expand Down
2 changes: 1 addition & 1 deletion README-ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ final AssetEntity? entity = await CameraPicker.pickFromCamera(
| minimumRecordingDuration | `Duration` | 录制视频最短时长 | `const Duration(seconds: 1)` |
| theme | `ThemeData?` | 选择器的主题 | `CameraPicker.themeData(wechatThemeColor)` |
| textDelegate | `CameraPickerTextDelegate?` | 控制部件中的文字实现 | `CameraPickerTextDelegate` |
| resolutionPreset | `ResolutionPreset` | 相机的分辨率预设 | `ResolutionPreset.max` |
| resolutionPreset | `ResolutionPreset` | 相机的分辨率预设 | `ResolutionPreset.ultraHigh` |
| cameraQuarterTurns | `int` | 摄像机视图顺时针旋转次数,每次 90 度 | `0` |
| imageFormatGroup | `ImageFormatGroup` | 输出图像的格式描述 | `ImageFormatGroup.unknown` |
| preferredLensDirection | `CameraLensDirection` | 首次使用相机时首选的镜头方向 | `CameraLensDirection.back` |
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ Fields in `CameraPickerConfig`:
| minimumRecordingDuration | `Duration` | The minimum duration of the video recording process. | `const Duration(seconds: 1)` |
| theme | `ThemeData?` | Theme data for the picker. | `CameraPicker.themeData(wechatThemeColor)` |
| textDelegate | `CameraPickerTextDelegate?` | Text delegate that controls text in widgets. | `CameraPickerTextDelegate` |
| resolutionPreset | `ResolutionPreset` | Present resolution for the camera. | `ResolutionPreset.max` |
| resolutionPreset | `ResolutionPreset` | Present resolution for the camera. | `ResolutionPreset.ultraHigh` |
| cameraQuarterTurns | `int` | The number of clockwise quarter turns the camera view should be rotated. | `0` |
| imageFormatGroup | `ImageFormatGroup` | Describes the output of the raw image format. | `ImageFormatGroup.unknown` |
| preferredLensDirection | `CameraLensDirection` | Which lens direction is preferred when first using the camera. | `CameraLensDirection.back` |
Expand Down
17 changes: 17 additions & 0 deletions example/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ import 'pages/splash_page.dart';

const Color themeColor = Color(0xff00bc56);

/// The mock size is used for integration tests.
/// Changing this requires at least a hot-restart.
const Size? mockSize = null;

String? packageVersion;

void main() {
Expand Down Expand Up @@ -45,6 +49,19 @@ class MyApp extends StatelessWidget {
home: const SplashPage(),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
builder: (context, child) {
if (mockSize == null) {
return child!;
}
final mq = MediaQuery.of(context).copyWith(size: mockSize);
return MediaQuery(
data: mq,
child: Align(
alignment: Alignment.topCenter,
child: SizedBox.fromSize(size: mockSize, child: child),
),
);
},
);
}
}
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: wechat_camera_picker_demo
description: A new Flutter project.
version: 4.3.0+36
version: 4.3.1+37
publish_to: none

environment:
Expand Down
2 changes: 1 addition & 1 deletion lib/src/constants/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ final class CameraPickerConfig {
this.theme,
this.textDelegate,
this.cameraQuarterTurns = 0,
this.resolutionPreset = ResolutionPreset.max,
this.resolutionPreset = ResolutionPreset.ultraHigh,
this.imageFormatGroup = ImageFormatGroup.unknown,
this.preferredLensDirection = CameraLensDirection.back,
this.preferredFlashMode = FlashMode.off,
Expand Down
78 changes: 36 additions & 42 deletions lib/src/states/camera_picker_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ class CameraPickerState extends State<CameraPicker>
/// The locked capture orientation of the current camera instance.
DeviceOrientation? lockedCaptureOrientation;

/// The calculated capture actions section height.
double? lastCaptureActionsEffectiveHeight;

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -684,10 +687,10 @@ class CameraPickerState extends State<CameraPicker>
/// 处理双指缩放更新
Future<void> handleScaleUpdate(ScaleUpdateDetails details) async {
// When there are not exactly two fingers on screen don't scale
if (pointers != 2) {
if (innerController == null || pointers != 2) {
return;
}
zoom(details.scale);
zoom(details.scale * 2 - 1);
}

void restartExposurePointDisplayTimer() {
Expand Down Expand Up @@ -926,17 +929,16 @@ class CameraPickerState extends State<CameraPicker>
Navigator.of(context).pop(entity);
return;
}
await Future.wait(<Future<void>>[
wrapControllerMethod<void>(
'setFocusMode',
() => controller.setFocusMode(FocusMode.auto),
);
if (previousExposureMode != ExposureMode.locked) {
wrapControllerMethod<void>(
'setFocusMode',
() => controller.setFocusMode(FocusMode.auto),
),
if (previousExposureMode != ExposureMode.locked)
wrapControllerMethod<void>(
'setExposureMode',
() => controller.setExposureMode(previousExposureMode),
),
]);
'setExposureMode',
() => controller.setExposureMode(previousExposureMode),
);
}
await controller.resumePreview();
} catch (e, s) {
handleErrorWithHandler(e, s, pickerConfig.onError);
Expand Down Expand Up @@ -1283,8 +1285,9 @@ class CameraPickerState extends State<CameraPicker>
return AnimatedOpacity(
duration: recordDetectDuration,
opacity: controller?.value.isRecordingVideo ?? false ? 0 : 1,
child: Padding(
padding: const EdgeInsets.all(20),
child: Container(
height: 48.0,
alignment: Alignment.center,
child: Text(
tips,
style: const TextStyle(fontSize: 15),
Expand All @@ -1304,13 +1307,15 @@ class CameraPickerState extends State<CameraPicker>
required BoxConstraints constraints,
CameraController? controller,
}) {
const fallbackSize = 184.0;
const fallbackSize = 150.0;
final previewSize = controller?.value.previewSize;
final orientation = controller?.value.deviceOrientation ??
MediaQuery.orientationOf(context);
final isPortrait = orientation.toString().contains('portrait');
double effectiveSize;
if (previewSize != null) {
if (controller == null || pickerConfig.enableScaledPreview) {
effectiveSize = lastCaptureActionsEffectiveHeight ?? fallbackSize;
} else if (previewSize != null) {
Size constraintSize = Size(constraints.maxWidth, constraints.maxHeight);
if (isPortrait && constraintSize.aspectRatio > 1 ||
!isPortrait && constraintSize.aspectRatio < 1) {
Expand All @@ -1323,9 +1328,11 @@ class CameraPickerState extends State<CameraPicker>
effectiveSize = constraintSize.width -
constraintSize.height * previewSize.aspectRatio;
}
} else if (lastCaptureActionsEffectiveHeight != null) {
effectiveSize = lastCaptureActionsEffectiveHeight!;
} else {
// Fallback to a reasonable height.
effectiveSize = 184.0;
effectiveSize = fallbackSize;
}
if (effectiveSize <= 0) {
realDebugPrint(
Expand All @@ -1334,11 +1341,14 @@ class CameraPickerState extends State<CameraPicker>
'orientation: $orientation',
);
effectiveSize = fallbackSize;
} else if (effectiveSize < fallbackSize) {
effectiveSize = fallbackSize;
}

return SizedBox(
lastCaptureActionsEffectiveHeight = effectiveSize;
return Container(
width: isPortrait ? null : effectiveSize,
height: isPortrait ? effectiveSize : null,
padding: EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom),
child: Flex(
direction: isPortrait ? Axis.horizontal : Axis.vertical,
verticalDirection: orientation == DeviceOrientation.landscapeLeft
Expand Down Expand Up @@ -1670,8 +1680,8 @@ class CameraPickerState extends State<CameraPicker>
image: true,
onTap: () {
// Focus on the center point when using semantics tap.
final Size size = MediaQuery.of(context).size;
final TapUpDetails details = TapUpDetails(
final size = MediaQuery.sizeOf(context);
final details = TapUpDetails(
kind: PointerDeviceKind.touch,
globalPosition: Offset(size.width / 2, size.height / 2),
);
Expand Down Expand Up @@ -1752,22 +1762,6 @@ class CameraPickerState extends State<CameraPicker>
preview = Stack(
children: <Widget>[
preview,
Positioned.fill(
child: ExcludeSemantics(
child: RotatedBox(
quarterTurns: cameraQuarterTurns,
child: Align(
alignment: {
DeviceOrientation.portraitUp: Alignment.bottomCenter,
DeviceOrientation.portraitDown: Alignment.topCenter,
DeviceOrientation.landscapeLeft: Alignment.centerRight,
DeviceOrientation.landscapeRight: Alignment.centerLeft,
}[cameraValue.deviceOrientation]!,
child: buildCaptureTips(innerController),
),
),
),
),
if (pickerConfig.enableSetExposure)
buildExposureDetector(context, constraints),
buildFocusingPoint(
Expand Down Expand Up @@ -1827,9 +1821,10 @@ class CameraPickerState extends State<CameraPicker>
BoxConstraints constraints,
DeviceOrientation? deviceOrientation,
) {
final orientation = deviceOrientation ?? MediaQuery.of(context).orientation;
final orientation = deviceOrientation ?? MediaQuery.orientationOf(context);
final isPortrait = orientation.toString().contains('portrait');
return SafeArea(
bottom: false,
child: Flex(
direction: isPortrait ? Axis.vertical : Axis.horizontal,
textDirection: orientation == DeviceOrientation.landscapeRight
Expand All @@ -1844,8 +1839,7 @@ class CameraPickerState extends State<CameraPicker>
child: buildSettingActions(context),
),
const Spacer(),
if (enableScaledPreview)
ExcludeSemantics(child: buildCaptureTips(innerController)),
ExcludeSemantics(child: buildCaptureTips(innerController)),
Semantics(
sortKey: const OrdinalSortKey(2),
hidden: innerController == null,
Expand Down Expand Up @@ -1907,8 +1901,8 @@ class CameraPickerState extends State<CameraPicker>
image: true,
onTap: () {
// Focus on the center point when using semantics tap.
final Size size = MediaQuery.of(context).size;
final TapUpDetails details = TapUpDetails(
final size = MediaQuery.sizeOf(context);
final details = TapUpDetails(
kind: PointerDeviceKind.touch,
globalPosition: Offset(size.width / 2, size.height / 2),
);
Expand Down
6 changes: 3 additions & 3 deletions lib/src/states/camera_picker_viewer_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -150,18 +150,18 @@ class CameraPickerViewerState extends State<CameraPickerViewer> {
try {
final PermissionState ps = await PhotoManager.requestPermissionExtend();
if (ps == PermissionState.authorized || ps == PermissionState.limited) {
final filePath = previewFile.path;
switch (widget.viewType) {
case CameraPickerViewType.image:
final String filePath = previewFile.path;
entity = await PhotoManager.editor.saveImageWithPath(
filePath,
title: path.basename(previewFile.path),
title: path.basename(filePath),
);
break;
case CameraPickerViewType.video:
entity = await PhotoManager.editor.saveVideo(
previewFile,
title: path.basename(previewFile.path),
title: path.basename(filePath),
);
break;
}
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: wechat_camera_picker
version: 4.3.0+1
version: 4.3.1
description: |
A camera picker for Flutter projects based on WeChat's UI,
which is also a separate runnable extension to the
Expand Down

0 comments on commit 1f2ece4

Please sign in to comment.