|
@@ -1,9 +1,11 @@
|
|
|
import 'dart:io';
|
|
|
|
|
|
import 'package:ente_auth/l10n/l10n.dart';
|
|
|
+import 'package:ente_auth/models/code.dart';
|
|
|
import 'package:ente_auth/ui/components/buttons/button_widget.dart';
|
|
|
import 'package:ente_auth/ui/components/dialog_widget.dart';
|
|
|
import 'package:ente_auth/ui/components/models/button_type.dart';
|
|
|
+import 'package:ente_auth/ui/settings/data/import/google_auth_image_import.dart';
|
|
|
import 'package:ente_auth/ui/settings/data/import/qr_scanner_overlay.dart';
|
|
|
import 'package:ente_auth/utils/toast_util.dart';
|
|
|
import 'package:flutter/material.dart';
|
|
@@ -21,6 +23,7 @@ class QrScanner extends StatefulWidget {
|
|
|
|
|
|
class _QrScannerState extends State<QrScanner> {
|
|
|
bool isNavigationPerformed = false;
|
|
|
+ bool isScannedByImage = false;
|
|
|
|
|
|
//Scanner Initialization
|
|
|
MobileScannerController scannerController = MobileScannerController(
|
|
@@ -40,85 +43,40 @@ class _QrScannerState extends State<QrScanner> {
|
|
|
children: [
|
|
|
MobileScanner(
|
|
|
controller: scannerController,
|
|
|
- onDetect: (capture) {
|
|
|
+ onDetect: (capture) async {
|
|
|
if (!isNavigationPerformed) {
|
|
|
isNavigationPerformed = true;
|
|
|
- HapticFeedback.vibrate();
|
|
|
- showDialog(
|
|
|
- barrierDismissible: false,
|
|
|
- context: context,
|
|
|
- builder: (BuildContext context) {
|
|
|
- return AlertDialog(
|
|
|
- backgroundColor: Colors.white,
|
|
|
- buttonPadding: const EdgeInsets.all(0),
|
|
|
- actionsAlignment: MainAxisAlignment.center,
|
|
|
- alignment: Alignment.center,
|
|
|
- insetPadding: const EdgeInsets.symmetric(
|
|
|
- vertical: 24,
|
|
|
- horizontal: 24,
|
|
|
- ),
|
|
|
- shape: RoundedRectangleBorder(
|
|
|
- borderRadius: BorderRadius.circular(12),
|
|
|
- ),
|
|
|
- title: const Text(
|
|
|
- 'Scan result',
|
|
|
- style: TextStyle(
|
|
|
- letterSpacing: 0.5,
|
|
|
- fontWeight: FontWeight.w600,
|
|
|
- fontSize: 18,
|
|
|
- color: Colors.black,
|
|
|
- ),
|
|
|
- textAlign: TextAlign.center,
|
|
|
- ),
|
|
|
- content: Text(
|
|
|
- ' ${capture.barcodes[0].rawValue!}',
|
|
|
- style: const TextStyle(
|
|
|
- letterSpacing: 0.5,
|
|
|
- fontWeight: FontWeight.w600,
|
|
|
- fontSize: 15,
|
|
|
- color: Colors.black,
|
|
|
- ),
|
|
|
- textAlign: TextAlign.center,
|
|
|
- ),
|
|
|
- actions: [
|
|
|
- Column(
|
|
|
- children: [
|
|
|
- GestureDetector(
|
|
|
- onTap: () {
|
|
|
- Navigator.pop(context);
|
|
|
- isNavigationPerformed = false;
|
|
|
- },
|
|
|
- child: Container(
|
|
|
- decoration: BoxDecoration(
|
|
|
- color: Colors.black,
|
|
|
- borderRadius: BorderRadius.circular(24),
|
|
|
- ),
|
|
|
- child: const Padding(
|
|
|
- padding: EdgeInsets.symmetric(
|
|
|
- horizontal: 20,
|
|
|
- vertical: 8,
|
|
|
- ),
|
|
|
- child: Text(
|
|
|
- 'OK',
|
|
|
- style: TextStyle(
|
|
|
- letterSpacing: 0.5,
|
|
|
- fontWeight: FontWeight.w500,
|
|
|
- fontSize: 16,
|
|
|
- color: Colors.white,
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- ),
|
|
|
- const SizedBox(
|
|
|
- height: 30,
|
|
|
- ),
|
|
|
- ],
|
|
|
+ if (capture.barcodes[0].rawValue!
|
|
|
+ .startsWith(kGoogleAuthExportPrefix)) {
|
|
|
+ if (isScannedByImage) {
|
|
|
+ final result = await showDialogWidget(
|
|
|
+ context: context,
|
|
|
+ title: l10n.reminderText,
|
|
|
+ body: l10n.reminderPopupBody,
|
|
|
+ buttons: [
|
|
|
+ ButtonWidget(
|
|
|
+ buttonType: ButtonType.primary,
|
|
|
+ labelText: l10n.ok,
|
|
|
+ isInAlert: true,
|
|
|
+ buttonSize: ButtonSize.large,
|
|
|
+ buttonAction: ButtonAction.first,
|
|
|
),
|
|
|
],
|
|
|
);
|
|
|
- },
|
|
|
- );
|
|
|
+ if (result?.action != null &&
|
|
|
+ result!.action == ButtonAction.first) {
|
|
|
+ isScannedByImage = false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ HapticFeedback.vibrate();
|
|
|
+ List<Code> codes =
|
|
|
+ parseGoogleAuth(capture.barcodes[0].rawValue!);
|
|
|
+ scannerController.dispose();
|
|
|
+ Navigator.of(context).pop(codes);
|
|
|
+ } else {
|
|
|
+ showToast(context, l10n.invalidQrCodeText);
|
|
|
+ isNavigationPerformed = false;
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
),
|
|
@@ -163,13 +121,14 @@ class _QrScannerState extends State<QrScanner> {
|
|
|
onPressed: () async {
|
|
|
final result = await showDialogWidget(
|
|
|
context: context,
|
|
|
- title: l10n.importFromApp("Google Authenticator (saved image)"),
|
|
|
- body:
|
|
|
- 'Please turn off all photo cloud sync from all apps, including iCloud, Google Photo, OneDrive, etc. \nAlso if you have a second smartphone, it is safer to import by scanning QR code.',
|
|
|
+ title: l10n.importFromApp(
|
|
|
+ "Google Authenticator (saved image)",
|
|
|
+ ),
|
|
|
+ body: l10n.googleAuthImagePopupBody,
|
|
|
buttons: [
|
|
|
- const ButtonWidget(
|
|
|
+ ButtonWidget(
|
|
|
buttonType: ButtonType.primary,
|
|
|
- labelText: 'Import from image',
|
|
|
+ labelText: l10n.importGoogleAuthImageButtonText,
|
|
|
isInAlert: true,
|
|
|
buttonSize: ButtonSize.large,
|
|
|
buttonAction: ButtonAction.first,
|
|
@@ -191,6 +150,7 @@ class _QrScannerState extends State<QrScanner> {
|
|
|
context,
|
|
|
pickerConfig: const AssetPickerConfig(
|
|
|
maxAssets: 1,
|
|
|
+ requestType: RequestType.image,
|
|
|
),
|
|
|
);
|
|
|
|
|
@@ -201,14 +161,22 @@ class _QrScannerState extends State<QrScanner> {
|
|
|
|
|
|
if (await scannerController
|
|
|
.analyzeImage(path)) {
|
|
|
+ isScannedByImage = true;
|
|
|
if (!mounted) return;
|
|
|
} else {
|
|
|
if (!mounted) return;
|
|
|
- showToast(context, "Failed to scan image");
|
|
|
+ isScannedByImage = false;
|
|
|
+ showToast(
|
|
|
+ context,
|
|
|
+ l10n.unableToRecognizeQrCodeText,
|
|
|
+ );
|
|
|
}
|
|
|
} else {
|
|
|
if (!mounted) return;
|
|
|
- showToast(context, "Image not selected");
|
|
|
+ showToast(
|
|
|
+ context,
|
|
|
+ l10n.qrCodeImageNotSelectedText,
|
|
|
+ );
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -250,13 +218,10 @@ class _QrScannerState extends State<QrScanner> {
|
|
|
const SizedBox(
|
|
|
height: 25,
|
|
|
),
|
|
|
- const Text(
|
|
|
- 'Scan QR code',
|
|
|
+ Text(
|
|
|
+ l10n.scanACode,
|
|
|
textAlign: TextAlign.center,
|
|
|
- style: TextStyle(
|
|
|
- letterSpacing: 0.5,
|
|
|
- fontWeight: FontWeight.w600,
|
|
|
- fontSize: 14,
|
|
|
+ style: const TextStyle(
|
|
|
color: Colors.black,
|
|
|
),
|
|
|
),
|