Skip to content

Commit 0e5a391

Browse files
authored
🔖 3.5.0 (#117)
1 parent 98392a0 commit 0e5a391

File tree

6 files changed

+44
-37
lines changed

6 files changed

+44
-37
lines changed

CHANGELOG.md

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,7 @@ that can be found in the LICENSE file. -->
44

55
# Changelog
66

7-
## 3.5.0-dev.3
8-
9-
### Improvements
10-
11-
- Prevent switching cameras when taking picture or recording video. (#120)
12-
13-
## 3.5.0-dev.2
14-
15-
### Improvements
16-
17-
- Re-export `CameraPicker`'s constructor. (#116)
18-
19-
## 3.5.0-dev.1
7+
## 3.5.0
208

219
### New features
2210

@@ -25,6 +13,9 @@ that can be found in the LICENSE file. -->
2513
### Improvements
2614

2715
- Expose multiple internal widgets. (#113)
16+
- Re-export `CameraPicker`'s constructor. (#116)
17+
- Avoid duplicate entity saving. (#117)
18+
- Prevent switching cameras when taking picture or recording video. (#120)
2819

2920
## 3.4.0
3021

lib/src/internals/methods.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,5 @@ void handleErrorWithHandler(
2727
}
2828
throw e;
2929
}
30+
31+
T? ambiguate<T>(T value) => value;

lib/src/states/camera_picker_state.dart

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import 'dart:async';
77
import 'dart:io';
88
import 'dart:math' as math;
99

10-
import 'package:bindings_compatible/bindings_compatible.dart';
1110
import 'package:camera/camera.dart';
1211
import 'package:camera_platform_interface/camera_platform_interface.dart';
1312
import 'package:flutter/gestures.dart';
@@ -49,7 +48,9 @@ class CameraPickerState extends State<CameraPicker>
4948
/// 在开始录像前,最后一次在拍照按钮按下的位置
5049
Offset? lastShootingButtonPressedPosition;
5150

52-
final ValueNotifier<bool> isExposureModeDisplays = ValueNotifier<bool>(false);
51+
/// Whether the focus point is displaying.
52+
/// 是否正在展示当前的聚焦点
53+
final ValueNotifier<bool> isFocusPointDisplays = ValueNotifier<bool>(false);
5354

5455
/// The controller for the current camera.
5556
/// 当前相机实例的控制器
@@ -58,7 +59,7 @@ class CameraPickerState extends State<CameraPicker>
5859

5960
/// Available cameras.
6061
/// 可用的相机实例
61-
late List<CameraDescription> cameras;
62+
late final List<CameraDescription> cameras;
6263

6364
/// Current exposure offset.
6465
/// 当前曝光值
@@ -162,7 +163,7 @@ class CameraPickerState extends State<CameraPicker>
162163
@override
163164
void initState() {
164165
super.initState();
165-
useWidgetsBinding().addObserver(this);
166+
ambiguate(WidgetsBinding.instance)?.addObserver(this);
166167

167168
// TODO(Alex): Currently hide status bar will cause the viewport shaking on Android.
168169
/// Hide system status bar automatically when the platform is not Android.
@@ -179,11 +180,11 @@ class CameraPickerState extends State<CameraPicker>
179180
if (!Platform.isAndroid) {
180181
SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
181182
}
182-
useWidgetsBinding().removeObserver(this);
183+
ambiguate(WidgetsBinding.instance)?.removeObserver(this);
183184
innerController?.dispose();
184185
currentExposureOffset.dispose();
185186
lastExposurePoint.dispose();
186-
isExposureModeDisplays.dispose();
187+
isFocusPointDisplays.dispose();
187188
exposurePointDisplayTimer?.cancel();
188189
exposureModeDisplayTimer?.cancel();
189190
recordDetectTimer?.cancel();
@@ -255,7 +256,7 @@ class CameraPickerState extends State<CameraPicker>
255256
});
256257
// **IMPORTANT**: Push methods into a post frame callback, which ensures the
257258
// controller has already unbind from widgets.
258-
useWidgetsBinding().addPostFrameCallback((_) async {
259+
ambiguate(WidgetsBinding.instance)?.addPostFrameCallback((_) async {
259260
// When the [cameraDescription] is null, which means this is the first
260261
// time initializing cameras, so available cameras should be fetched.
261262
if (cameraDescription == null) {
@@ -264,7 +265,7 @@ class CameraPickerState extends State<CameraPicker>
264265

265266
// After cameras fetched, judge again with the list is empty or not to
266267
// ensure there is at least an available camera for use.
267-
if (cameraDescription == null && (cameras.isEmpty)) {
268+
if (cameraDescription == null && cameras.isEmpty) {
268269
handleErrorWithHandler(
269270
CameraException(
270271
'No CameraDescription found.',
@@ -440,7 +441,7 @@ class CameraPickerState extends State<CameraPicker>
440441
void restartDisplayModeDisplayTimer() {
441442
exposureModeDisplayTimer?.cancel();
442443
exposureModeDisplayTimer = Timer(const Duration(seconds: 2), () {
443-
isExposureModeDisplays.value = false;
444+
isFocusPointDisplays.value = false;
444445
});
445446
}
446447

@@ -474,7 +475,7 @@ class CameraPickerState extends State<CameraPicker>
474475
Offset position,
475476
BoxConstraints constraints,
476477
) async {
477-
isExposureModeDisplays.value = false;
478+
isFocusPointDisplays.value = false;
478479
// Ignore point update when the new point is less than 8% and higher than
479480
// 92% of the screen's height.
480481
if (position.dy < constraints.maxHeight / 12 ||
@@ -535,8 +536,8 @@ class CameraPickerState extends State<CameraPicker>
535536
} catch (e, s) {
536537
handleErrorWithHandler(e, pickerConfig.onError, s: s);
537538
}
538-
if (!isExposureModeDisplays.value) {
539-
isExposureModeDisplays.value = true;
539+
if (!isFocusPointDisplays.value) {
540+
isFocusPointDisplays.value = true;
540541
}
541542
restartDisplayModeDisplayTimer();
542543
restartExposurePointDisplayTimer();
@@ -1008,7 +1009,7 @@ class CameraPickerState extends State<CameraPicker>
10081009
final bool isLocked = mode == ExposureMode.locked;
10091010
final Color? color = isLocked ? _lockedColor : theme.iconTheme.color;
10101011
final Widget lineWidget = ValueListenableBuilder<bool>(
1011-
valueListenable: isExposureModeDisplays,
1012+
valueListenable: isFocusPointDisplays,
10121013
builder: (_, bool value, Widget? child) => AnimatedOpacity(
10131014
duration: _kDuration,
10141015
opacity: value ? 1 : 0,
@@ -1077,7 +1078,7 @@ class CameraPickerState extends State<CameraPicker>
10771078
return Column(
10781079
children: <Widget>[
10791080
ValueListenableBuilder<bool>(
1080-
valueListenable: isExposureModeDisplays,
1081+
valueListenable: isFocusPointDisplays,
10811082
builder: (_, bool value, Widget? child) => AnimatedOpacity(
10821083
duration: _kDuration,
10831084
opacity: value ? 1 : 0,

lib/src/states/camera_picker_viewer_state.dart

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class CameraPickerViewerState extends State<CameraPickerViewer> {
4747
/// 初始化视频控制器时是否发生错误
4848
bool hasErrorWhenInitializing = false;
4949

50+
/// Whether the saving process is ongoing.
51+
bool isSavingEntity = false;
52+
5053
CameraErrorHandler? get onError => widget.pickerConfig.onError;
5154

5255
@override
@@ -121,13 +124,23 @@ class CameraPickerViewerState extends State<CameraPickerViewer> {
121124
/// While the entity might returned null, there's no side effects if popping `null`
122125
/// because the parent picker will ignore it.
123126
Future<void> createAssetEntityAndPop() async {
127+
if (isSavingEntity) {
128+
return;
129+
}
130+
isSavingEntity = true;
124131
final CameraPickerViewType viewType = widget.viewType;
125132
if (widget.pickerConfig.onEntitySaving != null) {
126-
await widget.pickerConfig.onEntitySaving!(
127-
context,
128-
widget.viewType,
129-
File(widget.previewXFile.path),
130-
);
133+
try {
134+
await widget.pickerConfig.onEntitySaving!(
135+
context,
136+
widget.viewType,
137+
File(widget.previewXFile.path),
138+
);
139+
} catch (e, s) {
140+
handleErrorWithHandler(e, widget.pickerConfig.onError, s: s);
141+
} finally {
142+
isSavingEntity = false;
143+
}
131144
return;
132145
}
133146
AssetEntity? entity;
@@ -165,6 +178,7 @@ class CameraPickerViewerState extends State<CameraPickerViewer> {
165178
realDebugPrint('Saving entity failed: $e');
166179
handleErrorWithHandler(e, widget.pickerConfig.onError, s: s);
167180
} finally {
181+
isSavingEntity = false;
168182
if (mounted) {
169183
Navigator.of(context).pop(entity);
170184
}

lib/src/widgets/camera_progress_button.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
import 'dart:math' as math;
66

7-
import 'package:bindings_compatible/bindings_compatible.dart';
87
import 'package:flutter/material.dart';
98

109
import '../constants/styles.dart';
10+
import '../internals/methods.dart';
1111

1212
class CameraProgressButton extends StatefulWidget {
1313
const CameraProgressButton({
@@ -41,7 +41,7 @@ class _CircleProgressState extends State<CameraProgressButton>
4141
@override
4242
void initState() {
4343
super.initState();
44-
useWidgetsBinding().addPostFrameCallback((Duration _) {
44+
ambiguate(WidgetsBinding.instance)?.addPostFrameCallback((_) {
4545
progressController.forward();
4646
});
4747
}

pubspec.yaml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: wechat_camera_picker
22
description: A camera picker which is an extension to wechat_assets_picker, but can be run separately.
3-
version: 3.5.0-dev.3
3+
version: 3.5.0
44
homepage: https://github.com/fluttercandies/flutter_wechat_camera_picker
55

66
environment:
@@ -11,9 +11,8 @@ dependencies:
1111
flutter:
1212
sdk: flutter
1313

14-
bindings_compatible: ^1.0.1
1514
camera: ^0.9.6
1615
camera_platform_interface: ^2.1.5
1716
path: ^1.8.0
18-
photo_manager: ^2.1.0+2
17+
photo_manager: ^2.2.0
1918
video_player: ^2.3.2

0 commit comments

Comments
 (0)