diff --git a/packages/at_onboarding_flutter/lib/at_onboarding.dart b/packages/at_onboarding_flutter/lib/at_onboarding.dart new file mode 100644 index 00000000..6dd052c7 --- /dev/null +++ b/packages/at_onboarding_flutter/lib/at_onboarding.dart @@ -0,0 +1,5 @@ +library at_onboarding_legacy; + +@Deprecated( + "This is a legacy export and will be removed in a future version: use at_onboarding_flutter.dart instead") +export 'src/at_onboarding.dart'; diff --git a/packages/at_onboarding_flutter/lib/at_onboarding_result.dart b/packages/at_onboarding_flutter/lib/at_onboarding_result.dart new file mode 100644 index 00000000..75438940 --- /dev/null +++ b/packages/at_onboarding_flutter/lib/at_onboarding_result.dart @@ -0,0 +1,5 @@ +library at_onboarding_result_legacy; + +@Deprecated( + "This is a legacy export and will be removed in a future version: use at_onboarding_flutter.dart instead") +export 'src/at_onboarding_result.dart'; diff --git a/packages/at_onboarding_flutter/lib/at_onboarding_screens.dart b/packages/at_onboarding_flutter/lib/at_onboarding_screens.dart new file mode 100644 index 00000000..8664fc75 --- /dev/null +++ b/packages/at_onboarding_flutter/lib/at_onboarding_screens.dart @@ -0,0 +1,16 @@ +library at_onboarding_screens; + +export "src/screen/at_onboarding_accounts_screen.dart"; +export "src/screen/at_onboarding_activate_screen.dart"; +export "src/screen/at_onboarding_backup_screen.dart"; +export "src/screen/at_onboarding_generate_screen.dart"; +export "src/screen/at_onboarding_home_screen.dart"; +export "src/screen/at_onboarding_input_atsign_screen.dart"; +export "src/screen/at_onboarding_intro_screen.dart"; +export "src/screen/at_onboarding_otp_screen.dart"; +export "src/screen/at_onboarding_pair_screen.dart"; +export "src/screen/at_onboarding_qrcode_screen.dart"; +export "src/screen/at_onboarding_reference_screen.dart"; +export "src/screen/at_onboarding_reset_screen.dart"; +export "src/screen/at_onboarding_start_screen.dart"; +export "src/screen/at_onboarding_webview_screen.dart"; diff --git a/packages/at_onboarding_flutter/lib/at_onboarding_services.dart b/packages/at_onboarding_flutter/lib/at_onboarding_services.dart new file mode 100644 index 00000000..642146d2 --- /dev/null +++ b/packages/at_onboarding_flutter/lib/at_onboarding_services.dart @@ -0,0 +1,11 @@ +library at_onboarding_services; + +export 'src/services/at_keys_file_upload_service.dart'; +export 'src/services/at_onboarding_backup_service.dart'; +export 'src/services/at_onboarding_config.dart'; +export 'src/services/at_onboarding_theme.dart'; +export 'src/services/at_onboarding_tutorial_service.dart'; +export 'src/services/backend_service.dart'; +export 'src/services/free_atsign_service.dart'; +export 'src/services/onboarding_service.dart'; +export 'src/services/sdk_service.dart'; diff --git a/packages/at_onboarding_flutter/lib/at_onboarding_widgets.dart b/packages/at_onboarding_flutter/lib/at_onboarding_widgets.dart new file mode 100644 index 00000000..67e50bf7 --- /dev/null +++ b/packages/at_onboarding_flutter/lib/at_onboarding_widgets.dart @@ -0,0 +1,4 @@ +library at_onboarding_widgets; + +export 'src/widgets/at_onboarding_button.dart'; +export 'src/widgets/at_onboarding_dialog.dart'; diff --git a/packages/at_onboarding_flutter/lib/src/screen/at_onboarding_home_screen.dart b/packages/at_onboarding_flutter/lib/src/screen/at_onboarding_home_screen.dart index 0a5dc29a..41a6caac 100644 --- a/packages/at_onboarding_flutter/lib/src/screen/at_onboarding_home_screen.dart +++ b/packages/at_onboarding_flutter/lib/src/screen/at_onboarding_home_screen.dart @@ -1,8 +1,5 @@ -import 'dart:convert'; import 'dart:io'; -import 'dart:typed_data'; -import 'package:archive/archive.dart'; import 'package:at_client_mobile/at_client_mobile.dart'; import 'package:at_onboarding_flutter/src/at_onboarding_result.dart'; import 'package:at_onboarding_flutter/localizations/generated/l10n.dart'; @@ -13,8 +10,8 @@ import 'package:at_onboarding_flutter/src/screen/at_onboarding_input_atsign_scre import 'package:at_onboarding_flutter/src/screen/at_onboarding_reference_screen.dart'; import 'package:at_onboarding_flutter/src/services/at_onboarding_config.dart'; import 'package:at_onboarding_flutter/src/services/at_onboarding_tutorial_service.dart'; +import 'package:at_onboarding_flutter/src/services/at_keys_file_upload_service.dart'; import 'package:at_onboarding_flutter/src/services/onboarding_service.dart'; -import 'package:at_onboarding_flutter/src/utils/at_onboarding_app_constants.dart'; import 'package:at_onboarding_flutter/src/utils/at_onboarding_dimens.dart'; import 'package:at_onboarding_flutter/src/utils/at_onboarding_error_util.dart'; import 'package:at_onboarding_flutter/src/utils/at_onboarding_response_status.dart'; @@ -24,10 +21,8 @@ import 'package:at_onboarding_flutter/src/widgets/at_onboarding_dialog.dart'; import 'package:at_server_status/at_server_status.dart'; import 'package:at_sync_ui_flutter/at_sync_material.dart'; import 'package:at_utils/at_logger.dart'; -import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:image/image.dart' as img; -import 'package:path_provider/path_provider.dart' as path_provider; import 'package:permission_handler/permission_handler.dart'; import 'package:tutorial_coach_mark/tutorial_coach_mark.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -55,13 +50,13 @@ class AtOnboardingHomeScreen extends StatefulWidget { final bool isFromIntroScreen; const AtOnboardingHomeScreen({ - Key? key, + super.key, required this.config, this.getAtSign = false, this.hideReferences = false, this.hideQrScan = false, this.isFromIntroScreen = false, - }) : super(key: key); + }); @override State createState() => _AtOnboardingHomeScreenState(); @@ -78,7 +73,6 @@ class _AtOnboardingHomeScreenState extends State { bool loading = false; bool permissionGrated = false; - bool _isContinue = true; String? _pairingAtsign; ServerStatus? atSignStatus; @@ -98,6 +92,8 @@ class _AtOnboardingHomeScreenState extends State { GlobalKey keyActivateAtSign = GlobalKey(); GlobalKey keyCreateAnAtSign = GlobalKey(); + late AtKeysFileUploadService filePicker; + Future askPermissions(Permission type) async { if (type == Permission.camera) { await Permission.camera.request(); @@ -168,11 +164,7 @@ class _AtOnboardingHomeScreenState extends State { key: keyUploadAtSign, height: 48, borderRadius: 24, - onPressed: (Platform.isMacOS || - Platform.isLinux || - Platform.isWindows) - ? _uploadKeyFileForDesktop - : _uploadKeyFile, + onPressed: _uploadKeyFile, isLoading: loading, child: Row( mainAxisAlignment: MainAxisAlignment.center, @@ -312,6 +304,7 @@ class _AtOnboardingHomeScreenState extends State { @override void initState() { _inprogressDialog = AtSyncDialog(context: context); + filePicker = AtKeysFileUploadService(config: widget.config); checkPermissions(); super.initState(); _init(); @@ -465,19 +458,6 @@ class _AtOnboardingHomeScreenState extends State { } } - Future _desktopKeyPicker() async { - try { - FilePickerResult? result = await FilePicker.platform.pickFiles( - type: FileType.custom, - allowedExtensions: ['atKeys', 'atkeys'], - ); - return result?.files.single.path; - } catch (e) { - _logger.severe('Error with desktop atKeys file picker: $e'); - return null; - } - } - void _endTutorial() async { var tutorialInfo = await AtOnboardingTutorialService.getTutorialInfo(); tutorialInfo ??= AtTutorialServiceInfo(); @@ -491,70 +471,6 @@ class _AtOnboardingHomeScreenState extends State { await _checkShowTutorial(); } - Future _processAESKey( - String? atsign, String? aesKey, String contents) async { - dynamic authResponse; - assert(aesKey != null || aesKey != ''); - assert(atsign != null || atsign != ''); - assert(contents != ''); - _inprogressDialog.show( - message: AtOnboardingLocalizations.current.processing, - ); - await Future.delayed(const Duration(milliseconds: 400)); - try { - bool isExist = await _onboardingService.isExistingAtsign(atsign); - if (isExist) { - _inprogressDialog.close(); - await showErrorDialog(AtOnboardingErrorToString().pairedAtsign(atsign)); - return; - } - - _onboardingService.setAtClientPreference = - widget.config.atClientPreference; - - authResponse = await _onboardingService.authenticate( - atsign, - jsonData: contents, - decryptKey: aesKey, - ); - _inprogressDialog.close(); - if (authResponse == AtOnboardingResponseStatus.authSuccess) { - //Don't show backup key for case user upload backup key - // await AtOnboardingBackupScreen.push(context: context); - if (!mounted) return; - Navigator.pop(context, AtOnboardingResult.success(atsign: atsign!)); - } else if (authResponse == AtOnboardingResponseStatus.serverNotReached) { - await _showAlertDialog( - AtOnboardingLocalizations.current.msg_atSign_unreachable, - ); - } else if (authResponse == AtOnboardingResponseStatus.authFailed) { - await _showAlertDialog( - AtOnboardingLocalizations.current.error_authenticated_failed, - ); - } else { - await showErrorDialog( - AtOnboardingLocalizations.current.msg_response_time_out, - ); - } - } catch (e) { - _inprogressDialog.close(); - if (e == AtOnboardingResponseStatus.serverNotReached && _isContinue) { - await _processAESKey(atsign, aesKey, contents); - } else if (e == AtOnboardingResponseStatus.authFailed) { - _logger.severe('Error in authenticateWithAESKey'); - await showErrorDialog( - AtOnboardingLocalizations.current.msg_auth_failed, - ); - } else if (e == AtOnboardingResponseStatus.timeOut) { - await showErrorDialog( - AtOnboardingLocalizations.current.msg_response_time_out, - ); - } else { - _logger.warning(e); - } - } - } - Future _processSharedSecret(String atsign, String secret) async { dynamic authResponse; try { @@ -732,195 +648,81 @@ class _AtOnboardingHomeScreenState extends State { )..show(context: context); } - Future _uploadKeyFile() async { - try { - if (!permissionGrated) { - await checkPermissions(); - } - _isContinue = true; - String? fileContents, aesKey, atsign; - FilePickerResult? result = - await FilePicker.platform.pickFiles(type: FileType.any); - if ((result?.files ?? []).isEmpty) { - //User cancelled => do nothing - return; - } - setState(() { - loading = true; - }); - for (PlatformFile pickedFile in result?.files ?? []) { - String? path = pickedFile.path; - if (path == null) { - throw const FileSystemException( - 'FilePicker.pickFiles returned a null path', - ); - } - File selectedFile = File(path); - int length = selectedFile.lengthSync(); - if (length < 10) { - await showErrorDialog(_incorrectKeyFile); - return; - } - - if (pickedFile.extension == 'zip') { - Uint8List bytes = selectedFile.readAsBytesSync(); - Archive archive = ZipDecoder().decodeBytes(bytes); - for (ArchiveFile file in archive) { - if (file.name.contains('atKeys')) { - fileContents = String.fromCharCodes(file.content); - } else if (aesKey == null && - atsign == null && - file.name.contains('_private_key.png')) { - List bytes = file.content as List; - String path = (await path_provider.getTemporaryDirectory()).path; - File file1 = await File('${path}test').create(); - file1.writeAsBytesSync(bytes); - String result = decodeQrCode(file1.path); - List params = result.replaceAll('"', '').split(':'); - atsign = params[0]; - aesKey = params[1]; - await File('${path}test').delete(); - //read scan QRcode and extract atsign,aeskey - } - } - } else if (pickedFile.name.contains('atKeys')) { - fileContents = File(path.toString()).readAsStringSync(); - } else if (aesKey == null && - atsign == null && - pickedFile.name.contains('_private_key.png')) { - //read scan QRcode and extract atsign,aeskey - var result = decodeQrCode(path); - - List params = result.split(':'); - atsign = params[0]; - aesKey = params[1]; - } else { - Uint8List result1 = selectedFile.readAsBytesSync(); - fileContents = String.fromCharCodes(result1); - bool result = _validatePickedFileContents(fileContents); - _logger.finer('result after extracting data is......$result'); - if (!result) { - await showErrorDialog(_incorrectKeyFile); - setState(() { - loading = false; - }); - return; - } - } - } - if (aesKey == null && atsign == null && fileContents != null) { - List keyData = fileContents.split(',"@'); - List params = keyData[1] - .toString() - .substring(0, keyData[1].length - 2) - .split('":"'); - atsign = "@${params[0]}"; - Map keyMap = jsonDecode(fileContents); - aesKey = keyMap[AtOnboardingConstants.atSelfEncryptionKey]; - } - if (fileContents == null || (aesKey == null && atsign == null)) { - await showErrorDialog(_incorrectKeyFile); - setState(() { - loading = false; - }); - return; - } else if (OnboardingService.getInstance().formatAtSign(atsign) != - _pairingAtsign && - _pairingAtsign != null) { - await showErrorDialog( - AtOnboardingErrorToString().atsignMismatch(_pairingAtsign)); - setState(() { - loading = false; - }); - return; - } + void setLoading(bool loading) { + if (this.loading != loading) { setState(() { - loading = false; + this.loading = loading; }); - await _processAESKey(atsign, aesKey, fileContents); - } catch (error) { - setState(() { - loading = false; - }); - _logger.severe('Uploading backup zip file throws $error'); - await showErrorDialog(_failedFileProcessing); } } - Future _uploadKeyFileForDesktop() async { - try { - _isContinue = true; - String? fileContents, aesKey, atsign; - setState(() { - loading = true; - }); - - String? path = await _desktopKeyPicker(); - if (path == null) { - setState(() { - loading = false; - }); - return; - } - - File selectedFile = File(path); - int length = selectedFile.lengthSync(); - if (length < 10) { - await showErrorDialog(_incorrectKeyFile); - return; - } - - fileContents = File(path).readAsStringSync(); - // ignore: unnecessary_null_comparison - if (aesKey == null && atsign == null && fileContents.isNotEmpty) { - List keyData = fileContents.split(',"@'); - List params = keyData[1] - .toString() - .substring(0, keyData[1].length - 2) - .split('":"'); - atsign = "@${params[0]}"; - Map keyMap = jsonDecode(fileContents); - aesKey = keyMap[AtOnboardingConstants.atSelfEncryptionKey]; - } - if (fileContents.isEmpty || (aesKey == null && atsign == null)) { - await showErrorDialog(_incorrectKeyFile); - setState(() { - loading = false; - }); - return; - } else if (OnboardingService.getInstance().formatAtSign(atsign) != - _pairingAtsign && - _pairingAtsign != null) { - await showErrorDialog( - AtOnboardingErrorToString().atsignMismatch(_pairingAtsign)); - setState(() { - loading = false; - }); - return; + Future _uploadKeyFile() async { + await checkPermissions(); + Stream statusStream = + filePicker.uploadKeyFile(_pairingAtsign); + statusStream.listen((status) async { + switch (status) { + case FilePickingInProgress(): + setLoading(true); + break; + case FilePickingDone(): + setLoading(false); + break; + case FilePickingCanceled(): + setLoading(false); + break; + case ErrorIncorrectKeyFile(): + await showErrorDialog(_incorrectKeyFile); + break; + case ErrorAtSignMismatch(): + await showErrorDialog( + AtOnboardingErrorToString().atsignMismatch(_pairingAtsign)); + break; + case ErrorFailedFileProcessing(): + await showErrorDialog(_failedFileProcessing); + break; + case ProcessingAesKeyInProgress(): + _inprogressDialog.show( + message: AtOnboardingLocalizations.current.processing, + ); + break; + // Non constant status, so use _ for pattern match + case ErrorPairedAtsign _: + _inprogressDialog.close(); + await showErrorDialog( + AtOnboardingErrorToString().pairedAtsign(status.atSign)); + break; + case ProcessingAesKeyDone(): + _inprogressDialog.close(); + break; + case ErrorAtServerUnreachable(): + await _showAlertDialog( + AtOnboardingLocalizations.current.msg_atSign_unreachable, + ); + break; + case ErrorAuthFailed(): + await _showAlertDialog( + AtOnboardingLocalizations.current.error_authenticated_failed, + ); + break; + case ErrorAuthTimeout(): + await showErrorDialog( + AtOnboardingLocalizations.current.msg_response_time_out, + ); + break; + // Non constant status, so use _ for pattern match + case FileUploadAuthSuccess _: + //Don't show backup key for case user upload backup key + // await AtOnboardingBackupScreen.push(context: context); + if (!mounted) return; + Navigator.pop( + context, AtOnboardingResult.success(atsign: status.atSign!)); } + }, onDone: () { setState(() { - loading = false; - }); - await _processAESKey(atsign, aesKey, fileContents); - } catch (error) { - setState(() { - loading = false; + // Just in case + setLoading(false); }); - _logger.severe('Uploading backup zip file throws $error'); - await showErrorDialog(_failedFileProcessing); - } - } - - bool _validatePickedFileContents(String fileContents) { - bool result = fileContents - .contains(BackupKeyConstants.PKAM_PRIVATE_KEY_FROM_KEY_FILE) && - fileContents - .contains(BackupKeyConstants.PKAM_PUBLIC_KEY_FROM_KEY_FILE) && - fileContents - .contains(BackupKeyConstants.ENCRYPTION_PRIVATE_KEY_FROM_FILE) && - fileContents - .contains(BackupKeyConstants.ENCRYPTION_PUBLIC_KEY_FROM_FILE) && - fileContents.contains(BackupKeyConstants.SELF_ENCRYPTION_KEY_FROM_FILE); - return result; + }); } } diff --git a/packages/at_onboarding_flutter/lib/src/services/at_keys_file_upload_service.dart b/packages/at_onboarding_flutter/lib/src/services/at_keys_file_upload_service.dart new file mode 100644 index 00000000..1311c0d8 --- /dev/null +++ b/packages/at_onboarding_flutter/lib/src/services/at_keys_file_upload_service.dart @@ -0,0 +1,216 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; + +import 'package:at_onboarding_flutter/at_onboarding_flutter.dart'; +import 'package:at_onboarding_flutter/at_onboarding_services.dart'; +import 'package:at_onboarding_flutter/src/utils/at_onboarding_app_constants.dart'; +import 'package:at_onboarding_flutter/src/utils/at_onboarding_response_status.dart'; +import 'package:at_utils/at_logger.dart'; +import 'package:file_picker/file_picker.dart'; + +class AtKeysFileUploadService { + final AtSignLogger _logger = AtSignLogger('At Onboarding'); + final OnboardingService _onboardingService = OnboardingService.getInstance(); + final AtOnboardingConfig _config; + AtKeysFileUploadService({required AtOnboardingConfig config}) + : _config = config; + + Future pickFile() async { + try { + FilePickerResult? result = await FilePicker.platform.pickFiles( + type: FileType.custom, + allowedExtensions: ['atKeys', 'atkeys'], + ); + return result?.files.single.path; + } catch (e) { + _logger.severe('Error with desktop atKeys file picker: $e'); + return null; + } + } + + Stream uploadKeyFile(String? pairingAtsign) { + final StreamController streamController = + StreamController(); + _uploadKeyFileForDesktop(streamController, pairingAtsign); + return streamController.stream; + } + + Future _uploadKeyFileForDesktop( + StreamController streamController, + String? pairingAtsign) async { + try { + String? fileContents, aesKey, atsign; + streamController.add(const FilePickingInProgress()); + + String? path = await pickFile(); + if (path == null) { + streamController.add(const FilePickingCanceled()); + return; + } + + File selectedFile = File(path); + int length = selectedFile.lengthSync(); + if (length < 10) { + streamController.add(const ErrorIncorrectKeyFile()); + return; + } + + fileContents = File(path).readAsStringSync(); + if (!_validatePickedFileContents(fileContents)) { + streamController.add(const ErrorIncorrectKeyFile()); + return; + } + if (fileContents.isNotEmpty) { + List keyData = fileContents.split(',"@'); + List params = keyData[1] + .toString() + .substring(0, keyData[1].length - 2) + .split('":"'); + atsign = "@${params[0]}"; + Map keyMap = jsonDecode(fileContents); + aesKey = keyMap[AtOnboardingConstants.atSelfEncryptionKey]; + } + if (fileContents.isEmpty || (aesKey == null && atsign == null)) { + streamController.add(const ErrorIncorrectKeyFile()); + return; + } else if (OnboardingService.getInstance().formatAtSign(atsign) != + pairingAtsign && + pairingAtsign != null) { + streamController.add(const ErrorAtSignMismatch()); + return; + } + + streamController.add(const FilePickingDone()); + await _processAESKey(atsign, aesKey, fileContents, streamController); + } catch (error) { + _logger.severe('Uploading backup zip file throws $error'); + streamController.add(const ErrorFailedFileProcessing()); + } + } + + Future _processAESKey(String? atsign, String? aesKey, String contents, + StreamController? controller, + {bool retry = true}) async { + dynamic authResponse; + assert(aesKey != null || aesKey != ''); + assert(atsign != null || atsign != ''); + assert(contents != ''); + controller?.add(const ProcessingAesKeyInProgress()); + await Future.delayed(const Duration(milliseconds: 400)); + try { + bool isExist = await _onboardingService.isExistingAtsign(atsign); + if (isExist) { + controller?.add(const ProcessingAesKeyDone()); + controller?.add(ErrorPairedAtsign(atsign)); + return; + } + + _onboardingService.setAtClientPreference = _config.atClientPreference; + + authResponse = await _onboardingService.authenticate( + atsign, + jsonData: contents, + decryptKey: aesKey, + ); + controller?.add(const ProcessingAesKeyDone()); + if (authResponse == AtOnboardingResponseStatus.authSuccess) { + controller?.add(FileUploadAuthSuccess(atsign)); + } else if (authResponse == AtOnboardingResponseStatus.serverNotReached) { + controller?.add(const ErrorAtServerUnreachable()); + } else if (authResponse == AtOnboardingResponseStatus.authFailed) { + controller?.add(const ErrorAuthFailed()); + } else {} + } catch (e) { + controller?.add(const ProcessingAesKeyDone()); + if (e == AtOnboardingResponseStatus.serverNotReached && retry) { + await _processAESKey(atsign, aesKey, contents, controller, + retry: false); + } else if (e == AtOnboardingResponseStatus.authFailed) { + _logger.severe('Error in authenticateWithAESKey'); + controller?.add(const ErrorAuthFailed()); + } else if (e == AtOnboardingResponseStatus.timeOut) { + controller?.add(const ErrorAuthTimeout()); + } else { + _logger.warning(e); + } + } + } + + bool _validatePickedFileContents(String fileContents) { + bool result = fileContents + .contains(BackupKeyConstants.PKAM_PRIVATE_KEY_FROM_KEY_FILE) && + fileContents + .contains(BackupKeyConstants.PKAM_PUBLIC_KEY_FROM_KEY_FILE) && + fileContents + .contains(BackupKeyConstants.ENCRYPTION_PRIVATE_KEY_FROM_FILE) && + fileContents + .contains(BackupKeyConstants.ENCRYPTION_PUBLIC_KEY_FROM_FILE) && + fileContents.contains(BackupKeyConstants.SELF_ENCRYPTION_KEY_FROM_FILE); + return result; + } +} + +sealed class FileUploadStatus { + const FileUploadStatus(); +} + +// Errors + +class ErrorIncorrectKeyFile extends FileUploadStatus { + const ErrorIncorrectKeyFile(); +} + +class ErrorAtSignMismatch extends FileUploadStatus { + const ErrorAtSignMismatch(); +} + +class ErrorFailedFileProcessing extends FileUploadStatus { + const ErrorFailedFileProcessing(); +} + +class ErrorAtServerUnreachable extends FileUploadStatus { + const ErrorAtServerUnreachable(); +} + +class ErrorAuthFailed extends FileUploadStatus { + const ErrorAuthFailed(); +} + +class ErrorAuthTimeout extends FileUploadStatus { + const ErrorAuthTimeout(); +} + +class ErrorPairedAtsign extends FileUploadStatus { + final String? atSign; + ErrorPairedAtsign(this.atSign); +} + +// File Picking + +class FilePickingInProgress extends FileUploadStatus { + const FilePickingInProgress(); +} + +class FilePickingDone extends FileUploadStatus { + const FilePickingDone(); +} + +class FilePickingCanceled extends FileUploadStatus { + const FilePickingCanceled(); +} + +// Processing AesKey + +class ProcessingAesKeyInProgress extends FileUploadStatus { + const ProcessingAesKeyInProgress(); +} + +class ProcessingAesKeyDone extends FileUploadStatus { + const ProcessingAesKeyDone(); +} + +class FileUploadAuthSuccess extends FileUploadStatus { + final String? atSign; + FileUploadAuthSuccess(this.atSign); +} diff --git a/packages/at_onboarding_flutter/pubspec.yaml b/packages/at_onboarding_flutter/pubspec.yaml index 064680e9..d6a94b44 100644 --- a/packages/at_onboarding_flutter/pubspec.yaml +++ b/packages/at_onboarding_flutter/pubspec.yaml @@ -9,7 +9,7 @@ issue_tracker: https://github.com/atsign-foundation/at_widgets/issues documentation: https://docs.atsign.com/ environment: - sdk: ">=2.12.0 <4.0.0" + sdk: ">=3.0.0 <4.0.0" flutter: ">=1.20.0" dependencies: