feat: integrate enakgame and voucher
Build & Deploy iOS to TestFlight / build-and-deploy (push) Canceled after 0s

This commit is contained in:
efrilm
2026-10-10 02:33:16 +07:00
parent e5515d5871
commit 38850b281f
104 changed files with 7122 additions and 8063 deletions
@@ -0,0 +1,40 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/wallet/wallet.dart';
part 'voucher_loader_event.dart';
part 'voucher_loader_state.dart';
part 'voucher_loader_bloc.freezed.dart';
/// Katalog voucher yang bisa ditukar (§9.1).
@injectable
class VoucherLoaderBloc extends Bloc<VoucherLoaderEvent, VoucherLoaderState> {
final IVoucherRepository _repository;
VoucherLoaderBloc(this._repository) : super(VoucherLoaderState.initial()) {
on<VoucherLoaderEvent>(_onVoucherLoaderEvent);
}
Future<void> _onVoucherLoaderEvent(
VoucherLoaderEvent event,
Emitter<VoucherLoaderState> emit,
) {
return event.map(
fetched: (e) async {
emit(state.copyWith(isFetching: true, failureOption: none()));
final result = await _repository.getVouchers();
final data = result.fold(
(f) => state.copyWith(failureOption: optionOf(f)),
(vouchers) => state.copyWith(vouchers: vouchers, hasLoaded: true),
);
emit(data.copyWith(isFetching: false));
},
);
}
}
@@ -0,0 +1,486 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint, type=warning, deprecated_member_use, deprecated_member_use_from_same_package
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'voucher_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$VoucherLoaderEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is VoucherLoaderEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'VoucherLoaderEvent()';
}
}
/// @nodoc
class $VoucherLoaderEventCopyWith<$Res> {
$VoucherLoaderEventCopyWith(VoucherLoaderEvent _, $Res Function(VoucherLoaderEvent) __);
}
/// Adds pattern-matching-related methods to [VoucherLoaderEvent].
extension VoucherLoaderEventPatterns on VoucherLoaderEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Fetched value)? fetched,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Fetched() when fetched != null:
return fetched(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Fetched value) fetched,}){
final _that = this;
switch (_that) {
case _Fetched():
return fetched(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Fetched value)? fetched,}){
final _that = this;
switch (_that) {
case _Fetched() when fetched != null:
return fetched(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? fetched,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Fetched() when fetched != null:
return fetched();case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() fetched,}) {final _that = this;
switch (_that) {
case _Fetched():
return fetched();case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? fetched,}) {final _that = this;
switch (_that) {
case _Fetched() when fetched != null:
return fetched();case _:
return null;
}
}
}
/// @nodoc
class _Fetched implements VoucherLoaderEvent {
const _Fetched();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Fetched);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'VoucherLoaderEvent.fetched()';
}
}
/// @nodoc
mixin _$VoucherLoaderState {
List<Voucher> get vouchers; Option<WalletFailure> get failureOption; bool get isFetching; bool get hasLoaded;
/// Create a copy of VoucherLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$VoucherLoaderStateCopyWith<VoucherLoaderState> get copyWith => _$VoucherLoaderStateCopyWithImpl<VoucherLoaderState>(this as VoucherLoaderState, _$identity);
@override
bool operator ==(Object other) {
final _this = this as VoucherLoaderState;
return identical(this, other) || (other.runtimeType == runtimeType&&other is VoucherLoaderState&&const DeepCollectionEquality().equals(other.vouchers, _this.vouchers)&&(identical(other.failureOption, _this.failureOption) || other.failureOption == _this.failureOption)&&(identical(other.isFetching, _this.isFetching) || other.isFetching == _this.isFetching)&&(identical(other.hasLoaded, _this.hasLoaded) || other.hasLoaded == _this.hasLoaded));
}
@override
int get hashCode {
final _this = this as VoucherLoaderState;
return Object.hash(runtimeType,const DeepCollectionEquality().hash(_this.vouchers),_this.failureOption,_this.isFetching,_this.hasLoaded);
}
@override
String toString() {
final _this = this as VoucherLoaderState;
return 'VoucherLoaderState(vouchers: ${_this.vouchers}, failureOption: ${_this.failureOption}, isFetching: ${_this.isFetching}, hasLoaded: ${_this.hasLoaded})';
}
}
/// @nodoc
abstract mixin class $VoucherLoaderStateCopyWith<$Res> {
factory $VoucherLoaderStateCopyWith(VoucherLoaderState value, $Res Function(VoucherLoaderState) _then) = _$VoucherLoaderStateCopyWithImpl;
@useResult
$Res call({
List<Voucher> vouchers, Option<WalletFailure> failureOption, bool isFetching, bool hasLoaded
});
}
/// @nodoc
class _$VoucherLoaderStateCopyWithImpl<$Res>
implements $VoucherLoaderStateCopyWith<$Res> {
_$VoucherLoaderStateCopyWithImpl(this._self, this._then);
final VoucherLoaderState _self;
final $Res Function(VoucherLoaderState) _then;
/// Create a copy of VoucherLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? vouchers = null,Object? failureOption = null,Object? isFetching = null,Object? hasLoaded = null,}) {
return _then(VoucherLoaderState(
vouchers: null == vouchers ? _self.vouchers : vouchers // ignore: cast_nullable_to_non_nullable
as List<Voucher>,failureOption: null == failureOption ? _self.failureOption : failureOption // ignore: cast_nullable_to_non_nullable
as Option<WalletFailure>,isFetching: null == isFetching ? _self.isFetching : isFetching // ignore: cast_nullable_to_non_nullable
as bool,hasLoaded: null == hasLoaded ? _self.hasLoaded : hasLoaded // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [VoucherLoaderState].
extension VoucherLoaderStatePatterns on VoucherLoaderState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _VoucherLoaderState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _VoucherLoaderState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _VoucherLoaderState value) $default,){
final _that = this;
switch (_that) {
case _VoucherLoaderState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _VoucherLoaderState value)? $default,){
final _that = this;
switch (_that) {
case _VoucherLoaderState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<Voucher> vouchers, Option<WalletFailure> failureOption, bool isFetching, bool hasLoaded)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _VoucherLoaderState() when $default != null:
return $default(_that.vouchers,_that.failureOption,_that.isFetching,_that.hasLoaded);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<Voucher> vouchers, Option<WalletFailure> failureOption, bool isFetching, bool hasLoaded) $default,) {final _that = this;
switch (_that) {
case _VoucherLoaderState():
return $default(_that.vouchers,_that.failureOption,_that.isFetching,_that.hasLoaded);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<Voucher> vouchers, Option<WalletFailure> failureOption, bool isFetching, bool hasLoaded)? $default,) {final _that = this;
switch (_that) {
case _VoucherLoaderState() when $default != null:
return $default(_that.vouchers,_that.failureOption,_that.isFetching,_that.hasLoaded);case _:
return null;
}
}
}
/// @nodoc
class _VoucherLoaderState implements VoucherLoaderState {
const _VoucherLoaderState({required List<Voucher> vouchers, required this.failureOption, this.isFetching = false, this.hasLoaded = false}): _vouchers = vouchers;
final List<Voucher> _vouchers;
@override List<Voucher> get vouchers {
if (_vouchers is EqualUnmodifiableListView) return _vouchers;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_vouchers);
}
@override final Option<WalletFailure> failureOption;
@override@JsonKey() final bool isFetching;
@override@JsonKey() final bool hasLoaded;
/// Create a copy of VoucherLoaderState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$VoucherLoaderStateCopyWith<_VoucherLoaderState> get copyWith => __$VoucherLoaderStateCopyWithImpl<_VoucherLoaderState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _VoucherLoaderState&&const DeepCollectionEquality().equals(other.vouchers, _vouchers)&&(identical(other.failureOption, failureOption) || other.failureOption == failureOption)&&(identical(other.isFetching, isFetching) || other.isFetching == isFetching)&&(identical(other.hasLoaded, hasLoaded) || other.hasLoaded == hasLoaded));
}
@override
int get hashCode {
return Object.hash(runtimeType,const DeepCollectionEquality().hash(_vouchers),failureOption,isFetching,hasLoaded);
}
@override
String toString() {
return 'VoucherLoaderState(vouchers: $vouchers, failureOption: $failureOption, isFetching: $isFetching, hasLoaded: $hasLoaded)';
}
}
/// @nodoc
abstract mixin class _$VoucherLoaderStateCopyWith<$Res> implements $VoucherLoaderStateCopyWith<$Res> {
factory _$VoucherLoaderStateCopyWith(_VoucherLoaderState value, $Res Function(_VoucherLoaderState) _then) = __$VoucherLoaderStateCopyWithImpl;
@override @useResult
$Res call({
List<Voucher> vouchers, Option<WalletFailure> failureOption, bool isFetching, bool hasLoaded
});
}
/// @nodoc
class __$VoucherLoaderStateCopyWithImpl<$Res>
implements _$VoucherLoaderStateCopyWith<$Res> {
__$VoucherLoaderStateCopyWithImpl(this._self, this._then);
final _VoucherLoaderState _self;
final $Res Function(_VoucherLoaderState) _then;
/// Create a copy of VoucherLoaderState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? vouchers = null,Object? failureOption = null,Object? isFetching = null,Object? hasLoaded = null,}) {
return _then(_VoucherLoaderState(
vouchers: null == vouchers ? _self._vouchers : vouchers // ignore: cast_nullable_to_non_nullable
as List<Voucher>,failureOption: null == failureOption ? _self.failureOption : failureOption // ignore: cast_nullable_to_non_nullable
as Option<WalletFailure>,isFetching: null == isFetching ? _self.isFetching : isFetching // ignore: cast_nullable_to_non_nullable
as bool,hasLoaded: null == hasLoaded ? _self.hasLoaded : hasLoaded // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
// dart format on
@@ -0,0 +1,6 @@
part of 'voucher_loader_bloc.dart';
@freezed
abstract class VoucherLoaderEvent with _$VoucherLoaderEvent {
const factory VoucherLoaderEvent.fetched() = _Fetched;
}
@@ -0,0 +1,14 @@
part of 'voucher_loader_bloc.dart';
@freezed
abstract class VoucherLoaderState with _$VoucherLoaderState {
const factory VoucherLoaderState({
required List<Voucher> vouchers,
required Option<WalletFailure> failureOption,
@Default(false) bool isFetching,
@Default(false) bool hasLoaded,
}) = _VoucherLoaderState;
factory VoucherLoaderState.initial() =>
VoucherLoaderState(vouchers: const [], failureOption: none());
}
@@ -0,0 +1,63 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../common/function/app_function.dart';
import '../../../domain/wallet/wallet.dart';
part 'voucher_redeem_form_event.dart';
part 'voucher_redeem_form_state.dart';
part 'voucher_redeem_form_bloc.freezed.dart';
/// Tukar EnakPoint ke satu voucher (§9.2). Satu bloc per voucher, supaya
/// `Idempotency-Key` tidak terbawa ke voucher lain.
@injectable
class VoucherRedeemFormBloc
extends Bloc<VoucherRedeemFormEvent, VoucherRedeemFormState> {
final IVoucherRepository _repository;
VoucherRedeemFormBloc(this._repository)
: super(VoucherRedeemFormState.initial()) {
on<VoucherRedeemFormEvent>(_onVoucherRedeemFormEvent);
}
Future<void> _onVoucherRedeemFormEvent(
VoucherRedeemFormEvent event,
Emitter<VoucherRedeemFormState> emit,
) {
return event.map(
submitted: (e) async {
// Key baru untuk setiap konfirmasi, kecuali mengulang request yang
// sebelumnya gagal karena jaringan.
final key = state.idempotencyKey ?? generateUuidV4();
emit(
state.copyWith(
isSubmitting: true,
idempotencyKey: key,
failureOption: none(),
),
);
final result = await _repository.redeem(
voucherId: e.voucherId,
pin: e.pin,
idempotencyKey: key,
);
emit(
result
.fold(
(f) => state.copyWith(
failureOption: optionOf(f),
idempotencyKey: f.isNetworkError ? key : null,
),
(redeemResult) =>
state.copyWith(result: redeemResult, idempotencyKey: null),
)
.copyWith(isSubmitting: false),
);
},
);
}
}
@@ -0,0 +1,579 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint, type=warning, deprecated_member_use, deprecated_member_use_from_same_package
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'voucher_redeem_form_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$VoucherRedeemFormEvent {
String get voucherId; String get pin;
/// Create a copy of VoucherRedeemFormEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$VoucherRedeemFormEventCopyWith<VoucherRedeemFormEvent> get copyWith => _$VoucherRedeemFormEventCopyWithImpl<VoucherRedeemFormEvent>(this as VoucherRedeemFormEvent, _$identity);
@override
bool operator ==(Object other) {
final _this = this as VoucherRedeemFormEvent;
return identical(this, other) || (other.runtimeType == runtimeType&&other is VoucherRedeemFormEvent&&(identical(other.voucherId, _this.voucherId) || other.voucherId == _this.voucherId)&&(identical(other.pin, _this.pin) || other.pin == _this.pin));
}
@override
int get hashCode {
final _this = this as VoucherRedeemFormEvent;
return Object.hash(runtimeType,_this.voucherId,_this.pin);
}
@override
String toString() {
final _this = this as VoucherRedeemFormEvent;
return 'VoucherRedeemFormEvent(voucherId: ${_this.voucherId}, pin: ${_this.pin})';
}
}
/// @nodoc
abstract mixin class $VoucherRedeemFormEventCopyWith<$Res> {
factory $VoucherRedeemFormEventCopyWith(VoucherRedeemFormEvent value, $Res Function(VoucherRedeemFormEvent) _then) = _$VoucherRedeemFormEventCopyWithImpl;
@useResult
$Res call({
String voucherId, String pin
});
}
/// @nodoc
class _$VoucherRedeemFormEventCopyWithImpl<$Res>
implements $VoucherRedeemFormEventCopyWith<$Res> {
_$VoucherRedeemFormEventCopyWithImpl(this._self, this._then);
final VoucherRedeemFormEvent _self;
final $Res Function(VoucherRedeemFormEvent) _then;
/// Create a copy of VoucherRedeemFormEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? voucherId = null,Object? pin = null,}) {
return _then(VoucherRedeemFormEvent.submitted(
voucherId: null == voucherId ? _self.voucherId : voucherId // ignore: cast_nullable_to_non_nullable
as String,pin: null == pin ? _self.pin : pin // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// Adds pattern-matching-related methods to [VoucherRedeemFormEvent].
extension VoucherRedeemFormEventPatterns on VoucherRedeemFormEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Submitted value)? submitted,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Submitted() when submitted != null:
return submitted(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Submitted value) submitted,}){
final _that = this;
switch (_that) {
case _Submitted():
return submitted(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Submitted value)? submitted,}){
final _that = this;
switch (_that) {
case _Submitted() when submitted != null:
return submitted(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function( String voucherId, String pin)? submitted,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Submitted() when submitted != null:
return submitted(_that.voucherId,_that.pin);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function( String voucherId, String pin) submitted,}) {final _that = this;
switch (_that) {
case _Submitted():
return submitted(_that.voucherId,_that.pin);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function( String voucherId, String pin)? submitted,}) {final _that = this;
switch (_that) {
case _Submitted() when submitted != null:
return submitted(_that.voucherId,_that.pin);case _:
return null;
}
}
}
/// @nodoc
class _Submitted implements VoucherRedeemFormEvent {
const _Submitted({required this.voucherId, required this.pin});
@override final String voucherId;
@override final String pin;
/// Create a copy of VoucherRedeemFormEvent
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$SubmittedCopyWith<_Submitted> get copyWith => __$SubmittedCopyWithImpl<_Submitted>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Submitted&&(identical(other.voucherId, voucherId) || other.voucherId == voucherId)&&(identical(other.pin, pin) || other.pin == pin));
}
@override
int get hashCode {
return Object.hash(runtimeType,voucherId,pin);
}
@override
String toString() {
return 'VoucherRedeemFormEvent.submitted(voucherId: $voucherId, pin: $pin)';
}
}
/// @nodoc
abstract mixin class _$SubmittedCopyWith<$Res> implements $VoucherRedeemFormEventCopyWith<$Res> {
factory _$SubmittedCopyWith(_Submitted value, $Res Function(_Submitted) _then) = __$SubmittedCopyWithImpl;
@override @useResult
$Res call({
String voucherId, String pin
});
}
/// @nodoc
class __$SubmittedCopyWithImpl<$Res>
implements _$SubmittedCopyWith<$Res> {
__$SubmittedCopyWithImpl(this._self, this._then);
final _Submitted _self;
final $Res Function(_Submitted) _then;
/// Create a copy of VoucherRedeemFormEvent
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? voucherId = null,Object? pin = null,}) {
return _then(_Submitted(
voucherId: null == voucherId ? _self.voucherId : voucherId // ignore: cast_nullable_to_non_nullable
as String,pin: null == pin ? _self.pin : pin // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
mixin _$VoucherRedeemFormState {
VoucherRedeemResult? get result; Option<WalletFailure> get failureOption; bool get isSubmitting; String? get idempotencyKey;
/// Create a copy of VoucherRedeemFormState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$VoucherRedeemFormStateCopyWith<VoucherRedeemFormState> get copyWith => _$VoucherRedeemFormStateCopyWithImpl<VoucherRedeemFormState>(this as VoucherRedeemFormState, _$identity);
@override
bool operator ==(Object other) {
final _this = this as VoucherRedeemFormState;
return identical(this, other) || (other.runtimeType == runtimeType&&other is VoucherRedeemFormState&&(identical(other.result, _this.result) || other.result == _this.result)&&(identical(other.failureOption, _this.failureOption) || other.failureOption == _this.failureOption)&&(identical(other.isSubmitting, _this.isSubmitting) || other.isSubmitting == _this.isSubmitting)&&(identical(other.idempotencyKey, _this.idempotencyKey) || other.idempotencyKey == _this.idempotencyKey));
}
@override
int get hashCode {
final _this = this as VoucherRedeemFormState;
return Object.hash(runtimeType,_this.result,_this.failureOption,_this.isSubmitting,_this.idempotencyKey);
}
@override
String toString() {
final _this = this as VoucherRedeemFormState;
return 'VoucherRedeemFormState(result: ${_this.result}, failureOption: ${_this.failureOption}, isSubmitting: ${_this.isSubmitting}, idempotencyKey: ${_this.idempotencyKey})';
}
}
/// @nodoc
abstract mixin class $VoucherRedeemFormStateCopyWith<$Res> {
factory $VoucherRedeemFormStateCopyWith(VoucherRedeemFormState value, $Res Function(VoucherRedeemFormState) _then) = _$VoucherRedeemFormStateCopyWithImpl;
@useResult
$Res call({
VoucherRedeemResult? result, Option<WalletFailure> failureOption, bool isSubmitting, String? idempotencyKey
});
$VoucherRedeemResultCopyWith<$Res>? get result;
}
/// @nodoc
class _$VoucherRedeemFormStateCopyWithImpl<$Res>
implements $VoucherRedeemFormStateCopyWith<$Res> {
_$VoucherRedeemFormStateCopyWithImpl(this._self, this._then);
final VoucherRedeemFormState _self;
final $Res Function(VoucherRedeemFormState) _then;
/// Create a copy of VoucherRedeemFormState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? result = freezed,Object? failureOption = null,Object? isSubmitting = null,Object? idempotencyKey = freezed,}) {
return _then(VoucherRedeemFormState(
result: freezed == result ? _self.result : result // ignore: cast_nullable_to_non_nullable
as VoucherRedeemResult?,failureOption: null == failureOption ? _self.failureOption : failureOption // ignore: cast_nullable_to_non_nullable
as Option<WalletFailure>,isSubmitting: null == isSubmitting ? _self.isSubmitting : isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,idempotencyKey: freezed == idempotencyKey ? _self.idempotencyKey : idempotencyKey // ignore: cast_nullable_to_non_nullable
as String?,
));
}
/// Create a copy of VoucherRedeemFormState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$VoucherRedeemResultCopyWith<$Res>? get result {
if (_self.result == null) {
return null;
}
return $VoucherRedeemResultCopyWith<$Res>(_self.result!, (value) {
return _then(_self.copyWith(result: value));
});
}
}
/// Adds pattern-matching-related methods to [VoucherRedeemFormState].
extension VoucherRedeemFormStatePatterns on VoucherRedeemFormState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _VoucherRedeemFormState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _VoucherRedeemFormState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _VoucherRedeemFormState value) $default,){
final _that = this;
switch (_that) {
case _VoucherRedeemFormState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _VoucherRedeemFormState value)? $default,){
final _that = this;
switch (_that) {
case _VoucherRedeemFormState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( VoucherRedeemResult? result, Option<WalletFailure> failureOption, bool isSubmitting, String? idempotencyKey)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _VoucherRedeemFormState() when $default != null:
return $default(_that.result,_that.failureOption,_that.isSubmitting,_that.idempotencyKey);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( VoucherRedeemResult? result, Option<WalletFailure> failureOption, bool isSubmitting, String? idempotencyKey) $default,) {final _that = this;
switch (_that) {
case _VoucherRedeemFormState():
return $default(_that.result,_that.failureOption,_that.isSubmitting,_that.idempotencyKey);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( VoucherRedeemResult? result, Option<WalletFailure> failureOption, bool isSubmitting, String? idempotencyKey)? $default,) {final _that = this;
switch (_that) {
case _VoucherRedeemFormState() when $default != null:
return $default(_that.result,_that.failureOption,_that.isSubmitting,_that.idempotencyKey);case _:
return null;
}
}
}
/// @nodoc
class _VoucherRedeemFormState implements VoucherRedeemFormState {
const _VoucherRedeemFormState({this.result, required this.failureOption, this.isSubmitting = false, this.idempotencyKey});
@override final VoucherRedeemResult? result;
@override final Option<WalletFailure> failureOption;
@override@JsonKey() final bool isSubmitting;
@override final String? idempotencyKey;
/// Create a copy of VoucherRedeemFormState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$VoucherRedeemFormStateCopyWith<_VoucherRedeemFormState> get copyWith => __$VoucherRedeemFormStateCopyWithImpl<_VoucherRedeemFormState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _VoucherRedeemFormState&&(identical(other.result, result) || other.result == result)&&(identical(other.failureOption, failureOption) || other.failureOption == failureOption)&&(identical(other.isSubmitting, isSubmitting) || other.isSubmitting == isSubmitting)&&(identical(other.idempotencyKey, idempotencyKey) || other.idempotencyKey == idempotencyKey));
}
@override
int get hashCode {
return Object.hash(runtimeType,result,failureOption,isSubmitting,idempotencyKey);
}
@override
String toString() {
return 'VoucherRedeemFormState(result: $result, failureOption: $failureOption, isSubmitting: $isSubmitting, idempotencyKey: $idempotencyKey)';
}
}
/// @nodoc
abstract mixin class _$VoucherRedeemFormStateCopyWith<$Res> implements $VoucherRedeemFormStateCopyWith<$Res> {
factory _$VoucherRedeemFormStateCopyWith(_VoucherRedeemFormState value, $Res Function(_VoucherRedeemFormState) _then) = __$VoucherRedeemFormStateCopyWithImpl;
@override @useResult
$Res call({
VoucherRedeemResult? result, Option<WalletFailure> failureOption, bool isSubmitting, String? idempotencyKey
});
@override $VoucherRedeemResultCopyWith<$Res>? get result;
}
/// @nodoc
class __$VoucherRedeemFormStateCopyWithImpl<$Res>
implements _$VoucherRedeemFormStateCopyWith<$Res> {
__$VoucherRedeemFormStateCopyWithImpl(this._self, this._then);
final _VoucherRedeemFormState _self;
final $Res Function(_VoucherRedeemFormState) _then;
/// Create a copy of VoucherRedeemFormState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? result = freezed,Object? failureOption = null,Object? isSubmitting = null,Object? idempotencyKey = freezed,}) {
return _then(_VoucherRedeemFormState(
result: freezed == result ? _self.result : result // ignore: cast_nullable_to_non_nullable
as VoucherRedeemResult?,failureOption: null == failureOption ? _self.failureOption : failureOption // ignore: cast_nullable_to_non_nullable
as Option<WalletFailure>,isSubmitting: null == isSubmitting ? _self.isSubmitting : isSubmitting // ignore: cast_nullable_to_non_nullable
as bool,idempotencyKey: freezed == idempotencyKey ? _self.idempotencyKey : idempotencyKey // ignore: cast_nullable_to_non_nullable
as String?,
));
}
/// Create a copy of VoucherRedeemFormState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$VoucherRedeemResultCopyWith<$Res>? get result {
if (_self.result == null) {
return null;
}
return $VoucherRedeemResultCopyWith<$Res>(_self.result!, (value) {
return _then(_self.copyWith(result: value));
});
}
}
// dart format on
@@ -0,0 +1,10 @@
part of 'voucher_redeem_form_bloc.dart';
@freezed
abstract class VoucherRedeemFormEvent with _$VoucherRedeemFormEvent {
/// [pin] hanya diteruskan ke API, tidak disimpan di state.
const factory VoucherRedeemFormEvent.submitted({
required String voucherId,
required String pin,
}) = _Submitted;
}
@@ -0,0 +1,14 @@
part of 'voucher_redeem_form_bloc.dart';
@freezed
abstract class VoucherRedeemFormState with _$VoucherRedeemFormState {
const factory VoucherRedeemFormState({
VoucherRedeemResult? result,
required Option<WalletFailure> failureOption,
@Default(false) bool isSubmitting,
String? idempotencyKey,
}) = _VoucherRedeemFormState;
factory VoucherRedeemFormState.initial() =>
VoucherRedeemFormState(failureOption: none());
}
@@ -0,0 +1,73 @@
import 'package:bloc/bloc.dart';
import 'package:dartz/dartz.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/wallet/wallet.dart';
part 'voucher_redemption_loader_event.dart';
part 'voucher_redemption_loader_state.dart';
part 'voucher_redemption_loader_bloc.freezed.dart';
/// "Voucher saya" (§9.3).
@injectable
class VoucherRedemptionLoaderBloc
extends Bloc<VoucherRedemptionLoaderEvent, VoucherRedemptionLoaderState> {
final IVoucherRepository _repository;
static const int _limit = 20;
VoucherRedemptionLoaderBloc(this._repository)
: super(VoucherRedemptionLoaderState.initial()) {
on<VoucherRedemptionLoaderEvent>(_onVoucherRedemptionLoaderEvent);
}
Future<void> _onVoucherRedemptionLoaderEvent(
VoucherRedemptionLoaderEvent event,
Emitter<VoucherRedemptionLoaderState> emit,
) {
return event.map(
refreshed: (e) async {
emit(state.copyWith(isFetching: true, failureOption: none()));
final result = await _repository.getRedemptions(page: 1, limit: _limit);
emit(
result
.fold(
(f) => state.copyWith(failureOption: optionOf(f)),
(page) => state.copyWith(
items: page.items,
page: page.page,
totalPages: page.totalPages,
hasLoaded: true,
),
)
.copyWith(isFetching: false),
);
},
loadedMore: (e) async {
if (state.isFetching || state.isLoadingMore || !state.hasMore) return;
emit(state.copyWith(isLoadingMore: true, failureOption: none()));
final result = await _repository.getRedemptions(
page: state.page + 1,
limit: _limit,
);
emit(
result
.fold(
(f) => state.copyWith(failureOption: optionOf(f)),
(page) => state.copyWith(
items: [...state.items, ...page.items],
page: page.page,
totalPages: page.totalPages,
),
)
.copyWith(isLoadingMore: false),
);
},
);
}
}
@@ -0,0 +1,533 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// coverage:ignore-file
// ignore_for_file: type=lint, type=warning, deprecated_member_use, deprecated_member_use_from_same_package
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
part of 'voucher_redemption_loader_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
// GENERATED CODE - DO NOT MODIFY BY HAND
// dart format off
T _$identity<T>(T value) => value;
/// @nodoc
mixin _$VoucherRedemptionLoaderEvent {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is VoucherRedemptionLoaderEvent);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'VoucherRedemptionLoaderEvent()';
}
}
/// @nodoc
class $VoucherRedemptionLoaderEventCopyWith<$Res> {
$VoucherRedemptionLoaderEventCopyWith(VoucherRedemptionLoaderEvent _, $Res Function(VoucherRedemptionLoaderEvent) __);
}
/// Adds pattern-matching-related methods to [VoucherRedemptionLoaderEvent].
extension VoucherRedemptionLoaderEventPatterns on VoucherRedemptionLoaderEvent {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>({TResult Function( _Refreshed value)? refreshed,TResult Function( _LoadedMore value)? loadedMore,required TResult orElse(),}){
final _that = this;
switch (_that) {
case _Refreshed() when refreshed != null:
return refreshed(_that);case _LoadedMore() when loadedMore != null:
return loadedMore(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>({required TResult Function( _Refreshed value) refreshed,required TResult Function( _LoadedMore value) loadedMore,}){
final _that = this;
switch (_that) {
case _Refreshed():
return refreshed(_that);case _LoadedMore():
return loadedMore(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>({TResult? Function( _Refreshed value)? refreshed,TResult? Function( _LoadedMore value)? loadedMore,}){
final _that = this;
switch (_that) {
case _Refreshed() when refreshed != null:
return refreshed(_that);case _LoadedMore() when loadedMore != null:
return loadedMore(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>({TResult Function()? refreshed,TResult Function()? loadedMore,required TResult orElse(),}) {final _that = this;
switch (_that) {
case _Refreshed() when refreshed != null:
return refreshed();case _LoadedMore() when loadedMore != null:
return loadedMore();case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>({required TResult Function() refreshed,required TResult Function() loadedMore,}) {final _that = this;
switch (_that) {
case _Refreshed():
return refreshed();case _LoadedMore():
return loadedMore();case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>({TResult? Function()? refreshed,TResult? Function()? loadedMore,}) {final _that = this;
switch (_that) {
case _Refreshed() when refreshed != null:
return refreshed();case _LoadedMore() when loadedMore != null:
return loadedMore();case _:
return null;
}
}
}
/// @nodoc
class _Refreshed implements VoucherRedemptionLoaderEvent {
const _Refreshed();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Refreshed);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'VoucherRedemptionLoaderEvent.refreshed()';
}
}
/// @nodoc
class _LoadedMore implements VoucherRedemptionLoaderEvent {
const _LoadedMore();
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _LoadedMore);
}
@override
int get hashCode => runtimeType.hashCode;
@override
String toString() {
return 'VoucherRedemptionLoaderEvent.loadedMore()';
}
}
/// @nodoc
mixin _$VoucherRedemptionLoaderState {
List<VoucherRedemption> get items; int get page; int get totalPages; Option<WalletFailure> get failureOption; bool get isFetching; bool get isLoadingMore; bool get hasLoaded;
/// Create a copy of VoucherRedemptionLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
$VoucherRedemptionLoaderStateCopyWith<VoucherRedemptionLoaderState> get copyWith => _$VoucherRedemptionLoaderStateCopyWithImpl<VoucherRedemptionLoaderState>(this as VoucherRedemptionLoaderState, _$identity);
@override
bool operator ==(Object other) {
final _this = this as VoucherRedemptionLoaderState;
return identical(this, other) || (other.runtimeType == runtimeType&&other is VoucherRedemptionLoaderState&&const DeepCollectionEquality().equals(other.items, _this.items)&&(identical(other.page, _this.page) || other.page == _this.page)&&(identical(other.totalPages, _this.totalPages) || other.totalPages == _this.totalPages)&&(identical(other.failureOption, _this.failureOption) || other.failureOption == _this.failureOption)&&(identical(other.isFetching, _this.isFetching) || other.isFetching == _this.isFetching)&&(identical(other.isLoadingMore, _this.isLoadingMore) || other.isLoadingMore == _this.isLoadingMore)&&(identical(other.hasLoaded, _this.hasLoaded) || other.hasLoaded == _this.hasLoaded));
}
@override
int get hashCode {
final _this = this as VoucherRedemptionLoaderState;
return Object.hash(runtimeType,const DeepCollectionEquality().hash(_this.items),_this.page,_this.totalPages,_this.failureOption,_this.isFetching,_this.isLoadingMore,_this.hasLoaded);
}
@override
String toString() {
final _this = this as VoucherRedemptionLoaderState;
return 'VoucherRedemptionLoaderState(items: ${_this.items}, page: ${_this.page}, totalPages: ${_this.totalPages}, failureOption: ${_this.failureOption}, isFetching: ${_this.isFetching}, isLoadingMore: ${_this.isLoadingMore}, hasLoaded: ${_this.hasLoaded})';
}
}
/// @nodoc
abstract mixin class $VoucherRedemptionLoaderStateCopyWith<$Res> {
factory $VoucherRedemptionLoaderStateCopyWith(VoucherRedemptionLoaderState value, $Res Function(VoucherRedemptionLoaderState) _then) = _$VoucherRedemptionLoaderStateCopyWithImpl;
@useResult
$Res call({
List<VoucherRedemption> items, int page, int totalPages, Option<WalletFailure> failureOption, bool isFetching, bool isLoadingMore, bool hasLoaded
});
}
/// @nodoc
class _$VoucherRedemptionLoaderStateCopyWithImpl<$Res>
implements $VoucherRedemptionLoaderStateCopyWith<$Res> {
_$VoucherRedemptionLoaderStateCopyWithImpl(this._self, this._then);
final VoucherRedemptionLoaderState _self;
final $Res Function(VoucherRedemptionLoaderState) _then;
/// Create a copy of VoucherRedemptionLoaderState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? items = null,Object? page = null,Object? totalPages = null,Object? failureOption = null,Object? isFetching = null,Object? isLoadingMore = null,Object? hasLoaded = null,}) {
return _then(VoucherRedemptionLoaderState(
items: null == items ? _self.items : items // ignore: cast_nullable_to_non_nullable
as List<VoucherRedemption>,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable
as int,totalPages: null == totalPages ? _self.totalPages : totalPages // ignore: cast_nullable_to_non_nullable
as int,failureOption: null == failureOption ? _self.failureOption : failureOption // ignore: cast_nullable_to_non_nullable
as Option<WalletFailure>,isFetching: null == isFetching ? _self.isFetching : isFetching // ignore: cast_nullable_to_non_nullable
as bool,isLoadingMore: null == isLoadingMore ? _self.isLoadingMore : isLoadingMore // ignore: cast_nullable_to_non_nullable
as bool,hasLoaded: null == hasLoaded ? _self.hasLoaded : hasLoaded // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
/// Adds pattern-matching-related methods to [VoucherRedemptionLoaderState].
extension VoucherRedemptionLoaderStatePatterns on VoucherRedemptionLoaderState {
/// A variant of `map` that fallback to returning `orElse`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _VoucherRedemptionLoaderState value)? $default,{required TResult orElse(),}){
final _that = this;
switch (_that) {
case _VoucherRedemptionLoaderState() when $default != null:
return $default(_that);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// Callbacks receives the raw object, upcasted.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case final Subclass2 value:
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _VoucherRedemptionLoaderState value) $default,){
final _that = this;
switch (_that) {
case _VoucherRedemptionLoaderState():
return $default(_that);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `map` that fallback to returning `null`.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case final Subclass value:
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _VoucherRedemptionLoaderState value)? $default,){
final _that = this;
switch (_that) {
case _VoucherRedemptionLoaderState() when $default != null:
return $default(_that);case _:
return null;
}
}
/// A variant of `when` that fallback to an `orElse` callback.
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return orElse();
/// }
/// ```
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( List<VoucherRedemption> items, int page, int totalPages, Option<WalletFailure> failureOption, bool isFetching, bool isLoadingMore, bool hasLoaded)? $default,{required TResult orElse(),}) {final _that = this;
switch (_that) {
case _VoucherRedemptionLoaderState() when $default != null:
return $default(_that.items,_that.page,_that.totalPages,_that.failureOption,_that.isFetching,_that.isLoadingMore,_that.hasLoaded);case _:
return orElse();
}
}
/// A `switch`-like method, using callbacks.
///
/// As opposed to `map`, this offers destructuring.
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case Subclass2(:final field2):
/// return ...;
/// }
/// ```
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( List<VoucherRedemption> items, int page, int totalPages, Option<WalletFailure> failureOption, bool isFetching, bool isLoadingMore, bool hasLoaded) $default,) {final _that = this;
switch (_that) {
case _VoucherRedemptionLoaderState():
return $default(_that.items,_that.page,_that.totalPages,_that.failureOption,_that.isFetching,_that.isLoadingMore,_that.hasLoaded);case _:
throw StateError('Unexpected subclass');
}
}
/// A variant of `when` that fallback to returning `null`
///
/// It is equivalent to doing:
/// ```dart
/// switch (sealedClass) {
/// case Subclass(:final field):
/// return ...;
/// case _:
/// return null;
/// }
/// ```
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( List<VoucherRedemption> items, int page, int totalPages, Option<WalletFailure> failureOption, bool isFetching, bool isLoadingMore, bool hasLoaded)? $default,) {final _that = this;
switch (_that) {
case _VoucherRedemptionLoaderState() when $default != null:
return $default(_that.items,_that.page,_that.totalPages,_that.failureOption,_that.isFetching,_that.isLoadingMore,_that.hasLoaded);case _:
return null;
}
}
}
/// @nodoc
class _VoucherRedemptionLoaderState extends VoucherRedemptionLoaderState {
const _VoucherRedemptionLoaderState({required List<VoucherRedemption> items, required this.page, required this.totalPages, required this.failureOption, this.isFetching = false, this.isLoadingMore = false, this.hasLoaded = false}): _items = items,super._();
final List<VoucherRedemption> _items;
@override List<VoucherRedemption> get items {
if (_items is EqualUnmodifiableListView) return _items;
// ignore: implicit_dynamic_type
return EqualUnmodifiableListView(_items);
}
@override final int page;
@override final int totalPages;
@override final Option<WalletFailure> failureOption;
@override@JsonKey() final bool isFetching;
@override@JsonKey() final bool isLoadingMore;
@override@JsonKey() final bool hasLoaded;
/// Create a copy of VoucherRedemptionLoaderState
/// with the given fields replaced by the non-null parameter values.
@override @JsonKey(includeFromJson: false, includeToJson: false)
@pragma('vm:prefer-inline')
_$VoucherRedemptionLoaderStateCopyWith<_VoucherRedemptionLoaderState> get copyWith => __$VoucherRedemptionLoaderStateCopyWithImpl<_VoucherRedemptionLoaderState>(this, _$identity);
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _VoucherRedemptionLoaderState&&const DeepCollectionEquality().equals(other.items, _items)&&(identical(other.page, page) || other.page == page)&&(identical(other.totalPages, totalPages) || other.totalPages == totalPages)&&(identical(other.failureOption, failureOption) || other.failureOption == failureOption)&&(identical(other.isFetching, isFetching) || other.isFetching == isFetching)&&(identical(other.isLoadingMore, isLoadingMore) || other.isLoadingMore == isLoadingMore)&&(identical(other.hasLoaded, hasLoaded) || other.hasLoaded == hasLoaded));
}
@override
int get hashCode {
return Object.hash(runtimeType,const DeepCollectionEquality().hash(_items),page,totalPages,failureOption,isFetching,isLoadingMore,hasLoaded);
}
@override
String toString() {
return 'VoucherRedemptionLoaderState(items: $items, page: $page, totalPages: $totalPages, failureOption: $failureOption, isFetching: $isFetching, isLoadingMore: $isLoadingMore, hasLoaded: $hasLoaded)';
}
}
/// @nodoc
abstract mixin class _$VoucherRedemptionLoaderStateCopyWith<$Res> implements $VoucherRedemptionLoaderStateCopyWith<$Res> {
factory _$VoucherRedemptionLoaderStateCopyWith(_VoucherRedemptionLoaderState value, $Res Function(_VoucherRedemptionLoaderState) _then) = __$VoucherRedemptionLoaderStateCopyWithImpl;
@override @useResult
$Res call({
List<VoucherRedemption> items, int page, int totalPages, Option<WalletFailure> failureOption, bool isFetching, bool isLoadingMore, bool hasLoaded
});
}
/// @nodoc
class __$VoucherRedemptionLoaderStateCopyWithImpl<$Res>
implements _$VoucherRedemptionLoaderStateCopyWith<$Res> {
__$VoucherRedemptionLoaderStateCopyWithImpl(this._self, this._then);
final _VoucherRedemptionLoaderState _self;
final $Res Function(_VoucherRedemptionLoaderState) _then;
/// Create a copy of VoucherRedemptionLoaderState
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? items = null,Object? page = null,Object? totalPages = null,Object? failureOption = null,Object? isFetching = null,Object? isLoadingMore = null,Object? hasLoaded = null,}) {
return _then(_VoucherRedemptionLoaderState(
items: null == items ? _self._items : items // ignore: cast_nullable_to_non_nullable
as List<VoucherRedemption>,page: null == page ? _self.page : page // ignore: cast_nullable_to_non_nullable
as int,totalPages: null == totalPages ? _self.totalPages : totalPages // ignore: cast_nullable_to_non_nullable
as int,failureOption: null == failureOption ? _self.failureOption : failureOption // ignore: cast_nullable_to_non_nullable
as Option<WalletFailure>,isFetching: null == isFetching ? _self.isFetching : isFetching // ignore: cast_nullable_to_non_nullable
as bool,isLoadingMore: null == isLoadingMore ? _self.isLoadingMore : isLoadingMore // ignore: cast_nullable_to_non_nullable
as bool,hasLoaded: null == hasLoaded ? _self.hasLoaded : hasLoaded // ignore: cast_nullable_to_non_nullable
as bool,
));
}
}
// dart format on
@@ -0,0 +1,10 @@
part of 'voucher_redemption_loader_bloc.dart';
@freezed
abstract class VoucherRedemptionLoaderEvent
with _$VoucherRedemptionLoaderEvent {
/// Muat ulang dari halaman pertama.
const factory VoucherRedemptionLoaderEvent.refreshed() = _Refreshed;
const factory VoucherRedemptionLoaderEvent.loadedMore() = _LoadedMore;
}
@@ -0,0 +1,27 @@
part of 'voucher_redemption_loader_bloc.dart';
@freezed
abstract class VoucherRedemptionLoaderState
with _$VoucherRedemptionLoaderState {
const VoucherRedemptionLoaderState._();
const factory VoucherRedemptionLoaderState({
required List<VoucherRedemption> items,
required int page,
required int totalPages,
required Option<WalletFailure> failureOption,
@Default(false) bool isFetching,
@Default(false) bool isLoadingMore,
@Default(false) bool hasLoaded,
}) = _VoucherRedemptionLoaderState;
factory VoucherRedemptionLoaderState.initial() =>
VoucherRedemptionLoaderState(
items: const [],
page: 0,
totalPages: 0,
failureOption: none(),
);
bool get hasMore => page < totalPages;
}