diff --git a/packages/widget_toolkit_pin/CHANGELOG.md b/packages/widget_toolkit_pin/CHANGELOG.md index 195c938f..9ed6d1e5 100644 --- a/packages/widget_toolkit_pin/CHANGELOG.md +++ b/packages/widget_toolkit_pin/CHANGELOG.md @@ -1,3 +1,7 @@ +## [0.1.0] +- Update `PinCodeService.verifyPinCode` to return a `Future` instead of a `bool` +- Improvements to error handling + ## [0.0.2] - Upgrade major versions of dependencies: `theme_tailor`, `theme_tailor_annotation` ### Breaking changes: diff --git a/packages/widget_toolkit_pin/README.md b/packages/widget_toolkit_pin/README.md index 22a89d71..13876db9 100644 --- a/packages/widget_toolkit_pin/README.md +++ b/packages/widget_toolkit_pin/README.md @@ -249,8 +249,8 @@ ok, the biometrics authentication is triggered. When it is successful, on the sc a message that the biometrics are enabled. The next time when restart the app, because the pin code will be stored in the device secure storage, the biometrics authentication will be automatically triggered and the biometrics icon will be displayed on the bottom right. When you press it every -time it will trigger the biometric authentication. If a user types a wrong pin code and the error -ErrorWrongPin is thrown from the service layer, then a shake animation is triggered on the masked +time it will trigger the biometric authentication. If a user types a wrong pin code and the error +is thrown from the service layer, then a shake animation is triggered on the masked pin code and then the text from the ErrorWrongPin's errorMessage is displayed in the place of the pin code. Note: If `biometricsLocalDataSource`parameter is not provided to `PinCodeKeyboard` the biometrics authentication feature cannot be used. diff --git a/packages/widget_toolkit_pin/example/lib/main.dart b/packages/widget_toolkit_pin/example/lib/main.dart index 4d45f5cd..374f8554 100644 --- a/packages/widget_toolkit_pin/example/lib/main.dart +++ b/packages/widget_toolkit_pin/example/lib/main.dart @@ -82,7 +82,7 @@ class MyHomePage extends StatelessWidget { addDependencies: true, // Optionally you can provide [onAuthenticated] where the // function is invoked when the user is authenticated. - onAuthenticated: () { + onAuthenticated: (authValue) { _onAuthenticated(context); }, @@ -126,7 +126,8 @@ class MyHomePage extends StatelessWidget { ); } - String _translateError(Object error) => 'An error has occurred'; + String _translateError(Object error) => + error is ErrorModel ? error.toString() : 'An error has occurred'; String _exampleMapBiometricMessageToString(BiometricsMessage message) { switch (message) { @@ -156,7 +157,7 @@ class AppPinCodeService implements PinCodeService { @override Future isPinCodeInSecureStorage() async { - if (_pinCode == '111') { + if (_pinCode == '1111') { return Future.value(true); } return Future.value(false); @@ -169,14 +170,15 @@ class AppPinCodeService implements PinCodeService { } @override - Future getPinLength() async => Future.value(3); + Future getPinLength() async => Future.value(4); @override - Future verifyPinCode(String pinCode) async { - if (pinCode == '111') { - return Future.value(true); + Future verifyPinCode(String pinCode) async { + if (pinCode != '1111') { + throw WrongPinCodeException(pinCode); } - return false; + + return pinCode; } @override @@ -204,3 +206,13 @@ class ProfileLocalDataSource implements BiometricsLocalDataSource { Future setBiometricsEnabled(bool enable) async => _areBiometricsEnabled = enable; } + +/// Exception thrown when the pin code is wrong +class WrongPinCodeException implements ErrorModel { + final String pinCode; + + WrongPinCodeException(this.pinCode); + + @override + String toString() => 'Invalid pin code: $pinCode'; +} diff --git a/packages/widget_toolkit_pin/example/pubspec.yaml b/packages/widget_toolkit_pin/example/pubspec.yaml index 9c5dee79..8aff5a02 100644 --- a/packages/widget_toolkit_pin/example/pubspec.yaml +++ b/packages/widget_toolkit_pin/example/pubspec.yaml @@ -23,5 +23,9 @@ dev_dependencies: sdk: flutter build_runner: ^2.4.6 +dependency_overrides: + widget_toolkit_pin: + path: .. + flutter: uses-material-design: true diff --git a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.dart b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.dart index 6aab3244..6e45c663 100644 --- a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.dart +++ b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.dart @@ -31,7 +31,7 @@ abstract class PinCodeBlocStates { ConnectableStream get showBiometricsButton; ///Emits when user successfully authenticate (pin/biometrics) - ConnectableStream get authenticated; + ConnectableStream get authenticated; /// The loading state Stream get isLoading; @@ -56,9 +56,9 @@ class PinCodeBloc extends $PinCodeBloc { final String localizedReason; final BehaviorSubject _pinCode = BehaviorSubject.seeded(''); - final BehaviorSubject _pinAuth = BehaviorSubject(); + final BehaviorSubject _pinAuth = BehaviorSubject(); - Future encryptAndVerify(String pinCode) async { + Future encryptAndVerify(String pinCode) async { final encryptedPin = await pinCodeService.encryptPinCode(pinCode); final verifiedPin = await pinCodeService.verifyPinCode(encryptedPin); return verifiedPin; @@ -91,7 +91,7 @@ class PinCodeBloc extends $PinCodeBloc { Stream _mapToErrorsState() => errorState.mapToErrorModel(); @override - ConnectableStream _mapToAuthenticatedState() => Rx.merge([ + ConnectableStream _mapToAuthenticatedState() => Rx.merge([ _$biometricsButtonPressedEvent.switchMap((_) => biometricAuthenticationService .authenticate(localizedReason) @@ -127,16 +127,16 @@ class PinCodeBloc extends $PinCodeBloc { Future _checkPin(int digits) async { final storedPinLength = await pinCodeService.getPinLength(); if (digits == storedPinLength) { - final isCorrectPin = await encryptAndVerify(_pinCode.value); - if (isCorrectPin) { + try { + final authValue = await encryptAndVerify(_pinCode.value); final isSaved = await pinCodeService.isPinCodeInSecureStorage(); if (isSaved) { - _pinAuth.add(true); + _pinAuth.add(authValue); return true; } - } else { + } catch (_) { _pinCode.value = ''; - throw Exception('Wrong Pin'); + rethrow; } } return false; diff --git a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.rxb.g.dart b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.rxb.g.dart index fec3f337..69e07275 100644 --- a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.rxb.g.dart +++ b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/blocs/pin_code_bloc.rxb.g.dart @@ -40,7 +40,7 @@ abstract class $PinCodeBloc extends RxBlocBase _mapToShowBiometricsButtonState(); /// The state of [authenticated] implemented in [_mapToAuthenticatedState] - late final ConnectableStream _authenticatedState = + late final ConnectableStream _authenticatedState = _mapToAuthenticatedState(); /// The state of [isLoading] implemented in [_mapToIsLoadingState] @@ -69,7 +69,7 @@ abstract class $PinCodeBloc extends RxBlocBase _showBiometricsButtonState; @override - ConnectableStream get authenticated => _authenticatedState; + ConnectableStream get authenticated => _authenticatedState; @override Stream get isLoading => _isLoadingState; @@ -81,7 +81,7 @@ abstract class $PinCodeBloc extends RxBlocBase ConnectableStream _mapToShowBiometricsButtonState(); - ConnectableStream _mapToAuthenticatedState(); + ConnectableStream _mapToAuthenticatedState(); Stream _mapToIsLoadingState(); diff --git a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/services/pin_code_service.dart b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/services/pin_code_service.dart index 985c7f19..2ae39d17 100644 --- a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/services/pin_code_service.dart +++ b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/services/pin_code_service.dart @@ -4,8 +4,8 @@ abstract class PinCodeService { Future isPinCodeInSecureStorage(); /// Receives the encrypted pinCode from user input. - /// Returns whether it was verified by the server - Future verifyPinCode(String pinCode); + /// Returns the value verified by the server + Future verifyPinCode(String pinCode); /// Returns the correct length from the backend, /// the length should be less than 10 digits diff --git a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_component.dart b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_component.dart index cccd22cd..17bcfb46 100644 --- a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_component.dart +++ b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_component.dart @@ -47,7 +47,7 @@ class PinCodeComponent extends StatefulWidget { final String Function(BiometricsMessage message)? mapBiometricMessageToString; /// Returns the verification state of the input from the pin code value. - final VoidCallback? onAuthenticated; + final Function(dynamic)? onAuthenticated; /// Provide custom implementation for the most down left button. Do not forget /// to make it clickable. Default to LeftArrow. @@ -161,13 +161,14 @@ class _PinCodeComponentState extends State _startErrorAnimation(); }, ), - RxBlocListener( + RxBlocListener( state: (bloc) => bloc.states.authenticated, - listener: (context, auth) { + listener: (context, authValue) { setState(() { authenticatedPin = true; }); - widget.onAuthenticated?.call(); + + widget.onAuthenticated?.call(authValue); }, ), _buildBuilders() diff --git a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_keyboard.dart b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_keyboard.dart index 0395b92a..54f0b909 100644 --- a/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_keyboard.dart +++ b/packages/widget_toolkit_pin/lib/src/lib_pin_code_with_biometrics/ui_components/pin_code_keyboard.dart @@ -73,7 +73,7 @@ class PinCodeKeyboard extends StatelessWidget { final BiometricsLocalDataSource? biometricsLocalDataSource; /// Called when a user is authenticated with biometrics successfully - final VoidCallback? onAuthenticated; + final Function(dynamic)? onAuthenticated; /// Provide custom implementation for the most down left button, shown when /// there is pin code input on the screen. Do not forget to make it clickable. diff --git a/packages/widget_toolkit_pin/pubspec.yaml b/packages/widget_toolkit_pin/pubspec.yaml index c98a5b7b..16fe9cfc 100644 --- a/packages/widget_toolkit_pin/pubspec.yaml +++ b/packages/widget_toolkit_pin/pubspec.yaml @@ -1,7 +1,7 @@ name: widget_toolkit_pin description: This package provide out of the box entering PIN code functionality, which can be used with biometric authentication. -version: 0.0.2 +version: 0.1.0 homepage: https://primeholding.com/ environment: diff --git a/packages/widget_toolkit_pin/test/lib_pin_code/blocs/pin_code_test.mocks.dart b/packages/widget_toolkit_pin/test/lib_pin_code/blocs/pin_code_test.mocks.dart index 0baa3836..4968a124 100644 --- a/packages/widget_toolkit_pin/test/lib_pin_code/blocs/pin_code_test.mocks.dart +++ b/packages/widget_toolkit_pin/test/lib_pin_code/blocs/pin_code_test.mocks.dart @@ -156,13 +156,13 @@ class MockPinCodeService extends _i1.Mock implements _i7.PinCodeService { ) as _i4.Future); @override - _i4.Future verifyPinCode(String? pinCode) => (super.noSuchMethod( + _i4.Future verifyPinCode(String? pinCode) => (super.noSuchMethod( Invocation.method( #verifyPinCode, [pinCode], ), - returnValue: _i4.Future.value(false), - ) as _i4.Future); + returnValue: _i4.Future.value(), + ) as _i4.Future); @override _i4.Future getPinLength() => (super.noSuchMethod( diff --git a/packages/widget_toolkit_pin/test/mocks/pin_code_mock.mocks.dart b/packages/widget_toolkit_pin/test/mocks/pin_code_mock.mocks.dart index 13a1a2fd..21ad8cf4 100644 --- a/packages/widget_toolkit_pin/test/mocks/pin_code_mock.mocks.dart +++ b/packages/widget_toolkit_pin/test/mocks/pin_code_mock.mocks.dart @@ -81,13 +81,13 @@ class MockPinCodeBlocStates extends _i1.Mock implements _i3.PinCodeBlocStates { ) as _i2.ConnectableStream); @override - _i2.ConnectableStream get authenticated => (super.noSuchMethod( + _i2.ConnectableStream get authenticated => (super.noSuchMethod( Invocation.getter(#authenticated), - returnValue: _FakeConnectableStream_0( + returnValue: _FakeConnectableStream_0( this, Invocation.getter(#authenticated), ), - ) as _i2.ConnectableStream); + ) as _i2.ConnectableStream); @override _i4.Stream get isLoading => (super.noSuchMethod(