From d8cc455ff2c6837d165f54197ae4768de2f14f3b Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:40:38 -0300 Subject: [PATCH 1/5] fix(error handling) - fix missing error handling for loading names and selecting the name --- .../assign_name_bloc/assign_name_bloc.dart | 91 +++++++++--------- .../assign_name_bloc/assign_name_state.dart | 2 + lib/arns/presentation/assign_name_modal.dart | 58 ++++++++++++ .../assign_name_bloc_test.dart | 93 +++++++++++++++++++ 4 files changed, 199 insertions(+), 45 deletions(-) diff --git a/lib/arns/presentation/assign_name_bloc/assign_name_bloc.dart b/lib/arns/presentation/assign_name_bloc/assign_name_bloc.dart index 36acb7f115..6834d39923 100644 --- a/lib/arns/presentation/assign_name_bloc/assign_name_bloc.dart +++ b/lib/arns/presentation/assign_name_bloc/assign_name_bloc.dart @@ -24,22 +24,27 @@ class AssignNameBloc extends Bloc { _arnsRepository = arnsRepository, super(AssignNameInitial()) { on((event, emit) async { - emit(LoadingNames()); + try { + emit(LoadingNames()); - final walletAddress = await _auth.getWalletAddress(); - if (!event.updateARNSRecords) { - await _arnsRepository.waitForARNSRecordsToUpdate(); - } + final walletAddress = await _auth.getWalletAddress(); + if (!event.updateARNSRecords) { + await _arnsRepository.waitForARNSRecordsToUpdate(); + } - final names = await _arnsRepository.getAntRecordsForWallet( - walletAddress!, - update: event.updateARNSRecords, - ); + final names = await _arnsRepository.getAntRecordsForWallet( + walletAddress!, + update: event.updateARNSRecords, + ); - if (names.isEmpty) { - emit(AssignNameEmptyState()); - } else { - emit(NamesLoaded(names: names)); + if (names.isEmpty) { + emit(AssignNameEmptyState()); + } else { + emit(NamesLoaded(names: names)); + } + } catch (e) { + logger.e('Failed to load ArNS names', e); + emit(LoadingNamesFailed()); } }); @@ -100,41 +105,37 @@ class AssignNameBloc extends Bloc { on((event, emit) async { try { emit(ConfirmingSelection()); - try { - if (fileDataTableItem == null) { - throw StateError('File data table item is null'); - } - - ARNSUndername undername; - - if (_selectedUndername == null) { - undername = ARNSUndername( - name: '@', - record: ARNSRecord( - transactionId: fileDataTableItem.dataTxId, ttlSeconds: 3600), - domain: _selectedANTRecord!.domain, - ); - } else { - undername = ARNSUndername( - name: _selectedUndername!.name, - record: ARNSRecord( - transactionId: fileDataTableItem.dataTxId, - ttlSeconds: 3600, - ), - domain: _selectedANTRecord!.domain, - ); - } - - await _arnsRepository.setUndernamesToFile( - undername: undername, - fileId: fileDataTableItem.fileId, - driveId: fileDataTableItem.driveId, - processId: _selectedANTRecord!.processId, + if (fileDataTableItem == null) { + throw StateError('File data table item is null'); + } + + ARNSUndername undername; + + if (_selectedUndername == null) { + undername = ARNSUndername( + name: '@', + record: ARNSRecord( + transactionId: fileDataTableItem.dataTxId, ttlSeconds: 3600), + domain: _selectedANTRecord!.domain, + ); + } else { + undername = ARNSUndername( + name: _selectedUndername!.name, + record: ARNSRecord( + transactionId: fileDataTableItem.dataTxId, + ttlSeconds: 3600, + ), + domain: _selectedANTRecord!.domain, ); - } catch (e) { - logger.e('Failed to set ARNS', e); } + await _arnsRepository.setUndernamesToFile( + undername: undername, + fileId: fileDataTableItem.fileId, + driveId: fileDataTableItem.driveId, + processId: _selectedANTRecord!.processId, + ); + final (address, arAddress) = getAddressesFromArns( domain: _selectedANTRecord!.domain, undername: _selectedUndername?.name, diff --git a/lib/arns/presentation/assign_name_bloc/assign_name_state.dart b/lib/arns/presentation/assign_name_bloc/assign_name_state.dart index 02add380af..34215c9988 100644 --- a/lib/arns/presentation/assign_name_bloc/assign_name_state.dart +++ b/lib/arns/presentation/assign_name_bloc/assign_name_state.dart @@ -92,3 +92,5 @@ final class SelectionConfirmed extends AssignNameState { final class LoadingUndernames extends AssignNameState {} class SelectionFailed extends AssignNameState {} + +final class LoadingNamesFailed extends AssignNameState {} diff --git a/lib/arns/presentation/assign_name_modal.dart b/lib/arns/presentation/assign_name_modal.dart index 4a322e2428..8b98269c26 100644 --- a/lib/arns/presentation/assign_name_modal.dart +++ b/lib/arns/presentation/assign_name_modal.dart @@ -251,6 +251,28 @@ class _AssignArNSNameModalState extends State<_AssignArNSNameModal> { return const Center(child: CircularProgressIndicator()); } else if (state is AssignNameEmptyState) { return const _AssignNameEmptyState(); + } else if (state is SelectionFailed) { + final colorTokens = + ArDriveTheme.of(context).themeData.colorTokens; + return Center( + child: Text( + 'Error assigning ArNS name. Please try again later', + style: typography.paragraphLarge( + color: colorTokens.textMid, + ), + ), + ); + } else if (state is LoadingNamesFailed) { + final colorTokens = + ArDriveTheme.of(context).themeData.colorTokens; + return Center( + child: Text( + 'Error fetching ArNS names. Please try again later', + style: typography.paragraphLarge( + color: colorTokens.textMid, + ), + ), + ); } return const SizedBox(); @@ -279,6 +301,42 @@ class _AssignArNSNameModalState extends State<_AssignArNSNameModal> { return []; } + if (state is LoadingNamesFailed) { + return [ + ModalAction( + action: () { + Navigator.of(context).pop(); + }, + title: 'Cancel', + ), + ModalAction( + action: () { + context + .read() + .add(const LoadNames(updateARNSRecords: true)); + }, + title: 'Try again', + ), + ]; + } + + if (state is SelectionFailed) { + return [ + ModalAction( + action: () { + Navigator.of(context).pop(); + }, + title: 'Cancel', + ), + ModalAction( + action: () { + context.read().add(ConfirmSelectionAndUpload()); + }, + title: 'Try again', + ), + ]; + } + late final bool isButtonEnabled; if (state is NamesLoaded && state.selectedName != null) { diff --git a/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart b/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart index 130677415a..a52086d06e 100644 --- a/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart +++ b/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart @@ -106,6 +106,29 @@ void main() { verify(() => mockArnsRepository.getAntRecordsForWallet(walletAddress, update: true)).called(1); }); + + test('emits [LoadingNames, LoadingNamesFailed] when LoadNames is added', + () async { + // Arrange + const walletAddress = 'test_wallet_address'; + + when(() => mockAuth.getWalletAddress()) + .thenAnswer((_) async => walletAddress); + when(() => mockArnsRepository.getAntRecordsForWallet(walletAddress, + update: true)).thenThrow(StateError('Test error')); + + // Act + assignNameBloc.add(const LoadNames()); + + // Assert + await expectLater( + assignNameBloc.stream, + emitsInOrder([ + isA(), + isA(), + ]), + ); + }); }); group('SelectName', () { @@ -351,5 +374,75 @@ void main() { }, ); }); + + blocTest( + 'emits [ConfirmingSelection, SelectionFailed] when ConfirmSelection is added', + build: () { + when(() => mockFileDataTableItem.dataTxId) + .thenReturn('test_data_tx_id'); + when(() => mockFileDataTableItem.fileId).thenReturn('test_file_id'); + when(() => mockFileDataTableItem.driveId).thenReturn('test_drive_id'); + final antRecords = [ + ANTRecord(domain: 'test1.ar', processId: 'process1'), + ANTRecord(domain: 'test2.ar', processId: 'process2'), + ]; + + const walletAddress = 'test_wallet_address'; + + when(() => mockAuth.getWalletAddress()) + .thenAnswer((_) async => walletAddress); + when(() => mockArnsRepository.getAntRecordsForWallet(walletAddress, + update: true)).thenAnswer((_) async => antRecords); + + /// FAILED CALL + when(() => mockArnsRepository.setUndernamesToFile( + undername: any(named: 'undername'), + fileId: any(named: 'fileId'), + driveId: any(named: 'driveId'), + processId: any(named: 'processId'), + )).thenThrow(StateError('Test error')); + when(() => mockArnsRepository.getARNSUndernames(any())).thenAnswer( + (_) async => [ + ARNSUndername( + name: 'undername', + domain: 'domain', + record: ARNSRecord(transactionId: 'test_tx_id', ttlSeconds: 3600), + ) + ], + ); + return assignNameBloc; + }, + act: (bloc) { + bloc.add(const LoadNames()); + bloc.add( + SelectName(ANTRecord(domain: 'domain', processId: 'process_id'))); + bloc.add(const LoadUndernames()); + bloc.add(SelectUndername( + undername: ARNSUndername( + name: 'undername', + domain: 'domain', + record: ARNSRecord(transactionId: 'test_tx_id', ttlSeconds: 3600), + ), + )); + bloc.add(ConfirmSelectionAndUpload()); + }, + expect: () => [ + isA(), + isA(), + isA(), + isA(), + isA(), + isA(), + isA(), + ], + verify: (_) { + verify(() => mockArnsRepository.setUndernamesToFile( + undername: any(named: 'undername'), + fileId: any(named: 'fileId'), + driveId: any(named: 'driveId'), + processId: any(named: 'processId'), + )).called(1); + }, + ); }); } From ec4afa92f0cd5eed4b741fe23e1a9d8c081fbda5 Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Wed, 11 Sep 2024 09:44:31 -0300 Subject: [PATCH 2/5] Update arns_repository.dart complete with error --- lib/arns/domain/arns_repository.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/arns/domain/arns_repository.dart b/lib/arns/domain/arns_repository.dart index 65e5e13ad7..2d7b78a028 100644 --- a/lib/arns/domain/arns_repository.dart +++ b/lib/arns/domain/arns_repository.dart @@ -238,7 +238,7 @@ class _ARNSRepository implements ARNSRepository { } catch (e) { logger.e('Error getting ANT records for wallet: $e'); - _getARNSUndernamesCompleter!.complete([]); + _getARNSUndernamesCompleter!.completeError(e); _getARNSUndernamesCompleter = null; From 0643e3bcb00d724624922b1f473a590c702d8e6e Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:30:34 -0300 Subject: [PATCH 3/5] Update assign_name_bloc_test.dart --- .../presentation/assign_name_bloc/assign_name_bloc_test.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart b/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart index b0ee83f1be..874ec963e5 100644 --- a/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart +++ b/test/arns/presentation/assign_name_bloc/assign_name_bloc_test.dart @@ -393,8 +393,9 @@ void main() { when(() => mockAuth.getWalletAddress()) .thenAnswer((_) async => walletAddress); - when(() => mockArnsRepository.getAntRecordsForWallet(walletAddress, - update: true)).thenAnswer((_) async => antRecords); + when(() => mockArnsRepository.getAntRecordsForWallet( + walletAddress, + )).thenAnswer((_) async => antRecords); /// FAILED CALL when(() => mockArnsRepository.setUndernamesToFile( From 30a4a9ebda7376a0d72f42d283ea6eff451065a8 Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:45:47 -0300 Subject: [PATCH 4/5] feat(upload) - use size of the files instead of the data items being uploaded --- lib/blocs/upload/upload_cubit.dart | 12 ++++++++++++ lib/blocs/upload/upload_state.dart | 5 ++++- lib/components/upload_form.dart | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/lib/blocs/upload/upload_cubit.dart b/lib/blocs/upload/upload_cubit.dart index 0c758da480..37d8a0cbc0 100644 --- a/lib/blocs/upload/upload_cubit.dart +++ b/lib/blocs/upload/upload_cubit.dart @@ -120,6 +120,7 @@ class UploadCubit extends Cubit { showArnsCheckbox: showArnsCheckbox, showArnsNameSelection: false, loadingArNSNames: true, + totalSize: await _getTotalSize(), ), ); @@ -156,6 +157,7 @@ class UploadCubit extends Cubit { isArConnect: (state as UploadReadyToPrepare).isArConnect, showArnsCheckbox: showArnsCheckbox, showArnsNameSelection: false, + totalSize: await _getTotalSize(), ), ); } @@ -176,6 +178,16 @@ class UploadCubit extends Cubit { } } + Future _getTotalSize() async { + int size = 0; + + for (final file in files) { + size += await file.ioFile.length; + } + + return size; + } + void initialScreenNext({required LicenseCategory licenseCategory}) { if (state is UploadReady) { final readyState = state as UploadReady; diff --git a/lib/blocs/upload/upload_state.dart b/lib/blocs/upload/upload_state.dart index a855aa9389..5cacacf246 100644 --- a/lib/blocs/upload/upload_state.dart +++ b/lib/blocs/upload/upload_state.dart @@ -97,6 +97,7 @@ class UploadReady extends UploadState { final bool showArnsNameSelection; final bool loadingArNSNames; final bool loadingArNSNamesError; + final int totalSize; final bool isArConnect; @@ -112,6 +113,7 @@ class UploadReady extends UploadState { required this.showArnsNameSelection, this.loadingArNSNames = false, this.loadingArNSNamesError = false, + required this.totalSize, }); // copyWith @@ -129,6 +131,7 @@ class UploadReady extends UploadState { bool? showArnsNameSelection, bool? loadingArNSNames, bool? loadingArNSNamesError, + int? totalSize, }) { return UploadReady( loadingArNSNames: loadingArNSNames ?? this.loadingArNSNames, @@ -144,6 +147,7 @@ class UploadReady extends UploadState { showArnsNameSelection ?? this.showArnsNameSelection, loadingArNSNamesError: loadingArNSNamesError ?? this.loadingArNSNamesError, + totalSize: totalSize ?? this.totalSize, ); } @@ -155,7 +159,6 @@ class UploadReady extends UploadState { loadingArNSNamesError, loadingArNSNames, showArnsCheckbox, - ]; @override diff --git a/lib/components/upload_form.dart b/lib/components/upload_form.dart index 93a81f82cf..1b7c9c84bc 100644 --- a/lib/components/upload_form.dart +++ b/lib/components/upload_form.dart @@ -1568,7 +1568,7 @@ class _StatsScreenState extends State { ), TextSpan( text: filesize( - widget.readyState.paymentInfo.totalSize, + widget.readyState.totalSize, ), style: typography.paragraphNormal( fontWeight: ArFontWeight.bold, From c957514ca36ae43c6ea4dfe51b6d3a9057b5c800 Mon Sep 17 00:00:00 2001 From: Thiago Carvalho <32248947+thiagocarvalhodev@users.noreply.github.com> Date: Thu, 19 Sep 2024 11:19:19 -0300 Subject: [PATCH 5/5] add release notes and bump version --- android/fastlane/metadata/android/en-US/changelogs/154.txt | 2 ++ pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 android/fastlane/metadata/android/en-US/changelogs/154.txt diff --git a/android/fastlane/metadata/android/en-US/changelogs/154.txt b/android/fastlane/metadata/android/en-US/changelogs/154.txt new file mode 100644 index 0000000000..7b714dbe56 --- /dev/null +++ b/android/fastlane/metadata/android/en-US/changelogs/154.txt @@ -0,0 +1,2 @@ + - Improves handling of errors on the assign name flow + - Displays the file(s) size(s) instead of data items or bundle sizes at the upload page diff --git a/pubspec.yaml b/pubspec.yaml index 2417029a0d..274d7fbeba 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Secure, permanent storage publish_to: 'none' -version: 2.54.3 +version: 2.54.4 environment: sdk: '>=3.2.0 <4.0.0'