Julian Steenbakker

Merge branch 'hotfix/usage-after-dispose' into hotfix/hot-reload

# Conflicts:
#	lib/src/mobile_scanner.dart
@@ -22,10 +22,11 @@ class ScannerErrorWidget extends StatelessWidget { @@ -22,10 +22,11 @@ class ScannerErrorWidget extends StatelessWidget {
22 error.errorCode.message, 22 error.errorCode.message,
23 style: const TextStyle(color: Colors.white), 23 style: const TextStyle(color: Colors.white),
24 ), 24 ),
25 - if (error.errorDetails != null) Text(  
26 - error.errorDetails!.message ?? '',  
27 - style: const TextStyle(color: Colors.white),  
28 - ), 25 + if (error.errorDetails?.message case final String message)
  26 + Text(
  27 + message,
  28 + style: const TextStyle(color: Colors.white),
  29 + ),
29 ], 30 ],
30 ), 31 ),
31 ), 32 ),
@@ -83,7 +83,7 @@ class MethodChannelMobileScanner extends MobileScannerPlatform { @@ -83,7 +83,7 @@ class MethodChannelMobileScanner extends MobileScannerPlatform {
83 throw MobileScannerException( 83 throw MobileScannerException(
84 errorCode: MobileScannerErrorCode.unsupported, 84 errorCode: MobileScannerErrorCode.unsupported,
85 errorDetails: MobileScannerErrorDetails( 85 errorDetails: MobileScannerErrorDetails(
86 - message:MobileScannerErrorCode.unsupported.message, 86 + message: MobileScannerErrorCode.unsupported.message,
87 ), 87 ),
88 ); 88 );
89 } 89 }
@@ -202,7 +202,6 @@ class _MobileScannerState extends State<MobileScanner> @@ -202,7 +202,6 @@ class _MobileScannerState extends State<MobileScanner>
202 return ValueListenableBuilder<MobileScannerState>( 202 return ValueListenableBuilder<MobileScannerState>(
203 valueListenable: controller, 203 valueListenable: controller,
204 builder: (BuildContext context, MobileScannerState value, Widget? child) { 204 builder: (BuildContext context, MobileScannerState value, Widget? child) {
205 - // If the controller is still initializing, show a black screen, or user provided placeholder  
206 if (!value.isInitialized) { 205 if (!value.isInitialized) {
207 const Widget defaultPlaceholder = ColoredBox(color: Colors.black); 206 const Widget defaultPlaceholder = ColoredBox(color: Colors.black);
208 207
@@ -211,7 +210,6 @@ class _MobileScannerState extends State<MobileScanner> @@ -211,7 +210,6 @@ class _MobileScannerState extends State<MobileScanner>
211 } 210 }
212 211
213 final MobileScannerException? error = value.error; 212 final MobileScannerException? error = value.error;
214 - // If the controller encountered, show an error screen, or user provided placeholder  
215 if (error != null) { 213 if (error != null) {
216 final Widget defaultError = ScannerErrorWidget(error: error); 214 final Widget defaultError = ScannerErrorWidget(error: error);
217 215
@@ -260,7 +258,7 @@ class _MobileScannerState extends State<MobileScanner> @@ -260,7 +258,7 @@ class _MobileScannerState extends State<MobileScanner>
260 258
261 StreamSubscription? _subscription; 259 StreamSubscription? _subscription;
262 260
263 - Future<void> initController() async { 261 + Future<void> initMobileScanner() async {
264 // If debug mode is enabled, stop the controller first before starting it. 262 // If debug mode is enabled, stop the controller first before starting it.
265 // If a hot-restart is initiated, the controller won't be stopped, and because 263 // If a hot-restart is initiated, the controller won't be stopped, and because
266 // there is no way of knowing if a hot-restart has happened, we must assume 264 // there is no way of knowing if a hot-restart has happened, we must assume
@@ -290,7 +288,10 @@ class _MobileScannerState extends State<MobileScanner> @@ -290,7 +288,10 @@ class _MobileScannerState extends State<MobileScanner>
290 } 288 }
291 } 289 }
292 290
293 - Future<void> disposeCamera() async { 291 + Future<void> disposeMobileScanner() async {
  292 + await _subscription?.cancel();
  293 + WidgetsBinding.instance.removeObserver(this);
  294 +
294 if (controller.autoStart) { 295 if (controller.autoStart) {
295 await controller.stop(); 296 await controller.stop();
296 } 297 }
@@ -298,7 +299,6 @@ class _MobileScannerState extends State<MobileScanner> @@ -298,7 +299,6 @@ class _MobileScannerState extends State<MobileScanner>
298 // Dispose default controller if not provided by user 299 // Dispose default controller if not provided by user
299 if (widget.controller == null) { 300 if (widget.controller == null) {
300 await controller.dispose(); 301 await controller.dispose();
301 - WidgetsBinding.instance.removeObserver(this);  
302 } 302 }
303 } 303 }
304 304
@@ -306,19 +306,13 @@ class _MobileScannerState extends State<MobileScanner> @@ -306,19 +306,13 @@ class _MobileScannerState extends State<MobileScanner>
306 void initState() { 306 void initState() {
307 super.initState(); 307 super.initState();
308 controller = widget.controller ?? MobileScannerController(); 308 controller = widget.controller ?? MobileScannerController();
309 - initController(); 309 + unawaited(initMobileScanner());
310 } 310 }
311 311
312 @override 312 @override
313 void dispose() { 313 void dispose() {
314 - if (_subscription != null) {  
315 - _subscription!.cancel();  
316 - _subscription = null;  
317 - }  
318 -  
319 - disposeCamera();  
320 -  
321 super.dispose(); 314 super.dispose();
  315 + disposeMobileScanner();
322 } 316 }
323 317
324 @override 318 @override
@@ -342,7 +336,6 @@ class _MobileScannerState extends State<MobileScanner> @@ -342,7 +336,6 @@ class _MobileScannerState extends State<MobileScanner>
342 unawaited(controller.start()); 336 unawaited(controller.start());
343 case AppLifecycleState.inactive: 337 case AppLifecycleState.inactive:
344 unawaited(_subscription?.cancel()); 338 unawaited(_subscription?.cancel());
345 - _subscription = null;  
346 unawaited(controller.stop()); 339 unawaited(controller.stop());
347 } 340 }
348 } 341 }
@@ -176,8 +176,7 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> { @@ -176,8 +176,7 @@ class MobileScannerController extends ValueNotifier<MobileScannerState> {
176 throw MobileScannerException( 176 throw MobileScannerException(
177 errorCode: MobileScannerErrorCode.controllerDisposed, 177 errorCode: MobileScannerErrorCode.controllerDisposed,
178 errorDetails: MobileScannerErrorDetails( 178 errorDetails: MobileScannerErrorDetails(
179 - message:  
180 - MobileScannerErrorCode.controllerDisposed.message, 179 + message: MobileScannerErrorCode.controllerDisposed.message,
181 ), 180 ),
182 ); 181 );
183 } 182 }
@@ -20,18 +20,20 @@ class ScannerErrorWidget extends StatelessWidget { @@ -20,18 +20,20 @@ class ScannerErrorWidget extends StatelessWidget {
20 child: Icon(Icons.error, color: Colors.white), 20 child: Icon(Icons.error, color: Colors.white),
21 ), 21 ),
22 if (kDebugMode) ...[ 22 if (kDebugMode) ...[
23 - Text(  
24 - error.errorCode.message,  
25 - style: const TextStyle(color: Colors.white),  
26 - ),  
27 - if (error.errorDetails != null) Text(  
28 - error.errorDetails!.message ?? '',  
29 - style: const TextStyle(color: Colors.white),  
30 - ),  
31 - ] else Text(  
32 - MobileScannerErrorCode.genericError.message,  
33 - style: const TextStyle(color: Colors.white),  
34 - ), 23 + Text(
  24 + error.errorCode.message,
  25 + style: const TextStyle(color: Colors.white),
  26 + ),
  27 + if (error.errorDetails?.message case final String message)
  28 + Text(
  29 + message,
  30 + style: const TextStyle(color: Colors.white),
  31 + ),
  32 + ] else
  33 + Text(
  34 + MobileScannerErrorCode.genericError.message,
  35 + style: const TextStyle(color: Colors.white),
  36 + ),
35 ], 37 ],
36 ), 38 ),
37 ), 39 ),