yubioath-flutter/lib/android/qr_scanner/qr_scanner_view.dart

185 lines
5.5 KiB
Dart
Raw Normal View History

2022-10-04 13:12:54 +03:00
/*
* Copyright (C) 2022-2023 Yubico.
2022-10-04 13:12:54 +03:00
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
2022-03-28 11:58:09 +03:00
import 'package:flutter/material.dart';
2023-02-28 13:34:29 +03:00
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
2022-04-22 16:28:08 +03:00
import 'package:qrscanner_zxing/qrscanner_zxing_view.dart';
2022-03-28 11:58:09 +03:00
2022-03-29 17:01:27 +03:00
import '../../oath/models.dart';
import '../app_methods.dart';
2022-08-05 11:40:36 +03:00
import 'qr_scanner_overlay_view.dart';
2022-08-05 15:04:04 +03:00
import 'qr_scanner_permissions_view.dart';
2022-08-05 11:40:36 +03:00
import 'qr_scanner_scan_status.dart';
import 'qr_scanner_ui_view.dart';
2022-03-28 11:58:09 +03:00
2022-08-05 11:40:36 +03:00
/// Shows Camera preview, overlay and UI
/// Handles user interactions
2022-03-29 17:01:27 +03:00
class QrScannerView extends StatefulWidget {
2022-05-12 10:56:55 +03:00
const QrScannerView({super.key});
2022-03-28 11:58:09 +03:00
2022-03-29 17:01:27 +03:00
@override
2022-05-12 09:34:51 +03:00
State<QrScannerView> createState() => _QrScannerViewState();
2022-03-29 17:01:27 +03:00
}
2022-08-05 15:04:04 +03:00
GlobalKey<QRScannerZxingViewState> _zxingViewKey = GlobalKey();
2022-03-29 17:01:27 +03:00
class _QrScannerViewState extends State<QrScannerView> {
String? _scannedString;
2022-03-31 17:31:03 +03:00
2022-08-05 11:40:36 +03:00
ScanStatus _status = ScanStatus.scanning;
2022-08-05 15:04:04 +03:00
bool _previewInitialized = false;
bool _permissionsGranted = false;
2022-03-31 17:31:03 +03:00
void setError() {
_scannedString = null;
2022-08-05 11:40:36 +03:00
_status = ScanStatus.error;
2022-03-31 17:31:03 +03:00
Future.delayed(const Duration(milliseconds: 2000), () {
2022-09-15 18:57:59 +03:00
if (mounted) {
resetError();
}
2022-03-31 17:31:03 +03:00
});
}
void resetError() {
setState(() {
_scannedString = null;
2022-08-05 11:40:36 +03:00
_status = ScanStatus.scanning;
2022-09-15 18:46:22 +03:00
_zxingViewKey.currentState?.resumeScanning();
2022-03-31 17:31:03 +03:00
});
}
2023-08-01 12:56:57 +03:00
void handleResult(String qrCodeData) {
2022-08-05 11:40:36 +03:00
if (_status != ScanStatus.scanning) {
2022-03-31 17:31:03 +03:00
// on success and error ignore reported codes
return;
}
2022-03-29 17:01:27 +03:00
setState(() {
2023-08-01 12:56:57 +03:00
if (qrCodeData.isNotEmpty) {
2022-03-29 17:01:27 +03:00
try {
2023-08-18 11:44:24 +03:00
CredentialData.fromUri(Uri.parse(
qrCodeData)); // throws ArgumentError if validation fails
2023-08-01 12:56:57 +03:00
_scannedString = qrCodeData;
2022-08-05 11:40:36 +03:00
_status = ScanStatus.success;
2022-03-31 17:31:03 +03:00
final navigator = Navigator.of(context);
2022-03-31 17:31:03 +03:00
Future.delayed(const Duration(milliseconds: 800), () {
if (navigator.canPop()) {
2022-03-31 17:31:03 +03:00
// prevent several callbacks
navigator.pop(_scannedString);
2022-03-31 17:31:03 +03:00
}
});
2022-03-29 17:01:27 +03:00
} on ArgumentError catch (_) {
2022-03-31 17:31:03 +03:00
setError();
} catch (e) {
setError();
2022-03-29 17:01:27 +03:00
}
} else {
2022-03-31 17:31:03 +03:00
setError();
2022-03-29 17:01:27 +03:00
}
});
}
2022-08-05 11:40:36 +03:00
@override
void initState() {
super.initState();
_status = ScanStatus.scanning;
}
2022-03-28 11:58:09 +03:00
@override
Widget build(BuildContext context) {
2023-02-28 13:34:29 +03:00
final l10n = AppLocalizations.of(context)!;
2022-08-05 15:04:04 +03:00
final screenSize = MediaQuery.of(context).size;
final overlayWidgetKey = GlobalKey();
return Scaffold(
2022-08-05 11:40:36 +03:00
resizeToAvoidBottomInset: false,
extendBodyBehindAppBar: true,
extendBody: true,
appBar: AppBar(
2023-02-28 13:34:29 +03:00
title: Text(
l10n.s_add_account,
2023-02-28 13:34:29 +03:00
style: const TextStyle(color: Colors.white),
2022-08-05 11:40:36 +03:00
),
backgroundColor: Colors.transparent,
foregroundColor: Colors.white,
elevation: 0,
leading: BackButton(
onPressed: () {
Navigator.of(context).pop();
},
),
),
body: Stack(
children: [
2022-08-05 15:04:04 +03:00
Container(
color: Colors.black,
child: const Column(
2022-08-05 15:04:04 +03:00
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [Spacer()])),
2022-08-05 15:04:04 +03:00
Visibility(
maintainState: true,
maintainInteractivity: true,
maintainAnimation: true,
maintainSize: true,
visible: _permissionsGranted,
child: QRScannerZxingView(
2023-10-27 11:10:23 +03:00
key: _zxingViewKey,
marginPct: 10,
onDetect: (scannedData) => handleResult(scannedData),
onViewInitialized: (bool permissionsGranted) {
Future.delayed(const Duration(milliseconds: 50), () {
setState(() {
_previewInitialized = true;
_permissionsGranted = permissionsGranted;
2022-08-05 15:04:04 +03:00
});
2023-10-27 11:10:23 +03:00
});
},
beforePermissionsRequest: () async {
await preserveConnectedDeviceWhenPaused();
},
)),
2022-08-05 15:04:04 +03:00
Visibility(
visible: _permissionsGranted,
child: QRScannerOverlay(
status: _status,
screenSize: screenSize,
overlayWidgetKey: overlayWidgetKey,
2022-08-05 15:04:04 +03:00
)),
Visibility(
visible: _permissionsGranted,
child: QRScannerUI(
status: _status,
screenSize: screenSize,
overlayWidgetKey: overlayWidgetKey,
2022-08-05 15:04:04 +03:00
)),
Visibility(
visible: _previewInitialized && !_permissionsGranted,
child: QRScannerPermissionsUI(
status: _status,
screenSize: screenSize,
onPermissionRequest: () {
_zxingViewKey.currentState?.requestPermissions();
},
)),
2022-08-05 11:40:36 +03:00
],
),
);
2022-03-28 11:58:09 +03:00
}
}