Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚸 Improve the overall experiences #258

Merged
merged 8 commits into from
Jun 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading