Skip to content

Commit

Permalink
Merge pull request #136 from Prime-Holding/develop
Browse files Browse the repository at this point in the history
Merge develop to master
  • Loading branch information
DDavidPrime authored Oct 31, 2024
2 parents e31df77 + ff5e639 commit c0dabb7
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 145 deletions.
3 changes: 3 additions & 0 deletions packages/widget_toolkit_pin/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## [0.2.2]
* Fixed a bug where a newly input pin could get deleted if the user starts typing again immediately after an error shake animation starts

## [0.2.1]
* Fixed a visual bug where held buttons would remain stuck in the pressed state
* Fixed a visual bug where pin indicators wouldn't be displayed after an error is presented
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ abstract class PinCodeBlocEvents {

///Triggered when user tap on biometrics button
void biometricsButtonPressed();

void checkIfPinIsStored();
}

/// A contract class containing all states of the PinCodeBloc.
abstract class PinCodeBlocStates {
///Indicating how much dots to present
/// Emits current PIN length to UI
Stream<int> get digitsCount;

/// Emits placeholder PIN length to UI
Stream<int> get placeholderDigitsCount;

///Indicating the biometrics button must be presented
ConnectableStream<bool> get showBiometricsButton;
Stream<bool> get showBiometricsButton;

///Emits when user successfully authenticate (pin/biometrics)
ConnectableStream<dynamic> get authenticated;
Expand All @@ -50,22 +51,13 @@ class PinCodeBloc extends $PinCodeBloc {
required this.localizedReason,
}) {
authenticated.connect().addTo(_compositeSubscription);
showBiometricsButton.connect().addTo(_compositeSubscription);

_$biometricsButtonPressedEvent
.switchMap((_) => _authenticateWithBiometrics().asResultStream())
.setResultStateHandler(this)
.whereSuccess()
.listen((_) {})
.addTo(_compositeSubscription);
}

final PinBiometricsService biometricAuthenticationService;
final PinCodeService pinCodeService;
final String localizedReason;

final BehaviorSubject<String> _pinCode = BehaviorSubject.seeded('');
final BehaviorSubject<dynamic> _authResponse = BehaviorSubject();

@override
Stream<int> _mapToDigitsCountState() => Rx.merge([
Expand All @@ -77,34 +69,40 @@ class PinCodeBloc extends $PinCodeBloc {
return Stream.value(_pinCode.value.length);
},
).asResultStream(),
errorState
.delay(const Duration(milliseconds: 1000))
.mapTo(0)
.asResultStream(),
errorState.mapTo(0).asResultStream(),
]).whereSuccess().startWith(0).share();

@override
Stream<bool> _mapToIsLoadingState() => loadingState;
Stream<int> _mapToPlaceholderDigitsCountState() => pinCodeService
.getPinLength()
.asResultStream()
.setResultStateHandler(this)
.whereSuccess();

@override
Stream<ErrorModel> _mapToErrorsState() => errorState.mapToErrorModel();
Stream<bool> _mapToIsLoadingState() => loadingState;

@override
ConnectableStream<dynamic> _mapToAuthenticatedState() =>
_authResponse.publish();
Stream<ErrorModel> _mapToErrorsState() => errorState.mapToErrorModel();

@override
ConnectableStream<bool> _mapToShowBiometricsButtonState() => Rx.merge([
_$checkIfPinIsStoredEvent.switchMap(
(_) => pinCodeService.isPinCodeInSecureStorage().asResultStream()),
ConnectableStream<dynamic> _mapToAuthenticatedState() => Rx.merge([
_digitsCountState.switchMap((digitsCount) =>
_checkPin(_pinCode.value, digitsCount).asResultStream()),
_getAreBiometricsEnabled().asResultStream(),
_$biometricsButtonPressedEvent
.switchMap((_) => _authenticateWithBiometrics().asResultStream()),
]).setResultStateHandler(this).whereSuccess().publish();

@override
Stream<bool> _mapToShowBiometricsButtonState() => const Stream.empty()
.startWith(null)
.switchMap((_) => _getAreBiometricsEnabled().asResultStream())
.setResultStateHandler(this)
.whereSuccess()
.shareReplay(maxSize: 1);

@override
void dispose() {
_authResponse.close();
_pinCode.close();
super.dispose();
}
Expand Down Expand Up @@ -147,15 +145,14 @@ class PinCodeBloc extends $PinCodeBloc {
}

/// Checks the validity of the pin code
Future<bool> _checkPin(String pinCode, int digits) async {
Future<dynamic> _checkPin(String pinCode, int digits) async {
final storedPinLength = await pinCodeService.getPinLength();
if (digits == storedPinLength) {
if (storedPinLength != 0 && digits == storedPinLength) {
try {
final authValue = await _encryptAndVerify(pinCode);
final isSaved = await pinCodeService.isPinCodeInSecureStorage();
if (isSaved) {
_authResponse.add(authValue);
return true;
return authValue;
}
} catch (_) {
_pinCode.value = '';
Expand All @@ -167,7 +164,7 @@ class PinCodeBloc extends $PinCodeBloc {

/// Authenticates the user with biometrics after which the pin code is
/// retrieved from the device and checked.
Future<bool> _authenticateWithBiometrics() async {
Future<bool?> _authenticateWithBiometrics() async {
if (!await biometricAuthenticationService.isDeviceSupported) {
throw ErrorEnableBiometrics(BiometricsMessage.notSupported);
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import 'package:widget_toolkit_biometrics/widget_toolkit_biometrics.dart';
import '../models/biometrics_authentication_type.dart';

class PinBiometricsAuthDataSource extends BiometricsAuthDataSource {
PinBiometricsAuthDataSource({required this.localAuthentication});
PinBiometricsAuthDataSource({LocalAuthentication? localAuthentication})
: _localAuthentication = localAuthentication ?? LocalAuthentication();

final LocalAuthentication localAuthentication;
final LocalAuthentication _localAuthentication;

Future<List<BiometricsAuthType>> get availableBiometrics =>
localAuthentication
_localAuthentication
.getAvailableBiometrics()
.then((list) => list.map((e) => mapBiometric(e)).toList());

Expand All @@ -27,14 +28,16 @@ class PinBiometricsAuthDataSource extends BiometricsAuthDataSource {
}

@override
Future<bool> get canCheckBiometrics => localAuthentication.canCheckBiometrics;
Future<bool> get canCheckBiometrics =>
_localAuthentication.canCheckBiometrics;

@override
Future<bool> get isDeviceSupported => localAuthentication.isDeviceSupported();
Future<bool> get isDeviceSupported =>
_localAuthentication.isDeviceSupported();

@override
Future<bool> authenticate(String localizedReason) =>
localAuthentication.authenticate(
_localAuthentication.authenticate(
localizedReason: localizedReason,
options: const AuthenticationOptions(
biometricOnly: false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import 'package:widget_toolkit_biometrics/widget_toolkit_biometrics.dart';

import '../../../widget_toolkit_pin.dart';
import '../data_source/biometrics_disabled_local_data_source.dart';
import '../data_source/pin_biometrics_auth_data_source.dart';
import '../repositories/pin_biometrics_repository.dart';
import '../services/pin_biometrics_service.dart';

Expand All @@ -14,22 +13,26 @@ class PinCodeDependencies {
this.pinCodeService,
this.biometricsLocalDataSource,
this.localizedReason,
this.biometricsAuthDataSource,
);

factory PinCodeDependencies.from({
required PinCodeService pinCodeService,
required BiometricsLocalDataSource? biometricsLocalDataSource,
required String localizedReason,
PinBiometricsAuthDataSource? biometricsAuthDataSource,
}) =>
PinCodeDependencies._(
pinCodeService,
biometricsLocalDataSource,
localizedReason,
biometricsAuthDataSource,
);

final String localizedReason;
final PinCodeService pinCodeService;
final BiometricsLocalDataSource? biometricsLocalDataSource;
final PinBiometricsAuthDataSource? biometricsAuthDataSource;

late List<SingleChildWidget> providers = [
..._localAuthentication,
Expand All @@ -47,9 +50,11 @@ class PinCodeDependencies {

late final List<SingleChildWidget> _dataSources = [
Provider<PinBiometricsAuthDataSource>(
create: (context) => PinBiometricsAuthDataSource(
localAuthentication: context.read<LocalAuthentication>(),
),
create: (context) =>
biometricsAuthDataSource ??
PinBiometricsAuthDataSource(
localAuthentication: context.read<LocalAuthentication>(),
),
),
if (biometricsLocalDataSource == null)
Provider<BiometricsLocalDataSource>(
Expand Down
Loading

0 comments on commit c0dabb7

Please sign in to comment.