Skip to content

Commit

Permalink
Handle errors (#114)
Browse files Browse the repository at this point in the history
* Add isError to state and showDialog

* Dismiss alert view

* Fix tests

* Add test for alertDialogDismissed

* Refactor scan bloc tests
  • Loading branch information
WezSieTato authored Aug 24, 2024
1 parent c68b2ee commit d711c95
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 66 deletions.
26 changes: 26 additions & 0 deletions lib/pages/scan/scan.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mobile_scanner/mobile_scanner.dart';
import 'package:pola_flutter/analytics/analytics_about_row.dart';
Expand Down Expand Up @@ -94,6 +95,31 @@ class _MainPageState extends State<MainPage> {
BlocBuilder<ScanBloc, ScanState>(
bloc: _scanBloc,
builder: (context, state) {
if (state.isError) {
SchedulerBinding.instance.addPostFrameCallback((_) {
showDialog(
context: context,
barrierDismissible: false,
builder: (_) {
return AlertDialog(
title: Text('Wystąpił błąd'),
content: Text('Niestety nie udało się pobrać danych. Spróbuj ponownie.'),
actions: <Widget>[
TextButton(
child: Text('Zamknij.'),
onPressed: () {
_scanBloc.add(ScanEvent.alertDialogDismissed());
SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.pop(context);
});
},
),
],
);
},
);
});
}
return CompaniesList(state, listScrollController);
},
),
Expand Down
28 changes: 17 additions & 11 deletions lib/pages/scan/scan_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,20 @@ class ScanBloc extends Bloc<ScanEvent, ScanState> {
final ScanVibration _scanVibration;
final PolaAnalytics _analytics;

_onBarcodeScanned(String barcode, Emitter<ScanState> emit) async {
ScanBloc(this._polaApiRepository, this._scanVibration, this._analytics, {ScanState state = const ScanState()})
: super(state) {
on<ScanEvent>((event, emit) async {
await event.when(
barcodeScanned: (barcode) async => await _onBarcodeScanned(barcode, emit),
alertDialogDismissed: () => _onAlertDialogDismissed(emit),
);
});
}

_onBarcodeScanned(String barcode, Emitter<ScanState> emit) async {
if (state.list.any((element) => element.code == barcode) ||
state.isLoading) {
state.isLoading ||
state.isError) {
return;
}
emit(state.copyWith(isLoading: true));
Expand All @@ -30,18 +41,13 @@ class ScanBloc extends Bloc<ScanEvent, ScanState> {
var results = List<SearchResult>.from(state.list);
results.add(result);
_analytics.searchResultReceived(result);
emit(state.copyWith(list: results, isLoading: false));
emit(state.copyWith(list: results, isLoading: false, isError: false));
} else {
emit(state.copyWith(isLoading: false));
emit(state.copyWith(isLoading: false, isError: true));
}
}

ScanBloc(this._polaApiRepository, this._scanVibration, this._analytics)
: super(ScanState()) {
on<ScanEvent>((event, emit) async {
await event.when(
barcodeScanned: (barcode) async => await _onBarcodeScanned(barcode, emit)
);
});
_onAlertDialogDismissed(Emitter<ScanState> emit) {
emit(state.copyWith(isError: false));
}
}
1 change: 1 addition & 0 deletions lib/pages/scan/scan_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ part 'scan_event.freezed.dart';
@freezed
class ScanEvent with _$ScanEvent {
const factory ScanEvent.barcodeScanned(String barcode) = BarcodeScanned;
const factory ScanEvent.alertDialogDismissed() = AlertDialogDismissed;
}
141 changes: 116 additions & 25 deletions lib/pages/scan/scan_event.freezed.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,51 +16,50 @@ final _privateConstructorUsedError = UnsupportedError(

/// @nodoc
mixin _$ScanEvent {
String get barcode => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String barcode) barcodeScanned,
required TResult Function() alertDialogDismissed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String barcode)? barcodeScanned,
TResult? Function()? alertDialogDismissed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String barcode)? barcodeScanned,
TResult Function()? alertDialogDismissed,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(BarcodeScanned value) barcodeScanned,
required TResult Function(AlertDialogDismissed value) alertDialogDismissed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(BarcodeScanned value)? barcodeScanned,
TResult? Function(AlertDialogDismissed value)? alertDialogDismissed,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(BarcodeScanned value)? barcodeScanned,
TResult Function(AlertDialogDismissed value)? alertDialogDismissed,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;

@JsonKey(ignore: true)
$ScanEventCopyWith<ScanEvent> get copyWith =>
throw _privateConstructorUsedError;
}

/// @nodoc
abstract class $ScanEventCopyWith<$Res> {
factory $ScanEventCopyWith(ScanEvent value, $Res Function(ScanEvent) then) =
_$ScanEventCopyWithImpl<$Res, ScanEvent>;
@useResult
$Res call({String barcode});
}

/// @nodoc
Expand All @@ -72,28 +71,13 @@ class _$ScanEventCopyWithImpl<$Res, $Val extends ScanEvent>
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;

@pragma('vm:prefer-inline')
@override
$Res call({
Object? barcode = null,
}) {
return _then(_value.copyWith(
barcode: null == barcode
? _value.barcode
: barcode // ignore: cast_nullable_to_non_nullable
as String,
) as $Val);
}
}

/// @nodoc
abstract class _$$BarcodeScannedImplCopyWith<$Res>
implements $ScanEventCopyWith<$Res> {
abstract class _$$BarcodeScannedImplCopyWith<$Res> {
factory _$$BarcodeScannedImplCopyWith(_$BarcodeScannedImpl value,
$Res Function(_$BarcodeScannedImpl) then) =
__$$BarcodeScannedImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({String barcode});
}
Expand Down Expand Up @@ -155,6 +139,7 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String barcode) barcodeScanned,
required TResult Function() alertDialogDismissed,
}) {
return barcodeScanned(barcode);
}
Expand All @@ -163,6 +148,7 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String barcode)? barcodeScanned,
TResult? Function()? alertDialogDismissed,
}) {
return barcodeScanned?.call(barcode);
}
Expand All @@ -171,6 +157,7 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String barcode)? barcodeScanned,
TResult Function()? alertDialogDismissed,
required TResult orElse(),
}) {
if (barcodeScanned != null) {
Expand All @@ -183,6 +170,7 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(BarcodeScanned value) barcodeScanned,
required TResult Function(AlertDialogDismissed value) alertDialogDismissed,
}) {
return barcodeScanned(this);
}
Expand All @@ -191,6 +179,7 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(BarcodeScanned value)? barcodeScanned,
TResult? Function(AlertDialogDismissed value)? alertDialogDismissed,
}) {
return barcodeScanned?.call(this);
}
Expand All @@ -199,6 +188,7 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(BarcodeScanned value)? barcodeScanned,
TResult Function(AlertDialogDismissed value)? alertDialogDismissed,
required TResult orElse(),
}) {
if (barcodeScanned != null) {
Expand All @@ -211,10 +201,111 @@ class _$BarcodeScannedImpl implements BarcodeScanned {
abstract class BarcodeScanned implements ScanEvent {
const factory BarcodeScanned(final String barcode) = _$BarcodeScannedImpl;

@override
String get barcode;
@override
@JsonKey(ignore: true)
_$$BarcodeScannedImplCopyWith<_$BarcodeScannedImpl> get copyWith =>
throw _privateConstructorUsedError;
}

/// @nodoc
abstract class _$$AlertDialogDismissedImplCopyWith<$Res> {
factory _$$AlertDialogDismissedImplCopyWith(_$AlertDialogDismissedImpl value,
$Res Function(_$AlertDialogDismissedImpl) then) =
__$$AlertDialogDismissedImplCopyWithImpl<$Res>;
}

/// @nodoc
class __$$AlertDialogDismissedImplCopyWithImpl<$Res>
extends _$ScanEventCopyWithImpl<$Res, _$AlertDialogDismissedImpl>
implements _$$AlertDialogDismissedImplCopyWith<$Res> {
__$$AlertDialogDismissedImplCopyWithImpl(_$AlertDialogDismissedImpl _value,
$Res Function(_$AlertDialogDismissedImpl) _then)
: super(_value, _then);
}

/// @nodoc
class _$AlertDialogDismissedImpl implements AlertDialogDismissed {
const _$AlertDialogDismissedImpl();

@override
String toString() {
return 'ScanEvent.alertDialogDismissed()';
}

@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$AlertDialogDismissedImpl);
}

@override
int get hashCode => runtimeType.hashCode;

@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String barcode) barcodeScanned,
required TResult Function() alertDialogDismissed,
}) {
return alertDialogDismissed();
}

@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String barcode)? barcodeScanned,
TResult? Function()? alertDialogDismissed,
}) {
return alertDialogDismissed?.call();
}

@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String barcode)? barcodeScanned,
TResult Function()? alertDialogDismissed,
required TResult orElse(),
}) {
if (alertDialogDismissed != null) {
return alertDialogDismissed();
}
return orElse();
}

@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(BarcodeScanned value) barcodeScanned,
required TResult Function(AlertDialogDismissed value) alertDialogDismissed,
}) {
return alertDialogDismissed(this);
}

@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(BarcodeScanned value)? barcodeScanned,
TResult? Function(AlertDialogDismissed value)? alertDialogDismissed,
}) {
return alertDialogDismissed?.call(this);
}

@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(BarcodeScanned value)? barcodeScanned,
TResult Function(AlertDialogDismissed value)? alertDialogDismissed,
required TResult orElse(),
}) {
if (alertDialogDismissed != null) {
return alertDialogDismissed(this);
}
return orElse();
}
}

abstract class AlertDialogDismissed implements ScanEvent {
const factory AlertDialogDismissed() = _$AlertDialogDismissedImpl;
}
1 change: 1 addition & 0 deletions lib/pages/scan/scan_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ class ScanState with _$ScanState {
const factory ScanState({
@Default([]) List<SearchResult> list,
@Default(false) bool isLoading,
@Default(false) bool isError
}) = Initial;
}
Loading

0 comments on commit d711c95

Please sign in to comment.