Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0693411cf7 | ||
|
|
a514a8abdb | ||
|
|
a6e58a8cc0 | ||
|
|
59d4d4c0e5 | ||
|
|
137f3d9636 | ||
|
|
37f0008ec8 | ||
|
|
34555dd789 | ||
|
|
8bd61eb58e | ||
|
|
b8eefcbac0 | ||
|
|
9e5a6cc7ae | ||
|
|
3135dde317 | ||
|
|
e8fd683077 | ||
|
|
08bbfc393b | ||
|
|
8fec9c8cd0 | ||
|
|
0bffd92a08 | ||
|
|
5c683eda8d | ||
|
|
d5ed3f62ff | ||
|
|
634b331716 | ||
|
|
655902a659 | ||
|
|
0e83d213fc | ||
|
|
013f313e35 | ||
|
|
e85138f27e | ||
|
|
9c38d001d1 | ||
|
|
9243e0948b | ||
|
|
754048b565 | ||
|
|
7bcf54c555 | ||
|
|
79e109cfe4 | ||
|
|
6892895021 | ||
|
|
4fdd1e44f8 | ||
|
|
dea5de8828 | ||
|
|
71fa4823fc | ||
|
|
683fff6eeb | ||
|
|
13b1b6e6b8 | ||
|
|
4dbdcadeaf | ||
|
|
97c03bcf96 | ||
|
|
05609d592d | ||
|
|
59062f9af1 | ||
|
|
ca5d2a58e7 | ||
|
|
5d9197c986 | ||
|
|
9a61cbecc4 | ||
|
|
cf8f0b373d | ||
|
|
4fee7c4bb7 |
@@ -1,28 +1,20 @@
|
||||
# This file configures the analyzer, which statically analyzes Dart code to
|
||||
# check for errors, warnings, and lints.
|
||||
#
|
||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
||||
# invoked from the command line by running `flutter analyze`.
|
||||
|
||||
# The following line activates a set of recommended lints for Flutter apps,
|
||||
# packages, and plugins designed to encourage good coding practices.
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
linter:
|
||||
# The lint rules applied to this project can be customized in the
|
||||
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
|
||||
# included above or to enable additional rules. A list of all available lints
|
||||
# and their documentation is published at https://dart.dev/lints.
|
||||
#
|
||||
# Instead of disabling a lint rule for the entire project in the
|
||||
# section below, it can also be suppressed for a single line of code
|
||||
# or a specific dart file by using the `// ignore: name_of_lint` and
|
||||
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
|
||||
# producing the lint.
|
||||
rules:
|
||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
||||
sort_pub_dependencies: false
|
||||
prefer_relative_imports: true
|
||||
|
||||
# Additional information about this file can be found at
|
||||
# https://dart.dev/guides/language/analysis-options
|
||||
analyzer:
|
||||
errors:
|
||||
missing_required_param: error
|
||||
missing_return: error
|
||||
must_be_immutable: error
|
||||
sort_unnamed_constructors_first: ignore
|
||||
invalid_annotation_target: ignore
|
||||
use_build_context_synchronously: ignore
|
||||
deprecated_member_use: ignore
|
||||
exclude:
|
||||
- test/generated/**
|
||||
- "**/**.g.dart"
|
||||
- "**/**.freezed.dart"
|
||||
|
||||
@@ -3,10 +3,11 @@ plugins {
|
||||
id("kotlin-android")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
id("com.google.gms.google-services")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.apskel_pos_flutter_v2"
|
||||
namespace = "com.apskel.pos"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
@@ -21,7 +22,7 @@ android {
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "com.example.apskel_pos_flutter_v2"
|
||||
applicationId = "com.apskel.pos"
|
||||
// You can update the following values to match your application needs.
|
||||
// For more information, see: https://flutter.dev/to/review-gradle-config.
|
||||
minSdk = flutter.minSdkVersion
|
||||
@@ -42,3 +43,10 @@ android {
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Import the Firebase BoM
|
||||
implementation(platform("com.google.firebase:firebase-bom:34.4.0"))
|
||||
|
||||
implementation("com.google.firebase:firebase-analytics")
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "765730035527",
|
||||
"project_id": "apskel-pos-v2",
|
||||
"storage_bucket": "apskel-pos-v2.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:765730035527:android:498defd7071336dd241e62",
|
||||
"android_client_info": {
|
||||
"package_name": "com.apskel.pos"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAOZwVSQwUeeM9BjcyTOK9GUh8AmTWucuc"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@@ -1,8 +1,19 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
|
||||
<!-- Izin khusus untuk akses foto (media images) di Android 33 ke atas -->
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<application
|
||||
android:label="apskel_pos_flutter_v2"
|
||||
android:label="Apskel POS"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
android:icon="@mipmap/launcher_icon">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.apskel_pos_flutter_v2
|
||||
package com.apskel.pos
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 8.2 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 19 KiB |
@@ -20,6 +20,7 @@ plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "8.7.3" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
|
||||
id("com.google.gms.google-services") version "4.4.4" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
|
||||
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 135 KiB |
|
After Width: | Height: | Size: 79 KiB |
|
After Width: | Height: | Size: 125 KiB |
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
|
||||
#include "Generated.xcconfig"
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '13.0'
|
||||
|
||||
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
|
||||
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
|
||||
|
||||
project 'Runner', {
|
||||
'Debug' => :debug,
|
||||
'Profile' => :release,
|
||||
'Release' => :release,
|
||||
}
|
||||
|
||||
def flutter_root
|
||||
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
|
||||
File.foreach(generated_xcode_build_settings_path) do |line|
|
||||
matches = line.match(/FLUTTER_ROOT\=(.*)/)
|
||||
return matches[1].strip if matches
|
||||
end
|
||||
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
|
||||
end
|
||||
|
||||
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
|
||||
|
||||
flutter_ios_podfile_setup
|
||||
|
||||
target 'Runner' do
|
||||
use_frameworks!
|
||||
|
||||
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
|
||||
target 'RunnerTests' do
|
||||
inherit! :search_paths
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
flutter_additional_ios_build_settings(target)
|
||||
end
|
||||
end
|
||||
@@ -427,7 +427,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
@@ -484,7 +484,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
|
||||
@@ -1,122 +1 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-20x20@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-29x29@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-40x40@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "60x60",
|
||||
"idiom" : "iphone",
|
||||
"filename" : "Icon-App-60x60@3x.png",
|
||||
"scale" : "3x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "20x20",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-20x20@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "29x29",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-29x29@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "40x40",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-40x40@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@1x.png",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"size" : "76x76",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-76x76@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "83.5x83.5",
|
||||
"idiom" : "ipad",
|
||||
"filename" : "Icon-App-83.5x83.5@2x.png",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"size" : "1024x1024",
|
||||
"idiom" : "ios-marketing",
|
||||
"filename" : "Icon-App-1024x1024@1x.png",
|
||||
"scale" : "1x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
|
||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 150 KiB |
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 678 B |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 450 B After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 282 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 462 B After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 704 B After Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 406 B After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 586 B After Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 862 B After Width: | Height: | Size: 9.8 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 762 B After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 15 KiB |
@@ -0,0 +1,15 @@
|
||||
# Generate: dart run flutter_launcher_icons -f launcher_icon.yaml
|
||||
|
||||
flutter_launcher_icons:
|
||||
android: "launcher_icon"
|
||||
ios: true
|
||||
image_path: "assets/images/logo.png"
|
||||
remove_alpha_ios: true
|
||||
min_sdk_android: 21 # android min sdk min:16, default 21
|
||||
web:
|
||||
generate: true
|
||||
image_path: "assets/images/logo.png"
|
||||
windows:
|
||||
generate: true
|
||||
image_path: "assets/images/logo.png"
|
||||
icon_size: 48
|
||||
@@ -0,0 +1,66 @@
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../domain/auth/auth.dart';
|
||||
import '../../domain/outlet/outlet.dart';
|
||||
|
||||
part 'auth_event.dart';
|
||||
part 'auth_state.dart';
|
||||
part 'auth_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
final IAuthRepository _repository;
|
||||
final IOutletRepository _outletRepository;
|
||||
AuthBloc(this._repository, this._outletRepository)
|
||||
: super(AuthState.initial()) {
|
||||
on<AuthEvent>(_onAuthEvent);
|
||||
}
|
||||
|
||||
Future<void> _onAuthEvent(AuthEvent event, Emitter<AuthState> emit) {
|
||||
return event.map(
|
||||
fetchCurrentUser: (e) async {
|
||||
emit(state.copyWith(failureOption: none()));
|
||||
|
||||
final token = await _repository.hasToken();
|
||||
|
||||
final failureOrAuth = await _repository.currentUser();
|
||||
|
||||
failureOrAuth.fold(
|
||||
(f) => emit(
|
||||
state.copyWith(
|
||||
failureOption: optionOf(f),
|
||||
status: token
|
||||
? AuthStatus.authenticated()
|
||||
: AuthStatus.unauthenticated(),
|
||||
),
|
||||
),
|
||||
(user) => emit(
|
||||
state.copyWith(
|
||||
user: user,
|
||||
status: token
|
||||
? AuthStatus.authenticated()
|
||||
: AuthStatus.unauthenticated(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
add(AuthEvent.fetchCurrentOutlet(state.user.outletId));
|
||||
},
|
||||
fetchCurrentOutlet: (e) async {
|
||||
emit(state.copyWith(failureOutletOption: none()));
|
||||
|
||||
final failureOrOutlet = await _outletRepository.getOutletById(
|
||||
e.outletId,
|
||||
);
|
||||
|
||||
failureOrOutlet.fold(
|
||||
(f) => emit(state.copyWith(failureOutletOption: optionOf(f))),
|
||||
(outlet) => emit(state.copyWith(outlet: outlet)),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class AuthEvent with _$AuthEvent {
|
||||
const factory AuthEvent.fetchCurrentUser() = _FetchCurrentUser;
|
||||
const factory AuthEvent.fetchCurrentOutlet(String outletId) =
|
||||
_FetchCurrentOutlet;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
part of 'auth_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class AuthState with _$AuthState {
|
||||
const AuthState._();
|
||||
|
||||
const factory AuthState({
|
||||
required User user,
|
||||
required Outlet outlet,
|
||||
@Default(AuthStatus.initial()) AuthStatus status,
|
||||
required Option<AuthFailure> failureOption,
|
||||
required Option<OutletFailure> failureOutletOption,
|
||||
@Default(false) bool isFetching,
|
||||
@Default(false) bool isFetchingOutlet,
|
||||
}) = _AuthState;
|
||||
|
||||
factory AuthState.initial() => AuthState(
|
||||
user: User.empty(),
|
||||
failureOption: none(),
|
||||
outlet: Outlet.empty(),
|
||||
failureOutletOption: none(),
|
||||
);
|
||||
|
||||
bool get isAuthenticated => status == const AuthStatus.authenticated();
|
||||
bool get isInitial => status == const AuthStatus.initial();
|
||||
}
|
||||
|
||||
@freezed
|
||||
sealed class AuthStatus with _$AuthStatus {
|
||||
const factory AuthStatus.authenticated() = _Authenticated;
|
||||
const factory AuthStatus.unauthenticated() = _Unauthenticated;
|
||||
const factory AuthStatus.initial() = _Initial;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/auth/auth.dart';
|
||||
|
||||
part 'login_form_event.dart';
|
||||
part 'login_form_state.dart';
|
||||
part 'login_form_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
|
||||
final IAuthRepository _authRepository;
|
||||
LoginFormBloc(this._authRepository) : super(LoginFormState.initial()) {
|
||||
on<LoginFormEvent>(_onLoginFormEvent);
|
||||
}
|
||||
|
||||
Future<void> _onLoginFormEvent(
|
||||
LoginFormEvent event,
|
||||
Emitter<LoginFormState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
emailChanged: (e) async {
|
||||
emit(state.copyWith(email: e.email, failureOrLoginOption: none()));
|
||||
},
|
||||
passwordChanged: (e) async {
|
||||
emit(
|
||||
state.copyWith(password: e.password, failureOrLoginOption: none()),
|
||||
);
|
||||
},
|
||||
submitted: (e) async {
|
||||
Either<AuthFailure, Login>? failureOrLogin;
|
||||
emit(state.copyWith(isSubmitting: true, failureOrLoginOption: none()));
|
||||
|
||||
final emailValid = state.email.isNotEmpty;
|
||||
final passwordValid = state.password.isNotEmpty;
|
||||
|
||||
log(
|
||||
'emailValid: $emailValid, passwordValid: $passwordValid, email: ${state.email}, password: ${state.password}',
|
||||
);
|
||||
|
||||
if (emailValid && passwordValid) {
|
||||
failureOrLogin = await _authRepository.login(
|
||||
email: state.email,
|
||||
password: state.password,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSubmitting: false,
|
||||
failureOrLoginOption: optionOf(failureOrLogin),
|
||||
),
|
||||
);
|
||||
}
|
||||
emit(state.copyWith(showErrorMessages: true, isSubmitting: false));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,734 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// 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 'login_form_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LoginFormEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(String email) emailChanged,
|
||||
required TResult Function(String password) passwordChanged,
|
||||
required TResult Function() submitted,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(String email)? emailChanged,
|
||||
TResult? Function(String password)? passwordChanged,
|
||||
TResult? Function()? submitted,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(String email)? emailChanged,
|
||||
TResult Function(String password)? passwordChanged,
|
||||
TResult Function()? submitted,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_EmailChanged value) emailChanged,
|
||||
required TResult Function(_PasswordChanged value) passwordChanged,
|
||||
required TResult Function(_Submitted value) submitted,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_EmailChanged value)? emailChanged,
|
||||
TResult? Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult? Function(_Submitted value)? submitted,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_EmailChanged value)? emailChanged,
|
||||
TResult Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult Function(_Submitted value)? submitted,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LoginFormEventCopyWith<$Res> {
|
||||
factory $LoginFormEventCopyWith(
|
||||
LoginFormEvent value,
|
||||
$Res Function(LoginFormEvent) then,
|
||||
) = _$LoginFormEventCopyWithImpl<$Res, LoginFormEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LoginFormEventCopyWithImpl<$Res, $Val extends LoginFormEvent>
|
||||
implements $LoginFormEventCopyWith<$Res> {
|
||||
_$LoginFormEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$EmailChangedImplCopyWith<$Res> {
|
||||
factory _$$EmailChangedImplCopyWith(
|
||||
_$EmailChangedImpl value,
|
||||
$Res Function(_$EmailChangedImpl) then,
|
||||
) = __$$EmailChangedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String email});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$EmailChangedImplCopyWithImpl<$Res>
|
||||
extends _$LoginFormEventCopyWithImpl<$Res, _$EmailChangedImpl>
|
||||
implements _$$EmailChangedImplCopyWith<$Res> {
|
||||
__$$EmailChangedImplCopyWithImpl(
|
||||
_$EmailChangedImpl _value,
|
||||
$Res Function(_$EmailChangedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? email = null}) {
|
||||
return _then(
|
||||
_$EmailChangedImpl(
|
||||
null == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$EmailChangedImpl implements _EmailChanged {
|
||||
const _$EmailChangedImpl(this.email);
|
||||
|
||||
@override
|
||||
final String email;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoginFormEvent.emailChanged(email: $email)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$EmailChangedImpl &&
|
||||
(identical(other.email, email) || other.email == email));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, email);
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$EmailChangedImplCopyWith<_$EmailChangedImpl> get copyWith =>
|
||||
__$$EmailChangedImplCopyWithImpl<_$EmailChangedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(String email) emailChanged,
|
||||
required TResult Function(String password) passwordChanged,
|
||||
required TResult Function() submitted,
|
||||
}) {
|
||||
return emailChanged(email);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(String email)? emailChanged,
|
||||
TResult? Function(String password)? passwordChanged,
|
||||
TResult? Function()? submitted,
|
||||
}) {
|
||||
return emailChanged?.call(email);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(String email)? emailChanged,
|
||||
TResult Function(String password)? passwordChanged,
|
||||
TResult Function()? submitted,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (emailChanged != null) {
|
||||
return emailChanged(email);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_EmailChanged value) emailChanged,
|
||||
required TResult Function(_PasswordChanged value) passwordChanged,
|
||||
required TResult Function(_Submitted value) submitted,
|
||||
}) {
|
||||
return emailChanged(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_EmailChanged value)? emailChanged,
|
||||
TResult? Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult? Function(_Submitted value)? submitted,
|
||||
}) {
|
||||
return emailChanged?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_EmailChanged value)? emailChanged,
|
||||
TResult Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult Function(_Submitted value)? submitted,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (emailChanged != null) {
|
||||
return emailChanged(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _EmailChanged implements LoginFormEvent {
|
||||
const factory _EmailChanged(final String email) = _$EmailChangedImpl;
|
||||
|
||||
String get email;
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$EmailChangedImplCopyWith<_$EmailChangedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$PasswordChangedImplCopyWith<$Res> {
|
||||
factory _$$PasswordChangedImplCopyWith(
|
||||
_$PasswordChangedImpl value,
|
||||
$Res Function(_$PasswordChangedImpl) then,
|
||||
) = __$$PasswordChangedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String password});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$PasswordChangedImplCopyWithImpl<$Res>
|
||||
extends _$LoginFormEventCopyWithImpl<$Res, _$PasswordChangedImpl>
|
||||
implements _$$PasswordChangedImplCopyWith<$Res> {
|
||||
__$$PasswordChangedImplCopyWithImpl(
|
||||
_$PasswordChangedImpl _value,
|
||||
$Res Function(_$PasswordChangedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? password = null}) {
|
||||
return _then(
|
||||
_$PasswordChangedImpl(
|
||||
null == password
|
||||
? _value.password
|
||||
: password // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$PasswordChangedImpl implements _PasswordChanged {
|
||||
const _$PasswordChangedImpl(this.password);
|
||||
|
||||
@override
|
||||
final String password;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoginFormEvent.passwordChanged(password: $password)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PasswordChangedImpl &&
|
||||
(identical(other.password, password) ||
|
||||
other.password == password));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, password);
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PasswordChangedImplCopyWith<_$PasswordChangedImpl> get copyWith =>
|
||||
__$$PasswordChangedImplCopyWithImpl<_$PasswordChangedImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(String email) emailChanged,
|
||||
required TResult Function(String password) passwordChanged,
|
||||
required TResult Function() submitted,
|
||||
}) {
|
||||
return passwordChanged(password);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(String email)? emailChanged,
|
||||
TResult? Function(String password)? passwordChanged,
|
||||
TResult? Function()? submitted,
|
||||
}) {
|
||||
return passwordChanged?.call(password);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(String email)? emailChanged,
|
||||
TResult Function(String password)? passwordChanged,
|
||||
TResult Function()? submitted,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (passwordChanged != null) {
|
||||
return passwordChanged(password);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_EmailChanged value) emailChanged,
|
||||
required TResult Function(_PasswordChanged value) passwordChanged,
|
||||
required TResult Function(_Submitted value) submitted,
|
||||
}) {
|
||||
return passwordChanged(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_EmailChanged value)? emailChanged,
|
||||
TResult? Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult? Function(_Submitted value)? submitted,
|
||||
}) {
|
||||
return passwordChanged?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_EmailChanged value)? emailChanged,
|
||||
TResult Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult Function(_Submitted value)? submitted,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (passwordChanged != null) {
|
||||
return passwordChanged(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _PasswordChanged implements LoginFormEvent {
|
||||
const factory _PasswordChanged(final String password) = _$PasswordChangedImpl;
|
||||
|
||||
String get password;
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PasswordChangedImplCopyWith<_$PasswordChangedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SubmittedImplCopyWith<$Res> {
|
||||
factory _$$SubmittedImplCopyWith(
|
||||
_$SubmittedImpl value,
|
||||
$Res Function(_$SubmittedImpl) then,
|
||||
) = __$$SubmittedImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SubmittedImplCopyWithImpl<$Res>
|
||||
extends _$LoginFormEventCopyWithImpl<$Res, _$SubmittedImpl>
|
||||
implements _$$SubmittedImplCopyWith<$Res> {
|
||||
__$$SubmittedImplCopyWithImpl(
|
||||
_$SubmittedImpl _value,
|
||||
$Res Function(_$SubmittedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of LoginFormEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SubmittedImpl implements _Submitted {
|
||||
const _$SubmittedImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoginFormEvent.submitted()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$SubmittedImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(String email) emailChanged,
|
||||
required TResult Function(String password) passwordChanged,
|
||||
required TResult Function() submitted,
|
||||
}) {
|
||||
return submitted();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(String email)? emailChanged,
|
||||
TResult? Function(String password)? passwordChanged,
|
||||
TResult? Function()? submitted,
|
||||
}) {
|
||||
return submitted?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(String email)? emailChanged,
|
||||
TResult Function(String password)? passwordChanged,
|
||||
TResult Function()? submitted,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (submitted != null) {
|
||||
return submitted();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_EmailChanged value) emailChanged,
|
||||
required TResult Function(_PasswordChanged value) passwordChanged,
|
||||
required TResult Function(_Submitted value) submitted,
|
||||
}) {
|
||||
return submitted(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_EmailChanged value)? emailChanged,
|
||||
TResult? Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult? Function(_Submitted value)? submitted,
|
||||
}) {
|
||||
return submitted?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_EmailChanged value)? emailChanged,
|
||||
TResult Function(_PasswordChanged value)? passwordChanged,
|
||||
TResult Function(_Submitted value)? submitted,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (submitted != null) {
|
||||
return submitted(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Submitted implements LoginFormEvent {
|
||||
const factory _Submitted() = _$SubmittedImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$LoginFormState {
|
||||
String get email => throw _privateConstructorUsedError;
|
||||
String get password => throw _privateConstructorUsedError;
|
||||
Option<Either<AuthFailure, Login>> get failureOrLoginOption =>
|
||||
throw _privateConstructorUsedError;
|
||||
bool get isSubmitting => throw _privateConstructorUsedError;
|
||||
bool get showErrorMessages => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of LoginFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$LoginFormStateCopyWith<LoginFormState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $LoginFormStateCopyWith<$Res> {
|
||||
factory $LoginFormStateCopyWith(
|
||||
LoginFormState value,
|
||||
$Res Function(LoginFormState) then,
|
||||
) = _$LoginFormStateCopyWithImpl<$Res, LoginFormState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
String email,
|
||||
String password,
|
||||
Option<Either<AuthFailure, Login>> failureOrLoginOption,
|
||||
bool isSubmitting,
|
||||
bool showErrorMessages,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$LoginFormStateCopyWithImpl<$Res, $Val extends LoginFormState>
|
||||
implements $LoginFormStateCopyWith<$Res> {
|
||||
_$LoginFormStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of LoginFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? email = null,
|
||||
Object? password = null,
|
||||
Object? failureOrLoginOption = null,
|
||||
Object? isSubmitting = null,
|
||||
Object? showErrorMessages = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
email: null == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
password: null == password
|
||||
? _value.password
|
||||
: password // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
failureOrLoginOption: null == failureOrLoginOption
|
||||
? _value.failureOrLoginOption
|
||||
: failureOrLoginOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<Either<AuthFailure, Login>>,
|
||||
isSubmitting: null == isSubmitting
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
showErrorMessages: null == showErrorMessages
|
||||
? _value.showErrorMessages
|
||||
: showErrorMessages // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$LoginFormStateImplCopyWith<$Res>
|
||||
implements $LoginFormStateCopyWith<$Res> {
|
||||
factory _$$LoginFormStateImplCopyWith(
|
||||
_$LoginFormStateImpl value,
|
||||
$Res Function(_$LoginFormStateImpl) then,
|
||||
) = __$$LoginFormStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
String email,
|
||||
String password,
|
||||
Option<Either<AuthFailure, Login>> failureOrLoginOption,
|
||||
bool isSubmitting,
|
||||
bool showErrorMessages,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$LoginFormStateImplCopyWithImpl<$Res>
|
||||
extends _$LoginFormStateCopyWithImpl<$Res, _$LoginFormStateImpl>
|
||||
implements _$$LoginFormStateImplCopyWith<$Res> {
|
||||
__$$LoginFormStateImplCopyWithImpl(
|
||||
_$LoginFormStateImpl _value,
|
||||
$Res Function(_$LoginFormStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of LoginFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? email = null,
|
||||
Object? password = null,
|
||||
Object? failureOrLoginOption = null,
|
||||
Object? isSubmitting = null,
|
||||
Object? showErrorMessages = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$LoginFormStateImpl(
|
||||
email: null == email
|
||||
? _value.email
|
||||
: email // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
password: null == password
|
||||
? _value.password
|
||||
: password // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
failureOrLoginOption: null == failureOrLoginOption
|
||||
? _value.failureOrLoginOption
|
||||
: failureOrLoginOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<Either<AuthFailure, Login>>,
|
||||
isSubmitting: null == isSubmitting
|
||||
? _value.isSubmitting
|
||||
: isSubmitting // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
showErrorMessages: null == showErrorMessages
|
||||
? _value.showErrorMessages
|
||||
: showErrorMessages // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$LoginFormStateImpl implements _LoginFormState {
|
||||
const _$LoginFormStateImpl({
|
||||
required this.email,
|
||||
required this.password,
|
||||
required this.failureOrLoginOption,
|
||||
this.isSubmitting = false,
|
||||
this.showErrorMessages = false,
|
||||
});
|
||||
|
||||
@override
|
||||
final String email;
|
||||
@override
|
||||
final String password;
|
||||
@override
|
||||
final Option<Either<AuthFailure, Login>> failureOrLoginOption;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isSubmitting;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool showErrorMessages;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'LoginFormState(email: $email, password: $password, failureOrLoginOption: $failureOrLoginOption, isSubmitting: $isSubmitting, showErrorMessages: $showErrorMessages)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$LoginFormStateImpl &&
|
||||
(identical(other.email, email) || other.email == email) &&
|
||||
(identical(other.password, password) ||
|
||||
other.password == password) &&
|
||||
(identical(other.failureOrLoginOption, failureOrLoginOption) ||
|
||||
other.failureOrLoginOption == failureOrLoginOption) &&
|
||||
(identical(other.isSubmitting, isSubmitting) ||
|
||||
other.isSubmitting == isSubmitting) &&
|
||||
(identical(other.showErrorMessages, showErrorMessages) ||
|
||||
other.showErrorMessages == showErrorMessages));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
email,
|
||||
password,
|
||||
failureOrLoginOption,
|
||||
isSubmitting,
|
||||
showErrorMessages,
|
||||
);
|
||||
|
||||
/// Create a copy of LoginFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$LoginFormStateImplCopyWith<_$LoginFormStateImpl> get copyWith =>
|
||||
__$$LoginFormStateImplCopyWithImpl<_$LoginFormStateImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class _LoginFormState implements LoginFormState {
|
||||
const factory _LoginFormState({
|
||||
required final String email,
|
||||
required final String password,
|
||||
required final Option<Either<AuthFailure, Login>> failureOrLoginOption,
|
||||
final bool isSubmitting,
|
||||
final bool showErrorMessages,
|
||||
}) = _$LoginFormStateImpl;
|
||||
|
||||
@override
|
||||
String get email;
|
||||
@override
|
||||
String get password;
|
||||
@override
|
||||
Option<Either<AuthFailure, Login>> get failureOrLoginOption;
|
||||
@override
|
||||
bool get isSubmitting;
|
||||
@override
|
||||
bool get showErrorMessages;
|
||||
|
||||
/// Create a copy of LoginFormState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$LoginFormStateImplCopyWith<_$LoginFormStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
part of 'login_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class LoginFormEvent with _$LoginFormEvent {
|
||||
const factory LoginFormEvent.emailChanged(String email) = _EmailChanged;
|
||||
const factory LoginFormEvent.passwordChanged(String password) =
|
||||
_PasswordChanged;
|
||||
const factory LoginFormEvent.submitted() = _Submitted;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
part of 'login_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class LoginFormState with _$LoginFormState {
|
||||
const factory LoginFormState({
|
||||
required String email,
|
||||
required String password,
|
||||
required Option<Either<AuthFailure, Login>> failureOrLoginOption,
|
||||
@Default(false) bool isSubmitting,
|
||||
@Default(false) bool showErrorMessages,
|
||||
}) = _LoginFormState;
|
||||
|
||||
factory LoginFormState.initial() =>
|
||||
LoginFormState(email: '', password: '', failureOrLoginOption: none());
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/category/category.dart';
|
||||
|
||||
part 'category_loader_event.dart';
|
||||
part 'category_loader_state.dart';
|
||||
part 'category_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class CategoryLoaderBloc
|
||||
extends Bloc<CategoryLoaderEvent, CategoryLoaderState> {
|
||||
final ICategoryRepository _categoryRepository;
|
||||
|
||||
Timer? _searchDebounce;
|
||||
bool _isLoadingMore = false;
|
||||
|
||||
CategoryLoaderBloc(this._categoryRepository)
|
||||
: super(CategoryLoaderState.initial()) {
|
||||
on<CategoryLoaderEvent>(_onCategoryLoaderEvent);
|
||||
}
|
||||
|
||||
Future<void> _onCategoryLoaderEvent(
|
||||
CategoryLoaderEvent event,
|
||||
Emitter<CategoryLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
getCategories: (e) async {
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
|
||||
log(
|
||||
'📱 Loading categories - isActive: ${e.isActive}, forceRemote: ${e.forceRemote}',
|
||||
);
|
||||
|
||||
final result = await _categoryRepository.getCategories(
|
||||
page: 1,
|
||||
limit: 50,
|
||||
isActive: e.isActive,
|
||||
search: e.search,
|
||||
forceRemote: e.forceRemote,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) async {
|
||||
final categories = [Category.all(), ...response.categories];
|
||||
|
||||
final totalPages = response.totalPages;
|
||||
final hasReachedMax = categories.length < 50 || 1 >= totalPages;
|
||||
|
||||
log(
|
||||
'✅ Categories loaded: ${categories.length}, hasReachedMax: $hasReachedMax',
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
categories: categories,
|
||||
page: 1,
|
||||
hasReachedMax: hasReachedMax,
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: none(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loadMore: (e) async {
|
||||
final currentState = state;
|
||||
|
||||
// ❌ HAPUS pengecekan is! _Loaded karena state cuma 1 class doang
|
||||
if (currentState.hasReachedMax ||
|
||||
_isLoadingMore ||
|
||||
currentState.isLoadingMore) {
|
||||
log(
|
||||
'⏹️ Load more blocked - hasReachedMax: ${currentState.hasReachedMax}, isLoadingMore: $_isLoadingMore',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
_isLoadingMore = true;
|
||||
emit(currentState.copyWith(isLoadingMore: true));
|
||||
|
||||
final nextPage = currentState.page + 1; // ✅ Ganti currentPage jadi page
|
||||
log('📄 Loading more categories - page: $nextPage');
|
||||
|
||||
try {
|
||||
final result = await _categoryRepository.getCategories(
|
||||
page: nextPage,
|
||||
limit: 10,
|
||||
isActive: true,
|
||||
search: currentState.searchQuery,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Error loading more categories: $failure');
|
||||
emit(currentState.copyWith(isLoadingMore: false));
|
||||
},
|
||||
(response) async {
|
||||
final newCategories = response.categories;
|
||||
final totalPages = response.totalPages;
|
||||
|
||||
// Prevent duplicate categories
|
||||
final currentCategoryIds = currentState.categories
|
||||
.map((c) => c.id)
|
||||
.toSet();
|
||||
final filteredNewCategories = newCategories
|
||||
.where(
|
||||
(category) => !currentCategoryIds.contains(category.id),
|
||||
)
|
||||
.toList();
|
||||
|
||||
final allCategories = List<Category>.from(currentState.categories)
|
||||
..addAll(filteredNewCategories);
|
||||
|
||||
final hasReachedMax =
|
||||
newCategories.length < 10 || nextPage >= totalPages;
|
||||
|
||||
log(
|
||||
'✅ More categories loaded: ${filteredNewCategories.length} new, total: ${allCategories.length}',
|
||||
);
|
||||
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
categories: allCategories,
|
||||
hasReachedMax: hasReachedMax,
|
||||
page: nextPage, // ✅ Update page
|
||||
isLoadingMore: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
log('❌ Exception loading more categories: $e');
|
||||
emit(currentState.copyWith(isLoadingMore: false));
|
||||
} finally {
|
||||
_isLoadingMore = false;
|
||||
}
|
||||
},
|
||||
refresh: (e) async {
|
||||
final currentState = state;
|
||||
bool isActive = true;
|
||||
String? searchQuery = currentState.searchQuery;
|
||||
|
||||
_isLoadingMore = false;
|
||||
_searchDebounce?.cancel();
|
||||
|
||||
log('🔄 Refreshing categories');
|
||||
|
||||
// Clear local cache
|
||||
_categoryRepository.clearCache();
|
||||
|
||||
add(
|
||||
CategoryLoaderEvent.getCategories(
|
||||
isActive: isActive,
|
||||
search: searchQuery,
|
||||
forceRemote: true, // Force remote refresh
|
||||
),
|
||||
);
|
||||
},
|
||||
search: (e) async {
|
||||
// Cancel previous search
|
||||
_searchDebounce?.cancel();
|
||||
|
||||
// Debounce search for better UX
|
||||
_searchDebounce = Timer(Duration(milliseconds: 300), () async {
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
_isLoadingMore = false;
|
||||
|
||||
log('🔍 Searching categories: "${e.query}"');
|
||||
|
||||
final result = await _categoryRepository.getCategories(
|
||||
page: 1,
|
||||
limit: 20, // More results for search
|
||||
isActive: e.isActive,
|
||||
search: e.query,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Search error: $failure');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) async {
|
||||
final categories = [Category.all(), ...response.categories];
|
||||
final totalPages = response.totalPages;
|
||||
final hasReachedMax = categories.length < 20 || 1 >= totalPages;
|
||||
|
||||
log('✅ Search results: ${categories.length} categories found');
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
categories: categories,
|
||||
hasReachedMax: hasReachedMax,
|
||||
page: 1,
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: none(),
|
||||
searchQuery: e.query,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
syncAll: (e) async {
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
|
||||
log('🔄 Starting full category sync...');
|
||||
|
||||
final result = await _categoryRepository.syncAllCategories();
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Sync failed: $failure');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: optionOf(failure),
|
||||
),
|
||||
);
|
||||
|
||||
// After sync error, try to load local data
|
||||
Timer(Duration(seconds: 2), () {
|
||||
add(const CategoryLoaderEvent.getCategories());
|
||||
});
|
||||
},
|
||||
(successMessage) async {
|
||||
log('✅ Sync completed: $successMessage');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: none(),
|
||||
),
|
||||
);
|
||||
|
||||
// After successful sync, load the updated data
|
||||
Timer(Duration(seconds: 1), () {
|
||||
add(const CategoryLoaderEvent.getCategories());
|
||||
});
|
||||
},
|
||||
);
|
||||
},
|
||||
getAllCategories: (e) async {
|
||||
try {
|
||||
log('📋 Loading all categories for dropdown...');
|
||||
|
||||
// final categories = await _categoryRepository.getAllCategories();
|
||||
|
||||
// emit(
|
||||
// state.copyWith(
|
||||
// categories: categories,
|
||||
// isLoadingMore: false,
|
||||
// failureOptionCategory: none(),
|
||||
// ),
|
||||
// );
|
||||
// log('✅ All categories loaded: ${categories.length}');
|
||||
} catch (e) {
|
||||
log('❌ Error loading all categories: $e');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionCategory: optionOf(
|
||||
CategoryFailure.dynamicErrorMessage(
|
||||
'Gagal memuat semua kategori: $e',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
getDatabaseStats: (e) async {
|
||||
try {
|
||||
final stats = await _categoryRepository.getDatabaseStats();
|
||||
log('📊 Category database stats retrieved: $stats');
|
||||
|
||||
// You can emit a special state here if needed for UI updates
|
||||
// For now, just log the stats
|
||||
} catch (e) {
|
||||
log('❌ Error getting category database stats: $e');
|
||||
}
|
||||
},
|
||||
clearCache: (e) async {
|
||||
log('🧹 Manually clearing category cache');
|
||||
_categoryRepository.clearCache();
|
||||
|
||||
// Refresh current data after cache clear
|
||||
add(const CategoryLoaderEvent.refresh());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_searchDebounce?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
part of 'category_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class CategoryLoaderEvent with _$CategoryLoaderEvent {
|
||||
const factory CategoryLoaderEvent.getCategories({
|
||||
@Default(true) bool isActive,
|
||||
String? search,
|
||||
@Default(false) bool forceRemote,
|
||||
}) = _GetCategories;
|
||||
|
||||
const factory CategoryLoaderEvent.loadMore() = _LoadMore;
|
||||
|
||||
const factory CategoryLoaderEvent.refresh() = _Refresh;
|
||||
|
||||
const factory CategoryLoaderEvent.search({
|
||||
required String query,
|
||||
@Default(true) bool isActive,
|
||||
}) = _Search;
|
||||
|
||||
const factory CategoryLoaderEvent.syncAll() = _SyncAll;
|
||||
|
||||
const factory CategoryLoaderEvent.getAllCategories() = _GetAllCategories;
|
||||
|
||||
const factory CategoryLoaderEvent.getDatabaseStats() = _GetDatabaseStats;
|
||||
|
||||
const factory CategoryLoaderEvent.clearCache() = _ClearCache;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
part of 'category_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class CategoryLoaderState with _$CategoryLoaderState {
|
||||
factory CategoryLoaderState({
|
||||
required List<Category> categories,
|
||||
required Option<CategoryFailure> failureOptionCategory,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
@Default(false) bool isLoadingMore,
|
||||
String? searchQuery,
|
||||
}) = _CategoryLoaderState;
|
||||
|
||||
factory CategoryLoaderState.initial() =>
|
||||
CategoryLoaderState(categories: [], failureOptionCategory: none());
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../common/types/order_type.dart';
|
||||
import '../../../domain/delivery/delivery.dart';
|
||||
import '../../../domain/product/product.dart';
|
||||
import '../../../domain/table/table.dart';
|
||||
|
||||
part 'checkout_form_event.dart';
|
||||
part 'checkout_form_state.dart';
|
||||
part 'checkout_form_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class CheckoutFormBloc extends Bloc<CheckoutFormEvent, CheckoutFormState> {
|
||||
CheckoutFormBloc() : super(CheckoutFormState.initial()) {
|
||||
on<CheckoutFormEvent>(_onCheckoutFormEvent);
|
||||
}
|
||||
Future<void> _onCheckoutFormEvent(
|
||||
CheckoutFormEvent event,
|
||||
Emitter<CheckoutFormState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
addItem: (e) async {
|
||||
final currentState = state;
|
||||
emit(currentState.copyWith(isLoading: true));
|
||||
|
||||
List<ProductQuantity> items = [...currentState.items];
|
||||
|
||||
final index = items.indexWhere(
|
||||
(element) =>
|
||||
element.product.id == e.product.id &&
|
||||
element.variant?.id == e.variant?.id,
|
||||
);
|
||||
|
||||
if (index != -1) {
|
||||
// Jika sudah ada → tambah quantity
|
||||
items[index] = items[index].copyWith(
|
||||
quantity: items[index].quantity + 1,
|
||||
);
|
||||
} else {
|
||||
// Jika belum ada → tambahkan item baru
|
||||
items.add(
|
||||
ProductQuantity(
|
||||
product: e.product,
|
||||
quantity: 1,
|
||||
variant: e.variant,
|
||||
notes: '',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
log('🛒 Items updated: ${items.length} items total ${items.toList()}');
|
||||
|
||||
final totalQuantity = items.fold<int>(
|
||||
0,
|
||||
(sum, item) => sum + item.quantity,
|
||||
);
|
||||
|
||||
final totalPrice = state.items.isEmpty
|
||||
? 0.0
|
||||
: state.items
|
||||
.map(
|
||||
(e) =>
|
||||
(e.product.price * e.quantity) +
|
||||
(e.variant?.priceModifier ?? 0),
|
||||
)
|
||||
.reduce((value, element) => value + element);
|
||||
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
items: items,
|
||||
totalQuantity: totalQuantity,
|
||||
totalPrice: totalPrice.toInt(),
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
removeItem: (e) async {
|
||||
final currentState = state;
|
||||
emit(currentState.copyWith(isLoading: true));
|
||||
List<ProductQuantity> items = [...currentState.items];
|
||||
|
||||
final index = items.indexWhere(
|
||||
(element) =>
|
||||
element.product.id == e.product.id &&
|
||||
element.variant?.id == e.variant?.id,
|
||||
);
|
||||
|
||||
if (index != -1) {
|
||||
final currentItem = items[index];
|
||||
if (currentItem.quantity > 1) {
|
||||
// Kurangi quantity
|
||||
items[index] = currentItem.copyWith(
|
||||
quantity: currentItem.quantity - 1,
|
||||
);
|
||||
} else {
|
||||
// Hapus item kalau quantity = 1
|
||||
items.removeAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
final totalQuantity = items.fold<int>(
|
||||
0,
|
||||
(sum, item) => sum + item.quantity,
|
||||
);
|
||||
final totalPrice = items.fold<int>(
|
||||
0,
|
||||
(sum, item) =>
|
||||
sum +
|
||||
(item.quantity *
|
||||
(item.variant?.priceModifier.toInt() ??
|
||||
item.product.price.toInt())),
|
||||
);
|
||||
|
||||
log(
|
||||
'🗑️ Item removed. Total items: ${items.length}, totalQuantity: $totalQuantity, totalPrice: $totalPrice',
|
||||
);
|
||||
|
||||
// Emit state baru
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
items: items,
|
||||
totalQuantity: totalQuantity,
|
||||
totalPrice: totalPrice,
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
started: (e) async {
|
||||
emit(CheckoutFormState.initial().copyWith(isLoading: true));
|
||||
try {
|
||||
emit(
|
||||
CheckoutFormState.initial().copyWith(
|
||||
items: e.items,
|
||||
tax: 0,
|
||||
serviceCharge: 0,
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
// Kalau gagal, pakai default values
|
||||
log('⚠️ Failed to load settings: $e');
|
||||
emit(
|
||||
CheckoutFormState.initial().copyWith(
|
||||
tax: 10,
|
||||
serviceCharge: 5,
|
||||
isLoading: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
updateItemNotes: (e) async {
|
||||
final currentState = state;
|
||||
|
||||
// Clone list items agar tidak mutasi langsung
|
||||
final items = [...currentState.items];
|
||||
final index = items.indexWhere(
|
||||
(element) => element.product.id == e.product.id,
|
||||
);
|
||||
|
||||
if (index != -1) {
|
||||
items[index] = items[index].copyWith(notes: e.notes);
|
||||
}
|
||||
|
||||
emit(currentState.copyWith(items: items, isLoading: false));
|
||||
},
|
||||
updateOrderType: (e) async {
|
||||
emit(state.copyWith(orderType: e.orderType));
|
||||
},
|
||||
updateDelivery: (e) async {
|
||||
emit(state.copyWith(delivery: e.delivery));
|
||||
},
|
||||
updateTable: (e) async {
|
||||
emit(state.copyWith(table: e.table));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
part of 'checkout_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class CheckoutFormEvent with _$CheckoutFormEvent {
|
||||
const factory CheckoutFormEvent.started(List<ProductQuantity> items) =
|
||||
_Started;
|
||||
|
||||
const factory CheckoutFormEvent.addItem(
|
||||
Product product,
|
||||
ProductVariant? variant,
|
||||
) = _AddItem;
|
||||
|
||||
const factory CheckoutFormEvent.removeItem(
|
||||
Product product,
|
||||
ProductVariant? variant,
|
||||
) = _RemoveItem;
|
||||
|
||||
const factory CheckoutFormEvent.updateItemNotes(
|
||||
Product product,
|
||||
String notes,
|
||||
) = _UpdateItemNotes;
|
||||
|
||||
const factory CheckoutFormEvent.updateOrderType(OrderType orderType) =
|
||||
_UpdateOrderType;
|
||||
|
||||
const factory CheckoutFormEvent.updateDelivery(Delivery delivery) =
|
||||
_UpdateDelivery;
|
||||
|
||||
const factory CheckoutFormEvent.updateTable(Table? table) = _UpdateTable;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
part of 'checkout_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class CheckoutFormState with _$CheckoutFormState {
|
||||
factory CheckoutFormState({
|
||||
required List<ProductQuantity> items,
|
||||
required int discount,
|
||||
required int discountAmount,
|
||||
required int tax,
|
||||
required int serviceCharge,
|
||||
required int totalQuantity,
|
||||
required int totalPrice,
|
||||
required String draftName,
|
||||
required OrderType orderType,
|
||||
Delivery? delivery,
|
||||
Table? table,
|
||||
@Default(false) bool isLoading,
|
||||
}) = _CheckoutFormState;
|
||||
|
||||
factory CheckoutFormState.initial() => CheckoutFormState(
|
||||
items: [],
|
||||
discount: 0,
|
||||
discountAmount: 0,
|
||||
tax: 0,
|
||||
serviceCharge: 0,
|
||||
totalQuantity: 0,
|
||||
totalPrice: 0,
|
||||
draftName: '',
|
||||
orderType: OrderType.dineIn,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../../../domain/customer/customer.dart';
|
||||
|
||||
part 'customer_loader_event.dart';
|
||||
part 'customer_loader_state.dart';
|
||||
part 'customer_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class CustomerLoaderBloc
|
||||
extends Bloc<CustomerLoaderEvent, CustomerLoaderState> {
|
||||
final ICustomerRepository _repository;
|
||||
CustomerLoaderBloc(this._repository) : super(CustomerLoaderState.initial()) {
|
||||
on<CustomerLoaderEvent>(_onCustomerLoaderEvent);
|
||||
}
|
||||
|
||||
Future<void> _onCustomerLoaderEvent(
|
||||
CustomerLoaderEvent event,
|
||||
Emitter<CustomerLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
fetched: (e) async {
|
||||
var newState = state;
|
||||
|
||||
if (e.isRefresh) {
|
||||
newState = newState.copyWith(isFetching: true);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
newState = await _mapFetchedToState(newState, isRefresh: e.isRefresh);
|
||||
|
||||
emit(newState);
|
||||
},
|
||||
setSelectedCustomer: (e) async {
|
||||
emit(state.copyWith(selectedCustomer: e.customer));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<CustomerLoaderState> _mapFetchedToState(
|
||||
CustomerLoaderState state, {
|
||||
bool isRefresh = false,
|
||||
}) async {
|
||||
state = state.copyWith(isFetching: false);
|
||||
|
||||
if (state.hasReachedMax && state.customers.isNotEmpty && !isRefresh) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
state = state.copyWith(
|
||||
page: 1,
|
||||
failureOrOption: none(),
|
||||
hasReachedMax: false,
|
||||
customers: [],
|
||||
);
|
||||
}
|
||||
|
||||
final failureOrCustomer = await _repository.getCustomer(page: state.page);
|
||||
|
||||
state = failureOrCustomer.fold(
|
||||
(f) {
|
||||
if (state.customers.isNotEmpty) {
|
||||
return state.copyWith(hasReachedMax: true);
|
||||
}
|
||||
return state.copyWith(failureOrOption: optionOf(f));
|
||||
},
|
||||
(customers) {
|
||||
return state.copyWith(
|
||||
customers: List.from(state.customers)..addAll(customers.customers),
|
||||
failureOrOption: none(),
|
||||
page: state.page + 1,
|
||||
hasReachedMax: customers.customers.length < 10,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,668 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// 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 'customer_loader_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CustomerLoaderEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(Customer customer) setSelectedCustomer,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(Customer customer)? setSelectedCustomer,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(Customer customer)? setSelectedCustomer,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_SetSelectedCustomer value) setSelectedCustomer,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_SetSelectedCustomer value)? setSelectedCustomer,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_SetSelectedCustomer value)? setSelectedCustomer,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CustomerLoaderEventCopyWith<$Res> {
|
||||
factory $CustomerLoaderEventCopyWith(
|
||||
CustomerLoaderEvent value,
|
||||
$Res Function(CustomerLoaderEvent) then,
|
||||
) = _$CustomerLoaderEventCopyWithImpl<$Res, CustomerLoaderEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$CustomerLoaderEventCopyWithImpl<$Res, $Val extends CustomerLoaderEvent>
|
||||
implements $CustomerLoaderEventCopyWith<$Res> {
|
||||
_$CustomerLoaderEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SetSelectedCustomerImplCopyWith<$Res> {
|
||||
factory _$$SetSelectedCustomerImplCopyWith(
|
||||
_$SetSelectedCustomerImpl value,
|
||||
$Res Function(_$SetSelectedCustomerImpl) then,
|
||||
) = __$$SetSelectedCustomerImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({Customer customer});
|
||||
|
||||
$CustomerCopyWith<$Res> get customer;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SetSelectedCustomerImplCopyWithImpl<$Res>
|
||||
extends _$CustomerLoaderEventCopyWithImpl<$Res, _$SetSelectedCustomerImpl>
|
||||
implements _$$SetSelectedCustomerImplCopyWith<$Res> {
|
||||
__$$SetSelectedCustomerImplCopyWithImpl(
|
||||
_$SetSelectedCustomerImpl _value,
|
||||
$Res Function(_$SetSelectedCustomerImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? customer = null}) {
|
||||
return _then(
|
||||
_$SetSelectedCustomerImpl(
|
||||
null == customer
|
||||
? _value.customer
|
||||
: customer // ignore: cast_nullable_to_non_nullable
|
||||
as Customer,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CustomerCopyWith<$Res> get customer {
|
||||
return $CustomerCopyWith<$Res>(_value.customer, (value) {
|
||||
return _then(_value.copyWith(customer: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SetSelectedCustomerImpl implements _SetSelectedCustomer {
|
||||
const _$SetSelectedCustomerImpl(this.customer);
|
||||
|
||||
@override
|
||||
final Customer customer;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CustomerLoaderEvent.setSelectedCustomer(customer: $customer)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SetSelectedCustomerImpl &&
|
||||
(identical(other.customer, customer) ||
|
||||
other.customer == customer));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, customer);
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SetSelectedCustomerImplCopyWith<_$SetSelectedCustomerImpl> get copyWith =>
|
||||
__$$SetSelectedCustomerImplCopyWithImpl<_$SetSelectedCustomerImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(Customer customer) setSelectedCustomer,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) {
|
||||
return setSelectedCustomer(customer);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(Customer customer)? setSelectedCustomer,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) {
|
||||
return setSelectedCustomer?.call(customer);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(Customer customer)? setSelectedCustomer,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (setSelectedCustomer != null) {
|
||||
return setSelectedCustomer(customer);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_SetSelectedCustomer value) setSelectedCustomer,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) {
|
||||
return setSelectedCustomer(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_SetSelectedCustomer value)? setSelectedCustomer,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) {
|
||||
return setSelectedCustomer?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_SetSelectedCustomer value)? setSelectedCustomer,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (setSelectedCustomer != null) {
|
||||
return setSelectedCustomer(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _SetSelectedCustomer implements CustomerLoaderEvent {
|
||||
const factory _SetSelectedCustomer(final Customer customer) =
|
||||
_$SetSelectedCustomerImpl;
|
||||
|
||||
Customer get customer;
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SetSelectedCustomerImplCopyWith<_$SetSelectedCustomerImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FetchedImplCopyWith<$Res> {
|
||||
factory _$$FetchedImplCopyWith(
|
||||
_$FetchedImpl value,
|
||||
$Res Function(_$FetchedImpl) then,
|
||||
) = __$$FetchedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({bool isRefresh});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FetchedImplCopyWithImpl<$Res>
|
||||
extends _$CustomerLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
|
||||
implements _$$FetchedImplCopyWith<$Res> {
|
||||
__$$FetchedImplCopyWithImpl(
|
||||
_$FetchedImpl _value,
|
||||
$Res Function(_$FetchedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? isRefresh = null}) {
|
||||
return _then(
|
||||
_$FetchedImpl(
|
||||
isRefresh: null == isRefresh
|
||||
? _value.isRefresh
|
||||
: isRefresh // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$FetchedImpl implements _Fetched {
|
||||
const _$FetchedImpl({this.isRefresh = false});
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isRefresh;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CustomerLoaderEvent.fetched(isRefresh: $isRefresh)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FetchedImpl &&
|
||||
(identical(other.isRefresh, isRefresh) ||
|
||||
other.isRefresh == isRefresh));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, isRefresh);
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
__$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(Customer customer) setSelectedCustomer,
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(Customer customer)? setSelectedCustomer,
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) {
|
||||
return fetched?.call(isRefresh);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(Customer customer)? setSelectedCustomer,
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_SetSelectedCustomer value) setSelectedCustomer,
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) {
|
||||
return fetched(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_SetSelectedCustomer value)? setSelectedCustomer,
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) {
|
||||
return fetched?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_SetSelectedCustomer value)? setSelectedCustomer,
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Fetched implements CustomerLoaderEvent {
|
||||
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
|
||||
|
||||
bool get isRefresh;
|
||||
|
||||
/// Create a copy of CustomerLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$CustomerLoaderState {
|
||||
List<Customer> get customers => throw _privateConstructorUsedError;
|
||||
Option<CustomerFailure> get failureOrOption =>
|
||||
throw _privateConstructorUsedError;
|
||||
Customer? get selectedCustomer => throw _privateConstructorUsedError;
|
||||
bool get isFetching => throw _privateConstructorUsedError;
|
||||
bool get hasReachedMax => throw _privateConstructorUsedError;
|
||||
int get page => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of CustomerLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$CustomerLoaderStateCopyWith<CustomerLoaderState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $CustomerLoaderStateCopyWith<$Res> {
|
||||
factory $CustomerLoaderStateCopyWith(
|
||||
CustomerLoaderState value,
|
||||
$Res Function(CustomerLoaderState) then,
|
||||
) = _$CustomerLoaderStateCopyWithImpl<$Res, CustomerLoaderState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Customer> customers,
|
||||
Option<CustomerFailure> failureOrOption,
|
||||
Customer? selectedCustomer,
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
});
|
||||
|
||||
$CustomerCopyWith<$Res>? get selectedCustomer;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$CustomerLoaderStateCopyWithImpl<$Res, $Val extends CustomerLoaderState>
|
||||
implements $CustomerLoaderStateCopyWith<$Res> {
|
||||
_$CustomerLoaderStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of CustomerLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? customers = null,
|
||||
Object? failureOrOption = null,
|
||||
Object? selectedCustomer = freezed,
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
customers: null == customers
|
||||
? _value.customers
|
||||
: customers // ignore: cast_nullable_to_non_nullable
|
||||
as List<Customer>,
|
||||
failureOrOption: null == failureOrOption
|
||||
? _value.failureOrOption
|
||||
: failureOrOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<CustomerFailure>,
|
||||
selectedCustomer: freezed == selectedCustomer
|
||||
? _value.selectedCustomer
|
||||
: selectedCustomer // ignore: cast_nullable_to_non_nullable
|
||||
as Customer?,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy of CustomerLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$CustomerCopyWith<$Res>? get selectedCustomer {
|
||||
if (_value.selectedCustomer == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $CustomerCopyWith<$Res>(_value.selectedCustomer!, (value) {
|
||||
return _then(_value.copyWith(selectedCustomer: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$CustomerLoaderStateImplCopyWith<$Res>
|
||||
implements $CustomerLoaderStateCopyWith<$Res> {
|
||||
factory _$$CustomerLoaderStateImplCopyWith(
|
||||
_$CustomerLoaderStateImpl value,
|
||||
$Res Function(_$CustomerLoaderStateImpl) then,
|
||||
) = __$$CustomerLoaderStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Customer> customers,
|
||||
Option<CustomerFailure> failureOrOption,
|
||||
Customer? selectedCustomer,
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
});
|
||||
|
||||
@override
|
||||
$CustomerCopyWith<$Res>? get selectedCustomer;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$CustomerLoaderStateImplCopyWithImpl<$Res>
|
||||
extends _$CustomerLoaderStateCopyWithImpl<$Res, _$CustomerLoaderStateImpl>
|
||||
implements _$$CustomerLoaderStateImplCopyWith<$Res> {
|
||||
__$$CustomerLoaderStateImplCopyWithImpl(
|
||||
_$CustomerLoaderStateImpl _value,
|
||||
$Res Function(_$CustomerLoaderStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of CustomerLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? customers = null,
|
||||
Object? failureOrOption = null,
|
||||
Object? selectedCustomer = freezed,
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$CustomerLoaderStateImpl(
|
||||
customers: null == customers
|
||||
? _value._customers
|
||||
: customers // ignore: cast_nullable_to_non_nullable
|
||||
as List<Customer>,
|
||||
failureOrOption: null == failureOrOption
|
||||
? _value.failureOrOption
|
||||
: failureOrOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<CustomerFailure>,
|
||||
selectedCustomer: freezed == selectedCustomer
|
||||
? _value.selectedCustomer
|
||||
: selectedCustomer // ignore: cast_nullable_to_non_nullable
|
||||
as Customer?,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$CustomerLoaderStateImpl implements _CustomerLoaderState {
|
||||
_$CustomerLoaderStateImpl({
|
||||
required final List<Customer> customers,
|
||||
required this.failureOrOption,
|
||||
this.selectedCustomer,
|
||||
this.isFetching = false,
|
||||
this.hasReachedMax = false,
|
||||
this.page = 1,
|
||||
}) : _customers = customers;
|
||||
|
||||
final List<Customer> _customers;
|
||||
@override
|
||||
List<Customer> get customers {
|
||||
if (_customers is EqualUnmodifiableListView) return _customers;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_customers);
|
||||
}
|
||||
|
||||
@override
|
||||
final Option<CustomerFailure> failureOrOption;
|
||||
@override
|
||||
final Customer? selectedCustomer;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFetching;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool hasReachedMax;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int page;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'CustomerLoaderState(customers: $customers, failureOrOption: $failureOrOption, selectedCustomer: $selectedCustomer, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$CustomerLoaderStateImpl &&
|
||||
const DeepCollectionEquality().equals(
|
||||
other._customers,
|
||||
_customers,
|
||||
) &&
|
||||
(identical(other.failureOrOption, failureOrOption) ||
|
||||
other.failureOrOption == failureOrOption) &&
|
||||
(identical(other.selectedCustomer, selectedCustomer) ||
|
||||
other.selectedCustomer == selectedCustomer) &&
|
||||
(identical(other.isFetching, isFetching) ||
|
||||
other.isFetching == isFetching) &&
|
||||
(identical(other.hasReachedMax, hasReachedMax) ||
|
||||
other.hasReachedMax == hasReachedMax) &&
|
||||
(identical(other.page, page) || other.page == page));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_customers),
|
||||
failureOrOption,
|
||||
selectedCustomer,
|
||||
isFetching,
|
||||
hasReachedMax,
|
||||
page,
|
||||
);
|
||||
|
||||
/// Create a copy of CustomerLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$CustomerLoaderStateImplCopyWith<_$CustomerLoaderStateImpl> get copyWith =>
|
||||
__$$CustomerLoaderStateImplCopyWithImpl<_$CustomerLoaderStateImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class _CustomerLoaderState implements CustomerLoaderState {
|
||||
factory _CustomerLoaderState({
|
||||
required final List<Customer> customers,
|
||||
required final Option<CustomerFailure> failureOrOption,
|
||||
final Customer? selectedCustomer,
|
||||
final bool isFetching,
|
||||
final bool hasReachedMax,
|
||||
final int page,
|
||||
}) = _$CustomerLoaderStateImpl;
|
||||
|
||||
@override
|
||||
List<Customer> get customers;
|
||||
@override
|
||||
Option<CustomerFailure> get failureOrOption;
|
||||
@override
|
||||
Customer? get selectedCustomer;
|
||||
@override
|
||||
bool get isFetching;
|
||||
@override
|
||||
bool get hasReachedMax;
|
||||
@override
|
||||
int get page;
|
||||
|
||||
/// Create a copy of CustomerLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$CustomerLoaderStateImplCopyWith<_$CustomerLoaderStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
part of 'customer_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class CustomerLoaderEvent with _$CustomerLoaderEvent {
|
||||
const factory CustomerLoaderEvent.setSelectedCustomer(Customer customer) =
|
||||
_SetSelectedCustomer;
|
||||
const factory CustomerLoaderEvent.fetched({@Default(false) bool isRefresh}) =
|
||||
_Fetched;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
part of 'customer_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class CustomerLoaderState with _$CustomerLoaderState {
|
||||
factory CustomerLoaderState({
|
||||
required List<Customer> customers,
|
||||
required Option<CustomerFailure> failureOrOption,
|
||||
Customer? selectedCustomer,
|
||||
@Default(false) bool isFetching,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
}) = _CustomerLoaderState;
|
||||
|
||||
factory CustomerLoaderState.initial() =>
|
||||
CustomerLoaderState(customers: [], failureOrOption: none());
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
|
||||
import '../../../common/types/order_type.dart';
|
||||
import '../../../domain/customer/customer.dart';
|
||||
import '../../../domain/order/order.dart';
|
||||
import '../../../domain/outlet/outlet.dart';
|
||||
import '../../../domain/payment_method/payment_method.dart';
|
||||
import '../../../domain/product/product.dart';
|
||||
import '../../../domain/table/table.dart';
|
||||
part 'order_form_event.dart';
|
||||
part 'order_form_state.dart';
|
||||
part 'order_form_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class OrderFormBloc extends Bloc<OrderFormEvent, OrderFormState> {
|
||||
final IOrderRepository _repository;
|
||||
final IOutletRepository _outletRepository;
|
||||
OrderFormBloc(this._repository, this._outletRepository)
|
||||
: super(OrderFormState.initial()) {
|
||||
on<OrderFormEvent>(_onOrderFormBloc);
|
||||
}
|
||||
|
||||
Future<void> _onOrderFormBloc(
|
||||
OrderFormEvent event,
|
||||
Emitter<OrderFormState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
customerNameChanged: (e) async {
|
||||
emit(state.copyWith(customerName: e.customerName));
|
||||
},
|
||||
paymentMethodChanged: (e) async {
|
||||
emit(state.copyWith(paymentMethod: e.payment));
|
||||
},
|
||||
customerChanged: (e) async {
|
||||
emit(state.copyWith(customer: e.customer));
|
||||
},
|
||||
createOrderWithPayment: (e) async {
|
||||
Either<OrderFailure, Order> failureOrOrder;
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isCreatingWithPayment: true,
|
||||
failureOrCreateOrderWithPayment: none(),
|
||||
),
|
||||
);
|
||||
|
||||
final outlet = await _outletRepository.currentOutlet();
|
||||
|
||||
final request = OrderRequest(
|
||||
outletId: outlet.id,
|
||||
customerId: state.customer?.id ?? '',
|
||||
tableNumber: e.table?.tableName ?? '',
|
||||
tableId: e.table?.id ?? '',
|
||||
orderType: e.orderType.name,
|
||||
notes: '',
|
||||
customerName: state.customerName ?? "",
|
||||
orderItems: e.items
|
||||
.map(
|
||||
(item) => OrderItemRequest(
|
||||
productId: item.product.id,
|
||||
productVariantId: item.variant?.id ?? "",
|
||||
quantity: item.quantity,
|
||||
unitPrice: item.product.price.toInt(),
|
||||
notes: item.notes,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
failureOrOrder = await _repository.createOrderWithPayment(
|
||||
request: request,
|
||||
paymentMethodId: state.paymentMethod?.id ?? '',
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isCreatingWithPayment: false,
|
||||
failureOrCreateOrderWithPayment: optionOf(failureOrOrder),
|
||||
),
|
||||
);
|
||||
},
|
||||
createOrder: (e) async {
|
||||
Either<OrderFailure, Order> failureOrOrder;
|
||||
|
||||
emit(state.copyWith(isCreating: true, failureOrCreateOrder: none()));
|
||||
|
||||
final outlet = await _outletRepository.currentOutlet();
|
||||
|
||||
final request = OrderRequest(
|
||||
outletId: outlet.id,
|
||||
customerId: state.customer?.id ?? '',
|
||||
tableNumber: e.table?.tableName ?? '',
|
||||
tableId: e.table?.id ?? '',
|
||||
orderType: e.orderType.name,
|
||||
notes: '',
|
||||
customerName: state.customerName ?? "",
|
||||
orderItems: e.items
|
||||
.map(
|
||||
(item) => OrderItemRequest(
|
||||
productId: item.product.id,
|
||||
productVariantId: item.variant?.id ?? "",
|
||||
quantity: item.quantity,
|
||||
unitPrice: item.product.price.toInt(),
|
||||
notes: item.notes,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
);
|
||||
|
||||
failureOrOrder = await _repository.createOrder(request: request);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isCreating: false,
|
||||
failureOrCreateOrder: optionOf(failureOrOrder),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
part of 'order_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class OrderFormEvent with _$OrderFormEvent {
|
||||
const factory OrderFormEvent.customerNameChanged(String customerName) =
|
||||
_CustomerNameChanged;
|
||||
const factory OrderFormEvent.paymentMethodChanged(PaymentMethod payment) =
|
||||
_PaymentMethodChanged;
|
||||
const factory OrderFormEvent.customerChanged(Customer? customer) =
|
||||
_CustomerChanged;
|
||||
const factory OrderFormEvent.createOrderWithPayment({
|
||||
required List<ProductQuantity> items,
|
||||
required OrderType orderType,
|
||||
Table? table,
|
||||
}) = _CreateOrderWithPayment;
|
||||
|
||||
const factory OrderFormEvent.createOrder({
|
||||
required List<ProductQuantity> items,
|
||||
required OrderType orderType,
|
||||
Table? table,
|
||||
}) = _CreateOrder;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
part of 'order_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class OrderFormState with _$OrderFormState {
|
||||
factory OrderFormState({
|
||||
PaymentMethod? paymentMethod,
|
||||
String? customerName,
|
||||
Customer? customer,
|
||||
required Option<Either<OrderFailure, Order>> failureOrCreateOrder,
|
||||
required Option<Either<OrderFailure, Order>>
|
||||
failureOrCreateOrderWithPayment,
|
||||
@Default(false) bool isCreating,
|
||||
@Default(false) bool isCreatingWithPayment,
|
||||
}) = _OrderFormState;
|
||||
|
||||
factory OrderFormState.initial() => OrderFormState(
|
||||
failureOrCreateOrder: none(),
|
||||
failureOrCreateOrderWithPayment: none(),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart' hide Order;
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart' hide Order;
|
||||
|
||||
import '../../../domain/order/order.dart';
|
||||
|
||||
part 'order_loader_event.dart';
|
||||
part 'order_loader_state.dart';
|
||||
part 'order_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
|
||||
final IOrderRepository _repository;
|
||||
OrderLoaderBloc(this._repository) : super(OrderLoaderState.initial()) {
|
||||
on<OrderLoaderEvent>(_onOrderLoaderEvent);
|
||||
}
|
||||
|
||||
Future<void> _onOrderLoaderEvent(
|
||||
OrderLoaderEvent event,
|
||||
Emitter<OrderLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
setSelectedOrder: (e) async {
|
||||
emit(state.copyWith(selectedOrder: e.order));
|
||||
},
|
||||
dateTimeRangeChange: (e) async {
|
||||
emit(state.copyWith(startDate: e.startDate, endDate: e.endDate));
|
||||
},
|
||||
searchChange: (e) async {
|
||||
emit(state.copyWith(search: e.search));
|
||||
},
|
||||
fetched: (e) async {
|
||||
var newState = state;
|
||||
|
||||
if (e.isRefresh) {
|
||||
newState = newState.copyWith(isFetching: true);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
newState = await _mapFetchedToState(
|
||||
newState,
|
||||
isRefresh: e.isRefresh,
|
||||
status: e.status,
|
||||
);
|
||||
emit(newState);
|
||||
},
|
||||
getById: (e) async {
|
||||
emit(state.copyWith(isFetchingById: true, failureOption: none()));
|
||||
|
||||
final failureOrOrder = await _repository.getOrderById(e.id);
|
||||
failureOrOrder.fold(
|
||||
(f) => emit(
|
||||
state.copyWith(failureOption: optionOf(f), isFetching: false),
|
||||
),
|
||||
(order) => emit(
|
||||
state.copyWith(
|
||||
order: order,
|
||||
isFetching: false,
|
||||
failureOption: none(),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
emit(state.copyWith(isFetchingById: false));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<OrderLoaderState> _mapFetchedToState(
|
||||
OrderLoaderState state, {
|
||||
bool isRefresh = false,
|
||||
String status = 'completed',
|
||||
}) async {
|
||||
state = state.copyWith(isFetching: false);
|
||||
|
||||
if (state.hasReachedMax && state.orders.isNotEmpty && !isRefresh) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
state = state.copyWith(
|
||||
page: 1,
|
||||
failureOption: none(),
|
||||
hasReachedMax: false,
|
||||
orders: [],
|
||||
);
|
||||
}
|
||||
|
||||
final failureOrTable = await _repository.getOrders(
|
||||
page: state.page,
|
||||
status: status,
|
||||
startDate: state.startDate,
|
||||
endDate: state.endDate,
|
||||
search: state.search,
|
||||
);
|
||||
|
||||
state = failureOrTable.fold(
|
||||
(f) {
|
||||
if (state.orders.isNotEmpty) {
|
||||
return state.copyWith(hasReachedMax: true);
|
||||
}
|
||||
return state.copyWith(failureOption: optionOf(f));
|
||||
},
|
||||
(orders) {
|
||||
return state.copyWith(
|
||||
orders: List.from(state.orders)..addAll(orders.orders),
|
||||
failureOption: none(),
|
||||
page: state.page + 1,
|
||||
hasReachedMax: orders.orders.length < 10,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
part of 'order_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class OrderLoaderEvent with _$OrderLoaderEvent {
|
||||
const factory OrderLoaderEvent.dateTimeRangeChange(
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
) = _DateTimeRangeChange;
|
||||
const factory OrderLoaderEvent.searchChange(String search) = _SearchChange;
|
||||
const factory OrderLoaderEvent.setSelectedOrder(Order order) =
|
||||
_SetSelectedOrder;
|
||||
const factory OrderLoaderEvent.getById(String id) = _GetById;
|
||||
const factory OrderLoaderEvent.fetched({
|
||||
@Default(false) bool isRefresh,
|
||||
required String status,
|
||||
}) = _Fetched;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
part of 'order_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class OrderLoaderState with _$OrderLoaderState {
|
||||
factory OrderLoaderState({
|
||||
required List<Order> orders,
|
||||
required Option<OrderFailure> failureOption,
|
||||
required Option<OrderFailure> failureOptionGetById,
|
||||
required Order order,
|
||||
Order? selectedOrder,
|
||||
String? search,
|
||||
required DateTime startDate,
|
||||
required DateTime endDate,
|
||||
@Default(false) bool isFetching,
|
||||
@Default(false) bool isFetchingById,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
}) = _OrderLoaderState;
|
||||
|
||||
factory OrderLoaderState.initial() => OrderLoaderState(
|
||||
orders: [],
|
||||
failureOption: none(),
|
||||
startDate: DateTime.now(),
|
||||
endDate: DateTime.now(),
|
||||
failureOptionGetById: none(),
|
||||
order: Order.empty(),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/outlet/outlet.dart';
|
||||
|
||||
part 'outlet_loader_event.dart';
|
||||
part 'outlet_loader_state.dart';
|
||||
part 'outlet_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class OutletLoaderBloc extends Bloc<OutletLoaderEvent, OutletLoaderState> {
|
||||
final IOutletRepository _outletRepository;
|
||||
|
||||
OutletLoaderBloc(this._outletRepository)
|
||||
: super(OutletLoaderState.initial()) {
|
||||
on<OutletLoaderEvent>(_onOutletLoaderEvent);
|
||||
}
|
||||
|
||||
Future<void> _onOutletLoaderEvent(
|
||||
OutletLoaderEvent event,
|
||||
Emitter<OutletLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
fetched: (e) async {
|
||||
var newState = state;
|
||||
|
||||
if (e.isRefresh) {
|
||||
newState = state.copyWith(isFetching: true);
|
||||
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
newState = await _mapFetchedToState(state, isRefresh: e.isRefresh);
|
||||
|
||||
emit(newState);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<OutletLoaderState> _mapFetchedToState(
|
||||
OutletLoaderState state, {
|
||||
bool isRefresh = false,
|
||||
}) async {
|
||||
state = state.copyWith(isFetching: false);
|
||||
|
||||
if (state.hasReachedMax && state.outlets.isNotEmpty && !isRefresh) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
state = state.copyWith(
|
||||
page: 1,
|
||||
failureOptionOutlet: none(),
|
||||
hasReachedMax: false,
|
||||
outlets: [],
|
||||
);
|
||||
}
|
||||
|
||||
final failureOrOutlet = await _outletRepository.getOutlets(
|
||||
page: state.page,
|
||||
);
|
||||
|
||||
state = failureOrOutlet.fold(
|
||||
(f) {
|
||||
if (state.outlets.isNotEmpty) {
|
||||
return state.copyWith(hasReachedMax: true);
|
||||
}
|
||||
return state.copyWith(failureOptionOutlet: optionOf(f));
|
||||
},
|
||||
(outlets) {
|
||||
return state.copyWith(
|
||||
outlets: List.from(state.outlets)..addAll(outlets),
|
||||
failureOptionOutlet: none(),
|
||||
page: state.page + 1,
|
||||
hasReachedMax: outlets.length < 10,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,479 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// 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 'outlet_loader_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$OutletLoaderEvent {
|
||||
bool get isRefresh => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of OutletLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OutletLoaderEventCopyWith<OutletLoaderEvent> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $OutletLoaderEventCopyWith<$Res> {
|
||||
factory $OutletLoaderEventCopyWith(
|
||||
OutletLoaderEvent value,
|
||||
$Res Function(OutletLoaderEvent) then,
|
||||
) = _$OutletLoaderEventCopyWithImpl<$Res, OutletLoaderEvent>;
|
||||
@useResult
|
||||
$Res call({bool isRefresh});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$OutletLoaderEventCopyWithImpl<$Res, $Val extends OutletLoaderEvent>
|
||||
implements $OutletLoaderEventCopyWith<$Res> {
|
||||
_$OutletLoaderEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OutletLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? isRefresh = null}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
isRefresh: null == isRefresh
|
||||
? _value.isRefresh
|
||||
: isRefresh // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FetchedImplCopyWith<$Res>
|
||||
implements $OutletLoaderEventCopyWith<$Res> {
|
||||
factory _$$FetchedImplCopyWith(
|
||||
_$FetchedImpl value,
|
||||
$Res Function(_$FetchedImpl) then,
|
||||
) = __$$FetchedImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({bool isRefresh});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FetchedImplCopyWithImpl<$Res>
|
||||
extends _$OutletLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
|
||||
implements _$$FetchedImplCopyWith<$Res> {
|
||||
__$$FetchedImplCopyWithImpl(
|
||||
_$FetchedImpl _value,
|
||||
$Res Function(_$FetchedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of OutletLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? isRefresh = null}) {
|
||||
return _then(
|
||||
_$FetchedImpl(
|
||||
isRefresh: null == isRefresh
|
||||
? _value.isRefresh
|
||||
: isRefresh // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$FetchedImpl implements _Fetched {
|
||||
const _$FetchedImpl({this.isRefresh = false});
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isRefresh;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OutletLoaderEvent.fetched(isRefresh: $isRefresh)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FetchedImpl &&
|
||||
(identical(other.isRefresh, isRefresh) ||
|
||||
other.isRefresh == isRefresh));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, isRefresh);
|
||||
|
||||
/// Create a copy of OutletLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
__$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) {
|
||||
return fetched?.call(isRefresh);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) {
|
||||
return fetched(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) {
|
||||
return fetched?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Fetched implements OutletLoaderEvent {
|
||||
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
|
||||
|
||||
@override
|
||||
bool get isRefresh;
|
||||
|
||||
/// Create a copy of OutletLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$OutletLoaderState {
|
||||
List<Outlet> get outlets => throw _privateConstructorUsedError;
|
||||
Option<OutletFailure> get failureOptionOutlet =>
|
||||
throw _privateConstructorUsedError;
|
||||
bool get isFetching => throw _privateConstructorUsedError;
|
||||
bool get hasReachedMax => throw _privateConstructorUsedError;
|
||||
int get page => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of OutletLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$OutletLoaderStateCopyWith<OutletLoaderState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $OutletLoaderStateCopyWith<$Res> {
|
||||
factory $OutletLoaderStateCopyWith(
|
||||
OutletLoaderState value,
|
||||
$Res Function(OutletLoaderState) then,
|
||||
) = _$OutletLoaderStateCopyWithImpl<$Res, OutletLoaderState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Outlet> outlets,
|
||||
Option<OutletFailure> failureOptionOutlet,
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$OutletLoaderStateCopyWithImpl<$Res, $Val extends OutletLoaderState>
|
||||
implements $OutletLoaderStateCopyWith<$Res> {
|
||||
_$OutletLoaderStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of OutletLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? outlets = null,
|
||||
Object? failureOptionOutlet = null,
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
outlets: null == outlets
|
||||
? _value.outlets
|
||||
: outlets // ignore: cast_nullable_to_non_nullable
|
||||
as List<Outlet>,
|
||||
failureOptionOutlet: null == failureOptionOutlet
|
||||
? _value.failureOptionOutlet
|
||||
: failureOptionOutlet // ignore: cast_nullable_to_non_nullable
|
||||
as Option<OutletFailure>,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$OutletLoaderStateImplCopyWith<$Res>
|
||||
implements $OutletLoaderStateCopyWith<$Res> {
|
||||
factory _$$OutletLoaderStateImplCopyWith(
|
||||
_$OutletLoaderStateImpl value,
|
||||
$Res Function(_$OutletLoaderStateImpl) then,
|
||||
) = __$$OutletLoaderStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Outlet> outlets,
|
||||
Option<OutletFailure> failureOptionOutlet,
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$OutletLoaderStateImplCopyWithImpl<$Res>
|
||||
extends _$OutletLoaderStateCopyWithImpl<$Res, _$OutletLoaderStateImpl>
|
||||
implements _$$OutletLoaderStateImplCopyWith<$Res> {
|
||||
__$$OutletLoaderStateImplCopyWithImpl(
|
||||
_$OutletLoaderStateImpl _value,
|
||||
$Res Function(_$OutletLoaderStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of OutletLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? outlets = null,
|
||||
Object? failureOptionOutlet = null,
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$OutletLoaderStateImpl(
|
||||
outlets: null == outlets
|
||||
? _value._outlets
|
||||
: outlets // ignore: cast_nullable_to_non_nullable
|
||||
as List<Outlet>,
|
||||
failureOptionOutlet: null == failureOptionOutlet
|
||||
? _value.failureOptionOutlet
|
||||
: failureOptionOutlet // ignore: cast_nullable_to_non_nullable
|
||||
as Option<OutletFailure>,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$OutletLoaderStateImpl implements _OutletLoaderState {
|
||||
const _$OutletLoaderStateImpl({
|
||||
required final List<Outlet> outlets,
|
||||
required this.failureOptionOutlet,
|
||||
this.isFetching = false,
|
||||
this.hasReachedMax = false,
|
||||
this.page = 1,
|
||||
}) : _outlets = outlets;
|
||||
|
||||
final List<Outlet> _outlets;
|
||||
@override
|
||||
List<Outlet> get outlets {
|
||||
if (_outlets is EqualUnmodifiableListView) return _outlets;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_outlets);
|
||||
}
|
||||
|
||||
@override
|
||||
final Option<OutletFailure> failureOptionOutlet;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFetching;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool hasReachedMax;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int page;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'OutletLoaderState(outlets: $outlets, failureOptionOutlet: $failureOptionOutlet, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$OutletLoaderStateImpl &&
|
||||
const DeepCollectionEquality().equals(other._outlets, _outlets) &&
|
||||
(identical(other.failureOptionOutlet, failureOptionOutlet) ||
|
||||
other.failureOptionOutlet == failureOptionOutlet) &&
|
||||
(identical(other.isFetching, isFetching) ||
|
||||
other.isFetching == isFetching) &&
|
||||
(identical(other.hasReachedMax, hasReachedMax) ||
|
||||
other.hasReachedMax == hasReachedMax) &&
|
||||
(identical(other.page, page) || other.page == page));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_outlets),
|
||||
failureOptionOutlet,
|
||||
isFetching,
|
||||
hasReachedMax,
|
||||
page,
|
||||
);
|
||||
|
||||
/// Create a copy of OutletLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$OutletLoaderStateImplCopyWith<_$OutletLoaderStateImpl> get copyWith =>
|
||||
__$$OutletLoaderStateImplCopyWithImpl<_$OutletLoaderStateImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class _OutletLoaderState implements OutletLoaderState {
|
||||
const factory _OutletLoaderState({
|
||||
required final List<Outlet> outlets,
|
||||
required final Option<OutletFailure> failureOptionOutlet,
|
||||
final bool isFetching,
|
||||
final bool hasReachedMax,
|
||||
final int page,
|
||||
}) = _$OutletLoaderStateImpl;
|
||||
|
||||
@override
|
||||
List<Outlet> get outlets;
|
||||
@override
|
||||
Option<OutletFailure> get failureOptionOutlet;
|
||||
@override
|
||||
bool get isFetching;
|
||||
@override
|
||||
bool get hasReachedMax;
|
||||
@override
|
||||
int get page;
|
||||
|
||||
/// Create a copy of OutletLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$OutletLoaderStateImplCopyWith<_$OutletLoaderStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
part of 'outlet_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class OutletLoaderEvent with _$OutletLoaderEvent {
|
||||
const factory OutletLoaderEvent.fetched({@Default(false) bool isRefresh}) =
|
||||
_Fetched;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
part of 'outlet_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class OutletLoaderState with _$OutletLoaderState {
|
||||
const factory OutletLoaderState({
|
||||
required List<Outlet> outlets,
|
||||
required Option<OutletFailure> failureOptionOutlet,
|
||||
@Default(false) bool isFetching,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
}) = _OutletLoaderState;
|
||||
|
||||
factory OutletLoaderState.initial() =>
|
||||
OutletLoaderState(outlets: [], failureOptionOutlet: none());
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/payment_method/payment_method.dart';
|
||||
|
||||
part 'payment_method_loader_event.dart';
|
||||
part 'payment_method_loader_state.dart';
|
||||
part 'payment_method_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class PaymentMethodLoaderBloc
|
||||
extends Bloc<PaymentMethodLoaderEvent, PaymentMethodLoaderState> {
|
||||
final IPaymentMethodRepository _repository;
|
||||
PaymentMethodLoaderBloc(this._repository)
|
||||
: super(PaymentMethodLoaderState.initial()) {
|
||||
on<PaymentMethodLoaderEvent>(_onPaymentMethodLoaderEvent);
|
||||
}
|
||||
|
||||
Future<void> _onPaymentMethodLoaderEvent(
|
||||
PaymentMethodLoaderEvent event,
|
||||
Emitter<PaymentMethodLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
fetched: (e) async {
|
||||
var newState = state;
|
||||
|
||||
if (e.isRefresh) {
|
||||
newState = newState.copyWith(isFetching: true);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
newState = await _mapFetchedToState(newState, isRefresh: e.isRefresh);
|
||||
emit(newState);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<PaymentMethodLoaderState> _mapFetchedToState(
|
||||
PaymentMethodLoaderState state, {
|
||||
bool isRefresh = false,
|
||||
}) async {
|
||||
state = state.copyWith(isFetching: false);
|
||||
|
||||
if (state.hasReachedMax && state.paymentMethods.isNotEmpty && !isRefresh) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
state = state.copyWith(
|
||||
page: 1,
|
||||
failureOption: none(),
|
||||
hasReachedMax: false,
|
||||
paymentMethods: [],
|
||||
);
|
||||
}
|
||||
|
||||
final failureOrTable = await _repository.getPaymentMethods(
|
||||
page: state.page,
|
||||
);
|
||||
|
||||
state = failureOrTable.fold(
|
||||
(f) {
|
||||
if (state.paymentMethods.isNotEmpty) {
|
||||
return state.copyWith(hasReachedMax: true);
|
||||
}
|
||||
return state.copyWith(failureOption: optionOf(f));
|
||||
},
|
||||
(paymentMethods) {
|
||||
return state.copyWith(
|
||||
paymentMethods: List.from(state.paymentMethods)
|
||||
..addAll(paymentMethods.paymentMethods),
|
||||
failureOption: none(),
|
||||
page: state.page + 1,
|
||||
hasReachedMax: paymentMethods.paymentMethods.length < 10,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,492 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// 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 'payment_method_loader_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PaymentMethodLoaderEvent {
|
||||
bool get isRefresh => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PaymentMethodLoaderEventCopyWith<PaymentMethodLoaderEvent> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $PaymentMethodLoaderEventCopyWith<$Res> {
|
||||
factory $PaymentMethodLoaderEventCopyWith(
|
||||
PaymentMethodLoaderEvent value,
|
||||
$Res Function(PaymentMethodLoaderEvent) then,
|
||||
) = _$PaymentMethodLoaderEventCopyWithImpl<$Res, PaymentMethodLoaderEvent>;
|
||||
@useResult
|
||||
$Res call({bool isRefresh});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$PaymentMethodLoaderEventCopyWithImpl<
|
||||
$Res,
|
||||
$Val extends PaymentMethodLoaderEvent
|
||||
>
|
||||
implements $PaymentMethodLoaderEventCopyWith<$Res> {
|
||||
_$PaymentMethodLoaderEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? isRefresh = null}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
isRefresh: null == isRefresh
|
||||
? _value.isRefresh
|
||||
: isRefresh // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FetchedImplCopyWith<$Res>
|
||||
implements $PaymentMethodLoaderEventCopyWith<$Res> {
|
||||
factory _$$FetchedImplCopyWith(
|
||||
_$FetchedImpl value,
|
||||
$Res Function(_$FetchedImpl) then,
|
||||
) = __$$FetchedImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({bool isRefresh});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FetchedImplCopyWithImpl<$Res>
|
||||
extends _$PaymentMethodLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
|
||||
implements _$$FetchedImplCopyWith<$Res> {
|
||||
__$$FetchedImplCopyWithImpl(
|
||||
_$FetchedImpl _value,
|
||||
$Res Function(_$FetchedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? isRefresh = null}) {
|
||||
return _then(
|
||||
_$FetchedImpl(
|
||||
isRefresh: null == isRefresh
|
||||
? _value.isRefresh
|
||||
: isRefresh // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$FetchedImpl implements _Fetched {
|
||||
const _$FetchedImpl({this.isRefresh = false});
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isRefresh;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PaymentMethodLoaderEvent.fetched(isRefresh: $isRefresh)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FetchedImpl &&
|
||||
(identical(other.isRefresh, isRefresh) ||
|
||||
other.isRefresh == isRefresh));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, isRefresh);
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
__$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh) fetched,
|
||||
}) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh)? fetched,
|
||||
}) {
|
||||
return fetched?.call(isRefresh);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(isRefresh);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
}) {
|
||||
return fetched(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
}) {
|
||||
return fetched?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Fetched implements PaymentMethodLoaderEvent {
|
||||
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
|
||||
|
||||
@override
|
||||
bool get isRefresh;
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$PaymentMethodLoaderState {
|
||||
List<PaymentMethod> get paymentMethods => throw _privateConstructorUsedError;
|
||||
Option<PaymentMethodFailure> get failureOption =>
|
||||
throw _privateConstructorUsedError;
|
||||
bool get hasReachedMax => throw _privateConstructorUsedError;
|
||||
bool get isFetching => throw _privateConstructorUsedError;
|
||||
int get page => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$PaymentMethodLoaderStateCopyWith<PaymentMethodLoaderState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $PaymentMethodLoaderStateCopyWith<$Res> {
|
||||
factory $PaymentMethodLoaderStateCopyWith(
|
||||
PaymentMethodLoaderState value,
|
||||
$Res Function(PaymentMethodLoaderState) then,
|
||||
) = _$PaymentMethodLoaderStateCopyWithImpl<$Res, PaymentMethodLoaderState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<PaymentMethod> paymentMethods,
|
||||
Option<PaymentMethodFailure> failureOption,
|
||||
bool hasReachedMax,
|
||||
bool isFetching,
|
||||
int page,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$PaymentMethodLoaderStateCopyWithImpl<
|
||||
$Res,
|
||||
$Val extends PaymentMethodLoaderState
|
||||
>
|
||||
implements $PaymentMethodLoaderStateCopyWith<$Res> {
|
||||
_$PaymentMethodLoaderStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? paymentMethods = null,
|
||||
Object? failureOption = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? isFetching = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
paymentMethods: null == paymentMethods
|
||||
? _value.paymentMethods
|
||||
: paymentMethods // ignore: cast_nullable_to_non_nullable
|
||||
as List<PaymentMethod>,
|
||||
failureOption: null == failureOption
|
||||
? _value.failureOption
|
||||
: failureOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<PaymentMethodFailure>,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$PaymentMethodLoaderStateImplCopyWith<$Res>
|
||||
implements $PaymentMethodLoaderStateCopyWith<$Res> {
|
||||
factory _$$PaymentMethodLoaderStateImplCopyWith(
|
||||
_$PaymentMethodLoaderStateImpl value,
|
||||
$Res Function(_$PaymentMethodLoaderStateImpl) then,
|
||||
) = __$$PaymentMethodLoaderStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<PaymentMethod> paymentMethods,
|
||||
Option<PaymentMethodFailure> failureOption,
|
||||
bool hasReachedMax,
|
||||
bool isFetching,
|
||||
int page,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$PaymentMethodLoaderStateImplCopyWithImpl<$Res>
|
||||
extends
|
||||
_$PaymentMethodLoaderStateCopyWithImpl<
|
||||
$Res,
|
||||
_$PaymentMethodLoaderStateImpl
|
||||
>
|
||||
implements _$$PaymentMethodLoaderStateImplCopyWith<$Res> {
|
||||
__$$PaymentMethodLoaderStateImplCopyWithImpl(
|
||||
_$PaymentMethodLoaderStateImpl _value,
|
||||
$Res Function(_$PaymentMethodLoaderStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? paymentMethods = null,
|
||||
Object? failureOption = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? isFetching = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$PaymentMethodLoaderStateImpl(
|
||||
paymentMethods: null == paymentMethods
|
||||
? _value._paymentMethods
|
||||
: paymentMethods // ignore: cast_nullable_to_non_nullable
|
||||
as List<PaymentMethod>,
|
||||
failureOption: null == failureOption
|
||||
? _value.failureOption
|
||||
: failureOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<PaymentMethodFailure>,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$PaymentMethodLoaderStateImpl implements _PaymentMethodLoaderState {
|
||||
_$PaymentMethodLoaderStateImpl({
|
||||
required final List<PaymentMethod> paymentMethods,
|
||||
required this.failureOption,
|
||||
this.hasReachedMax = false,
|
||||
this.isFetching = false,
|
||||
this.page = 1,
|
||||
}) : _paymentMethods = paymentMethods;
|
||||
|
||||
final List<PaymentMethod> _paymentMethods;
|
||||
@override
|
||||
List<PaymentMethod> get paymentMethods {
|
||||
if (_paymentMethods is EqualUnmodifiableListView) return _paymentMethods;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_paymentMethods);
|
||||
}
|
||||
|
||||
@override
|
||||
final Option<PaymentMethodFailure> failureOption;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool hasReachedMax;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFetching;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int page;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'PaymentMethodLoaderState(paymentMethods: $paymentMethods, failureOption: $failureOption, hasReachedMax: $hasReachedMax, isFetching: $isFetching, page: $page)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$PaymentMethodLoaderStateImpl &&
|
||||
const DeepCollectionEquality().equals(
|
||||
other._paymentMethods,
|
||||
_paymentMethods,
|
||||
) &&
|
||||
(identical(other.failureOption, failureOption) ||
|
||||
other.failureOption == failureOption) &&
|
||||
(identical(other.hasReachedMax, hasReachedMax) ||
|
||||
other.hasReachedMax == hasReachedMax) &&
|
||||
(identical(other.isFetching, isFetching) ||
|
||||
other.isFetching == isFetching) &&
|
||||
(identical(other.page, page) || other.page == page));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_paymentMethods),
|
||||
failureOption,
|
||||
hasReachedMax,
|
||||
isFetching,
|
||||
page,
|
||||
);
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$PaymentMethodLoaderStateImplCopyWith<_$PaymentMethodLoaderStateImpl>
|
||||
get copyWith =>
|
||||
__$$PaymentMethodLoaderStateImplCopyWithImpl<
|
||||
_$PaymentMethodLoaderStateImpl
|
||||
>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _PaymentMethodLoaderState implements PaymentMethodLoaderState {
|
||||
factory _PaymentMethodLoaderState({
|
||||
required final List<PaymentMethod> paymentMethods,
|
||||
required final Option<PaymentMethodFailure> failureOption,
|
||||
final bool hasReachedMax,
|
||||
final bool isFetching,
|
||||
final int page,
|
||||
}) = _$PaymentMethodLoaderStateImpl;
|
||||
|
||||
@override
|
||||
List<PaymentMethod> get paymentMethods;
|
||||
@override
|
||||
Option<PaymentMethodFailure> get failureOption;
|
||||
@override
|
||||
bool get hasReachedMax;
|
||||
@override
|
||||
bool get isFetching;
|
||||
@override
|
||||
int get page;
|
||||
|
||||
/// Create a copy of PaymentMethodLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$PaymentMethodLoaderStateImplCopyWith<_$PaymentMethodLoaderStateImpl>
|
||||
get copyWith => throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
part of 'payment_method_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class PaymentMethodLoaderEvent with _$PaymentMethodLoaderEvent {
|
||||
const factory PaymentMethodLoaderEvent.fetched({
|
||||
@Default(false) bool isRefresh,
|
||||
}) = _Fetched;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
part of 'payment_method_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class PaymentMethodLoaderState with _$PaymentMethodLoaderState {
|
||||
factory PaymentMethodLoaderState({
|
||||
required List<PaymentMethod> paymentMethods,
|
||||
required Option<PaymentMethodFailure> failureOption,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(false) bool isFetching,
|
||||
@Default(1) int page,
|
||||
}) = _PaymentMethodLoaderState;
|
||||
factory PaymentMethodLoaderState.initial() =>
|
||||
PaymentMethodLoaderState(paymentMethods: [], failureOption: none());
|
||||
}
|
||||
@@ -0,0 +1,345 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/product/product.dart';
|
||||
|
||||
part 'product_loader_event.dart';
|
||||
part 'product_loader_state.dart';
|
||||
part 'product_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class ProductLoaderBloc extends Bloc<ProductLoaderEvent, ProductLoaderState> {
|
||||
final IProductRepository _productRepository;
|
||||
|
||||
Timer? _loadMoreDebounce;
|
||||
Timer? _searchDebounce;
|
||||
|
||||
ProductLoaderBloc(this._productRepository)
|
||||
: super(ProductLoaderState.initial()) {
|
||||
on<ProductLoaderEvent>(_onProductLoaderEvent);
|
||||
}
|
||||
|
||||
Future<void> _onProductLoaderEvent(
|
||||
ProductLoaderEvent event,
|
||||
Emitter<ProductLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
getProduct: (e) async {
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
|
||||
log(
|
||||
'📱 Loading local products - categoryId: ${e.categoryId}, search: ${e.search}',
|
||||
);
|
||||
|
||||
// Pastikan database lokal sudah siap
|
||||
final isReady = await _productRepository.isLocalDatabaseReady();
|
||||
if (!isReady) {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(
|
||||
ProductFailure.dynamicErrorMessage(
|
||||
'Database lokal belum siap. Silakan lakukan sinkronisasi data terlebih dahulu.',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
final result = await _productRepository.getProducts(
|
||||
page: 1,
|
||||
limit: 10,
|
||||
categoryId: e.categoryId,
|
||||
search: e.search,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Error loading local products: $failure');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) async {
|
||||
final products = response.products;
|
||||
final totalPages = response.totalPages;
|
||||
final hasReachedMax = products.length < 10 || 1 >= totalPages;
|
||||
|
||||
log(
|
||||
'✅ Local products loaded: ${products.length}, hasReachedMax: $hasReachedMax, totalPages: $totalPages',
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
products: products,
|
||||
page: 1,
|
||||
hasReachedMax: hasReachedMax,
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: none(),
|
||||
categoryId: e.categoryId,
|
||||
searchQuery: e.search,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
loadMore: (e) async {
|
||||
final currentState = state;
|
||||
|
||||
// Cegah double load
|
||||
if (currentState.isLoadingMore || currentState.hasReachedMax) {
|
||||
log(
|
||||
'⏹️ Load more blocked - isLoadingMore: ${currentState.isLoadingMore}, hasReachedMax: ${currentState.hasReachedMax}',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
emit(currentState.copyWith(isLoadingMore: true));
|
||||
|
||||
final nextPage = currentState.page + 1;
|
||||
log('📄 Loading more local products - page: $nextPage');
|
||||
|
||||
try {
|
||||
final result = await _productRepository.getProducts(
|
||||
page: nextPage,
|
||||
limit: 10,
|
||||
categoryId: currentState.categoryId,
|
||||
search: currentState.searchQuery,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Error loading more local products: $failure');
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) async {
|
||||
final newProducts = response.products;
|
||||
final totalPages = response.totalPages;
|
||||
|
||||
// Hindari duplikat produk
|
||||
final currentProductIds = currentState.products
|
||||
.map((p) => p.id)
|
||||
.toSet();
|
||||
final filteredNewProducts = newProducts
|
||||
.where((product) => !currentProductIds.contains(product.id))
|
||||
.toList();
|
||||
|
||||
final allProducts = [
|
||||
...currentState.products,
|
||||
...filteredNewProducts,
|
||||
];
|
||||
|
||||
final hasReachedMax =
|
||||
filteredNewProducts.length < 10 || nextPage >= totalPages;
|
||||
|
||||
log(
|
||||
'✅ More local products loaded: ${filteredNewProducts.length} new, total: ${allProducts.length}, hasReachedMax: $hasReachedMax',
|
||||
);
|
||||
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
products: allProducts,
|
||||
page: nextPage,
|
||||
hasReachedMax: hasReachedMax,
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: none(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
log('❌ Exception loading more local products: $e');
|
||||
emit(
|
||||
currentState.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(
|
||||
ProductFailure.dynamicErrorMessage(
|
||||
'Gagal memuat produk tambahan: $e',
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
refresh: (e) async {
|
||||
final categoryId = state.categoryId;
|
||||
final searchQuery = state.searchQuery;
|
||||
|
||||
_loadMoreDebounce?.cancel();
|
||||
_searchDebounce?.cancel();
|
||||
|
||||
log(
|
||||
'🔄 Refreshing local products - categoryId: $categoryId, search: $searchQuery',
|
||||
);
|
||||
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
|
||||
try {
|
||||
_productRepository.clearCache();
|
||||
|
||||
final result = await _productRepository.refreshProducts(
|
||||
categoryId: categoryId,
|
||||
search: searchQuery,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Failed to refresh local products: $failure');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) async {
|
||||
final products = response.products;
|
||||
final totalPages = response.totalPages;
|
||||
final hasReachedMax = products.length < 10 || 1 >= totalPages;
|
||||
|
||||
log('✅ Refreshed local products: ${products.length}');
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
products: products,
|
||||
hasReachedMax: hasReachedMax,
|
||||
page: 1,
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: none(),
|
||||
categoryId: categoryId,
|
||||
searchQuery: searchQuery,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
log('❌ Exception refreshing local products: $e');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(
|
||||
ProductFailure.dynamicErrorMessage(e.toString()),
|
||||
),
|
||||
),
|
||||
);
|
||||
} finally {}
|
||||
},
|
||||
searchProduct: (e) async {
|
||||
_searchDebounce?.cancel();
|
||||
|
||||
// Debounce ringan agar UX lebih halus
|
||||
_searchDebounce = Timer(const Duration(milliseconds: 150), () async {
|
||||
emit(state.copyWith(isLoadingMore: true));
|
||||
|
||||
log('🔍 Local search: "${e.query}"');
|
||||
|
||||
try {
|
||||
final result = await _productRepository.getProducts(
|
||||
page: 1,
|
||||
limit: 20, // lebih banyak hasil untuk pencarian
|
||||
categoryId: e.categoryId,
|
||||
search: e.query,
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Local search error: $failure');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(failure),
|
||||
),
|
||||
);
|
||||
},
|
||||
(response) async {
|
||||
final products = response.products;
|
||||
final totalPages = response.totalPages;
|
||||
final hasReachedMax = products.length < 20 || 1 >= totalPages;
|
||||
|
||||
log(
|
||||
'✅ Local search results: ${products.length} products found',
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
products: products,
|
||||
hasReachedMax: hasReachedMax,
|
||||
page: 1,
|
||||
isLoadingMore: false,
|
||||
categoryId: e.categoryId,
|
||||
searchQuery: e.query,
|
||||
failureOptionProduct: none(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
log('❌ Exception during local search: $e');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isLoadingMore: false,
|
||||
failureOptionProduct: optionOf(
|
||||
ProductFailure.dynamicErrorMessage(e.toString()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
getDatabaseStats: (e) async {
|
||||
log('📊 Getting local database stats...');
|
||||
|
||||
try {
|
||||
final result = await _productRepository.getDatabaseStats();
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
log('❌ Failed to get database stats: $failure');
|
||||
emit(state.copyWith(failureOptionProduct: optionOf(failure)));
|
||||
},
|
||||
(stats) async {
|
||||
log('✅ Local database stats retrieved: $stats');
|
||||
// Jika UI kamu perlu tampilkan, bisa simpan ke state, misalnya:
|
||||
// emit(state.copyWith(databaseStats: some(stats)));
|
||||
// Tapi kalau hanya untuk log/debug, tidak perlu ubah state
|
||||
},
|
||||
);
|
||||
} catch (e, s) {
|
||||
log(
|
||||
'❌ Exception while getting database stats: $e',
|
||||
error: e,
|
||||
stackTrace: s,
|
||||
);
|
||||
emit(
|
||||
state.copyWith(
|
||||
failureOptionProduct: optionOf(
|
||||
ProductFailure.dynamicErrorMessage(e.toString()),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
clearCache: (e) async {
|
||||
log('🧹 Manually clearing local cache');
|
||||
_productRepository.clearCache();
|
||||
|
||||
// Refresh current data after cache clear
|
||||
add(const ProductLoaderEvent.refresh());
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
part of 'product_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class ProductLoaderEvent with _$ProductLoaderEvent {
|
||||
const factory ProductLoaderEvent.getProduct({
|
||||
String? categoryId,
|
||||
String? search, // Added search parameter
|
||||
bool? forceRefresh, // Kept for compatibility but ignored
|
||||
}) = _GetProduct;
|
||||
|
||||
const factory ProductLoaderEvent.loadMore({
|
||||
String? categoryId,
|
||||
String? search,
|
||||
}) = _LoadMore;
|
||||
|
||||
const factory ProductLoaderEvent.refresh() = _Refresh;
|
||||
|
||||
const factory ProductLoaderEvent.searchProduct({
|
||||
String? query,
|
||||
String? categoryId,
|
||||
}) = _SearchProduct;
|
||||
|
||||
const factory ProductLoaderEvent.getDatabaseStats() = _GetDatabaseStats;
|
||||
|
||||
const factory ProductLoaderEvent.clearCache() = _ClearCache;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
part of 'product_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class ProductLoaderState with _$ProductLoaderState {
|
||||
factory ProductLoaderState({
|
||||
required List<Product> products,
|
||||
required Option<ProductFailure> failureOptionProduct,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
@Default(false) bool isLoadingMore,
|
||||
String? searchQuery,
|
||||
String? categoryId,
|
||||
}) = _ProductLoaderState;
|
||||
|
||||
factory ProductLoaderState.initial() =>
|
||||
ProductLoaderState(products: [], failureOptionProduct: none());
|
||||
}
|
||||
@@ -0,0 +1,323 @@
|
||||
import 'dart:async';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../domain/category/category.dart';
|
||||
import '../../domain/product/product.dart';
|
||||
|
||||
part 'sync_event.dart';
|
||||
part 'sync_state.dart';
|
||||
part 'sync_bloc.freezed.dart';
|
||||
|
||||
enum SyncStep { categories, products, variants, completed }
|
||||
|
||||
class SyncStats {
|
||||
final int totalProducts;
|
||||
final int totalCategories;
|
||||
final int totalVariants;
|
||||
final double databaseSizeMB;
|
||||
|
||||
SyncStats({
|
||||
required this.totalProducts,
|
||||
required this.totalCategories,
|
||||
required this.totalVariants,
|
||||
required this.databaseSizeMB,
|
||||
});
|
||||
}
|
||||
|
||||
@injectable
|
||||
class SyncBloc extends Bloc<SyncEvent, SyncState> {
|
||||
final IProductRepository _productRepository;
|
||||
final ICategoryRepository _categoryRepository;
|
||||
|
||||
Timer? _progressTimer;
|
||||
bool _isCancelled = false;
|
||||
|
||||
SyncBloc(this._productRepository, this._categoryRepository)
|
||||
: super(SyncState.initial()) {
|
||||
on<SyncEvent>(_onSyncEvent);
|
||||
}
|
||||
|
||||
Future<void> _onSyncEvent(SyncEvent event, Emitter<SyncState> emit) {
|
||||
return event.map(
|
||||
startSync: (e) async {
|
||||
log('🔄 Starting full data sync (categories + products)...');
|
||||
_isCancelled = false;
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: true,
|
||||
currentStep: SyncStep.categories,
|
||||
progress: 0.05,
|
||||
message: 'Membersihkan data lama...',
|
||||
errorMessage: null,
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
// Step 1: Clear existing local data
|
||||
await _productRepository.clearAllProducts();
|
||||
await _categoryRepository.clearAllCategories();
|
||||
|
||||
if (_isCancelled) return;
|
||||
|
||||
// Step 2: Sync categories first
|
||||
await _syncCategories(emit);
|
||||
|
||||
if (_isCancelled) return;
|
||||
|
||||
// Step 3: Sync products
|
||||
await _syncProducts(emit);
|
||||
|
||||
if (_isCancelled) return;
|
||||
|
||||
// Step 4: Final stats
|
||||
emit(
|
||||
state.copyWith(
|
||||
currentStep: SyncStep.completed,
|
||||
progress: 0.95,
|
||||
message: 'Menyelesaikan sinkronisasi...',
|
||||
),
|
||||
);
|
||||
|
||||
final stats = await _generateSyncStats();
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: false,
|
||||
stats: stats,
|
||||
progress: 1.0,
|
||||
message: 'Sinkronisasi selesai ✅',
|
||||
),
|
||||
);
|
||||
|
||||
log('✅ Full sync completed successfully');
|
||||
} catch (e) {
|
||||
log('❌ Sync failed: $e');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: false,
|
||||
errorMessage: 'Gagal sinkronisasi: $e',
|
||||
message: 'Sinkronisasi gagal ❌',
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
cancelSync: (e) async {
|
||||
log('⏹️ Cancelling sync...');
|
||||
_isCancelled = true;
|
||||
_progressTimer?.cancel();
|
||||
emit(SyncState.initial());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _syncCategories(Emitter<SyncState> emit) async {
|
||||
log('📁 Syncing categories...');
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: true,
|
||||
currentStep: SyncStep.categories,
|
||||
progress: 0.1,
|
||||
message: 'Mengunduh kategori...',
|
||||
errorMessage: null,
|
||||
),
|
||||
);
|
||||
|
||||
try {
|
||||
// Gunakan CategoryRepository sync method
|
||||
final result = await _categoryRepository.syncAllCategories();
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
throw Exception('Gagal sync kategori: $failure');
|
||||
},
|
||||
(successMessage) async {
|
||||
log('✅ Categories sync completed: $successMessage');
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
currentStep: SyncStep.categories,
|
||||
progress: 0.2,
|
||||
message: 'Kategori berhasil diunduh ✅',
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
log('❌ Category sync failed: $e');
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: false,
|
||||
errorMessage: 'Gagal sync kategori: $e',
|
||||
message: 'Sinkronisasi kategori gagal ❌',
|
||||
),
|
||||
);
|
||||
rethrow; // penting agar _onStartSync tahu kalau gagal
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _syncProducts(Emitter<SyncState> emit) async {
|
||||
log('📦 Syncing products...');
|
||||
|
||||
int page = 1;
|
||||
int totalSynced = 0;
|
||||
int? totalCount;
|
||||
int? totalPages;
|
||||
bool shouldContinue = true;
|
||||
|
||||
while (!_isCancelled && shouldContinue) {
|
||||
// Hitung progress dinamis (kategori 0.0–0.2, produk 0.2–0.9)
|
||||
double progress = 0.2;
|
||||
if (totalCount != null && totalCount! > 0) {
|
||||
progress = 0.2 + (totalSynced / totalCount!) * 0.7;
|
||||
}
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: true,
|
||||
currentStep: SyncStep.products,
|
||||
progress: progress,
|
||||
message: totalCount != null
|
||||
? 'Mengunduh produk... ($totalSynced dari $totalCount)'
|
||||
: 'Mengunduh produk... ($totalSynced produk)',
|
||||
errorMessage: null,
|
||||
),
|
||||
);
|
||||
|
||||
final result = await _productRepository.getRemoteProducts(
|
||||
page: page,
|
||||
limit: 50, // ambil batch besar biar cepat
|
||||
);
|
||||
|
||||
await result.fold(
|
||||
(failure) async {
|
||||
emit(
|
||||
state.copyWith(
|
||||
isSyncing: false,
|
||||
errorMessage: 'Gagal sync produk: $failure',
|
||||
message: 'Sinkronisasi produk gagal ❌',
|
||||
),
|
||||
);
|
||||
throw Exception(failure);
|
||||
},
|
||||
(response) async {
|
||||
final products = response.products;
|
||||
final responseData = response;
|
||||
|
||||
// Ambil total count & total page dari respons pertama
|
||||
if (page == 1) {
|
||||
totalCount = responseData.totalCount;
|
||||
totalPages = responseData.totalPages;
|
||||
log('📊 Total products to sync: $totalCount ($totalPages pages)');
|
||||
}
|
||||
|
||||
if (products.isEmpty) {
|
||||
shouldContinue = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Simpan batch produk ke local DB
|
||||
await _productRepository.saveProductsBatch(products);
|
||||
|
||||
totalSynced += products.length;
|
||||
page++;
|
||||
|
||||
log(
|
||||
'📦 Synced page ${page - 1}: ${products.length} products (Total: $totalSynced)',
|
||||
);
|
||||
|
||||
// Cek apakah sudah selesai sync
|
||||
if (totalPages != null && page > totalPages!) {
|
||||
shouldContinue = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback jika pagination info tidak lengkap
|
||||
if (products.length < 50) {
|
||||
shouldContinue = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Tambahkan delay kecil agar tidak overload server
|
||||
await Future.delayed(const Duration(milliseconds: 100));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Selesai sync produk
|
||||
emit(
|
||||
state.copyWith(
|
||||
progress: 0.9,
|
||||
message: 'Sinkronisasi produk selesai ✅ ($totalSynced total)',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<SyncStats> _generateSyncStats() async {
|
||||
try {
|
||||
log('📊 Generating sync statistics via repository...');
|
||||
|
||||
// Jalankan kedua query secara paralel untuk efisiensi
|
||||
final results = await Future.wait([
|
||||
_productRepository.getDatabaseStats(),
|
||||
_categoryRepository.getDatabaseStats(),
|
||||
]);
|
||||
|
||||
// Default kosong
|
||||
Map<String, dynamic> productStats = {};
|
||||
Map<String, dynamic> categoryStats = {};
|
||||
|
||||
// Ambil hasil product stats
|
||||
await results[0].fold(
|
||||
(failure) async {
|
||||
log('⚠️ Failed to get product stats: $failure');
|
||||
},
|
||||
(data) async {
|
||||
productStats = data;
|
||||
},
|
||||
);
|
||||
|
||||
// Ambil hasil category stats
|
||||
await results[1].fold(
|
||||
(failure) async {
|
||||
log('⚠️ Failed to get category stats: $failure');
|
||||
},
|
||||
(data) async {
|
||||
categoryStats = data;
|
||||
},
|
||||
);
|
||||
|
||||
// Bangun objek SyncStats akhir
|
||||
final stats = SyncStats(
|
||||
totalProducts: productStats['total_products'] ?? 0,
|
||||
totalCategories: categoryStats['total_categories'] ?? 0,
|
||||
totalVariants: productStats['total_variants'] ?? 0,
|
||||
databaseSizeMB:
|
||||
((productStats['database_size_mb'] ?? 0.0) as num).toDouble() +
|
||||
((categoryStats['database_size_mb'] ?? 0.0) as num).toDouble(),
|
||||
);
|
||||
|
||||
log('✅ Sync stats generated: $stats');
|
||||
return stats;
|
||||
} catch (e, stack) {
|
||||
log('❌ Error generating sync stats: $e\n$stack');
|
||||
return SyncStats(
|
||||
totalProducts: 0,
|
||||
totalCategories: 0,
|
||||
totalVariants: 0,
|
||||
databaseSizeMB: 0.0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() {
|
||||
_progressTimer?.cancel();
|
||||
return super.close();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// 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 'sync_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SyncEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() startSync,
|
||||
required TResult Function() cancelSync,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? startSync,
|
||||
TResult? Function()? cancelSync,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? startSync,
|
||||
TResult Function()? cancelSync,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_StartSync value) startSync,
|
||||
required TResult Function(_CancelSync value) cancelSync,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_StartSync value)? startSync,
|
||||
TResult? Function(_CancelSync value)? cancelSync,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_StartSync value)? startSync,
|
||||
TResult Function(_CancelSync value)? cancelSync,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $SyncEventCopyWith<$Res> {
|
||||
factory $SyncEventCopyWith(SyncEvent value, $Res Function(SyncEvent) then) =
|
||||
_$SyncEventCopyWithImpl<$Res, SyncEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$SyncEventCopyWithImpl<$Res, $Val extends SyncEvent>
|
||||
implements $SyncEventCopyWith<$Res> {
|
||||
_$SyncEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of SyncEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$StartSyncImplCopyWith<$Res> {
|
||||
factory _$$StartSyncImplCopyWith(
|
||||
_$StartSyncImpl value,
|
||||
$Res Function(_$StartSyncImpl) then,
|
||||
) = __$$StartSyncImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$StartSyncImplCopyWithImpl<$Res>
|
||||
extends _$SyncEventCopyWithImpl<$Res, _$StartSyncImpl>
|
||||
implements _$$StartSyncImplCopyWith<$Res> {
|
||||
__$$StartSyncImplCopyWithImpl(
|
||||
_$StartSyncImpl _value,
|
||||
$Res Function(_$StartSyncImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of SyncEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$StartSyncImpl implements _StartSync {
|
||||
const _$StartSyncImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SyncEvent.startSync()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$StartSyncImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() startSync,
|
||||
required TResult Function() cancelSync,
|
||||
}) {
|
||||
return startSync();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? startSync,
|
||||
TResult? Function()? cancelSync,
|
||||
}) {
|
||||
return startSync?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? startSync,
|
||||
TResult Function()? cancelSync,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (startSync != null) {
|
||||
return startSync();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_StartSync value) startSync,
|
||||
required TResult Function(_CancelSync value) cancelSync,
|
||||
}) {
|
||||
return startSync(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_StartSync value)? startSync,
|
||||
TResult? Function(_CancelSync value)? cancelSync,
|
||||
}) {
|
||||
return startSync?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_StartSync value)? startSync,
|
||||
TResult Function(_CancelSync value)? cancelSync,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (startSync != null) {
|
||||
return startSync(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _StartSync implements SyncEvent {
|
||||
const factory _StartSync() = _$StartSyncImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$CancelSyncImplCopyWith<$Res> {
|
||||
factory _$$CancelSyncImplCopyWith(
|
||||
_$CancelSyncImpl value,
|
||||
$Res Function(_$CancelSyncImpl) then,
|
||||
) = __$$CancelSyncImplCopyWithImpl<$Res>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$CancelSyncImplCopyWithImpl<$Res>
|
||||
extends _$SyncEventCopyWithImpl<$Res, _$CancelSyncImpl>
|
||||
implements _$$CancelSyncImplCopyWith<$Res> {
|
||||
__$$CancelSyncImplCopyWithImpl(
|
||||
_$CancelSyncImpl _value,
|
||||
$Res Function(_$CancelSyncImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of SyncEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$CancelSyncImpl implements _CancelSync {
|
||||
const _$CancelSyncImpl();
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SyncEvent.cancelSync()';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType && other is _$CancelSyncImpl);
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => runtimeType.hashCode;
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() startSync,
|
||||
required TResult Function() cancelSync,
|
||||
}) {
|
||||
return cancelSync();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function()? startSync,
|
||||
TResult? Function()? cancelSync,
|
||||
}) {
|
||||
return cancelSync?.call();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? startSync,
|
||||
TResult Function()? cancelSync,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (cancelSync != null) {
|
||||
return cancelSync();
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_StartSync value) startSync,
|
||||
required TResult Function(_CancelSync value) cancelSync,
|
||||
}) {
|
||||
return cancelSync(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_StartSync value)? startSync,
|
||||
TResult? Function(_CancelSync value)? cancelSync,
|
||||
}) {
|
||||
return cancelSync?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_StartSync value)? startSync,
|
||||
TResult Function(_CancelSync value)? cancelSync,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (cancelSync != null) {
|
||||
return cancelSync(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _CancelSync implements SyncEvent {
|
||||
const factory _CancelSync() = _$CancelSyncImpl;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$SyncState {
|
||||
bool get isSyncing => throw _privateConstructorUsedError;
|
||||
double get progress => throw _privateConstructorUsedError;
|
||||
SyncStep? get currentStep => throw _privateConstructorUsedError;
|
||||
String? get message => throw _privateConstructorUsedError;
|
||||
SyncStats? get stats => throw _privateConstructorUsedError;
|
||||
String? get errorMessage => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of SyncState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$SyncStateCopyWith<SyncState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $SyncStateCopyWith<$Res> {
|
||||
factory $SyncStateCopyWith(SyncState value, $Res Function(SyncState) then) =
|
||||
_$SyncStateCopyWithImpl<$Res, SyncState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isSyncing,
|
||||
double progress,
|
||||
SyncStep? currentStep,
|
||||
String? message,
|
||||
SyncStats? stats,
|
||||
String? errorMessage,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$SyncStateCopyWithImpl<$Res, $Val extends SyncState>
|
||||
implements $SyncStateCopyWith<$Res> {
|
||||
_$SyncStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of SyncState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? isSyncing = null,
|
||||
Object? progress = null,
|
||||
Object? currentStep = freezed,
|
||||
Object? message = freezed,
|
||||
Object? stats = freezed,
|
||||
Object? errorMessage = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
isSyncing: null == isSyncing
|
||||
? _value.isSyncing
|
||||
: isSyncing // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
progress: null == progress
|
||||
? _value.progress
|
||||
: progress // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
currentStep: freezed == currentStep
|
||||
? _value.currentStep
|
||||
: currentStep // ignore: cast_nullable_to_non_nullable
|
||||
as SyncStep?,
|
||||
message: freezed == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
stats: freezed == stats
|
||||
? _value.stats
|
||||
: stats // ignore: cast_nullable_to_non_nullable
|
||||
as SyncStats?,
|
||||
errorMessage: freezed == errorMessage
|
||||
? _value.errorMessage
|
||||
: errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SyncStateImplCopyWith<$Res>
|
||||
implements $SyncStateCopyWith<$Res> {
|
||||
factory _$$SyncStateImplCopyWith(
|
||||
_$SyncStateImpl value,
|
||||
$Res Function(_$SyncStateImpl) then,
|
||||
) = __$$SyncStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
bool isSyncing,
|
||||
double progress,
|
||||
SyncStep? currentStep,
|
||||
String? message,
|
||||
SyncStats? stats,
|
||||
String? errorMessage,
|
||||
});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SyncStateImplCopyWithImpl<$Res>
|
||||
extends _$SyncStateCopyWithImpl<$Res, _$SyncStateImpl>
|
||||
implements _$$SyncStateImplCopyWith<$Res> {
|
||||
__$$SyncStateImplCopyWithImpl(
|
||||
_$SyncStateImpl _value,
|
||||
$Res Function(_$SyncStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of SyncState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? isSyncing = null,
|
||||
Object? progress = null,
|
||||
Object? currentStep = freezed,
|
||||
Object? message = freezed,
|
||||
Object? stats = freezed,
|
||||
Object? errorMessage = freezed,
|
||||
}) {
|
||||
return _then(
|
||||
_$SyncStateImpl(
|
||||
isSyncing: null == isSyncing
|
||||
? _value.isSyncing
|
||||
: isSyncing // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
progress: null == progress
|
||||
? _value.progress
|
||||
: progress // ignore: cast_nullable_to_non_nullable
|
||||
as double,
|
||||
currentStep: freezed == currentStep
|
||||
? _value.currentStep
|
||||
: currentStep // ignore: cast_nullable_to_non_nullable
|
||||
as SyncStep?,
|
||||
message: freezed == message
|
||||
? _value.message
|
||||
: message // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
stats: freezed == stats
|
||||
? _value.stats
|
||||
: stats // ignore: cast_nullable_to_non_nullable
|
||||
as SyncStats?,
|
||||
errorMessage: freezed == errorMessage
|
||||
? _value.errorMessage
|
||||
: errorMessage // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SyncStateImpl implements _SyncState {
|
||||
const _$SyncStateImpl({
|
||||
this.isSyncing = false,
|
||||
this.progress = 0.0,
|
||||
this.currentStep,
|
||||
this.message,
|
||||
this.stats,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isSyncing;
|
||||
@override
|
||||
@JsonKey()
|
||||
final double progress;
|
||||
@override
|
||||
final SyncStep? currentStep;
|
||||
@override
|
||||
final String? message;
|
||||
@override
|
||||
final SyncStats? stats;
|
||||
@override
|
||||
final String? errorMessage;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'SyncState(isSyncing: $isSyncing, progress: $progress, currentStep: $currentStep, message: $message, stats: $stats, errorMessage: $errorMessage)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SyncStateImpl &&
|
||||
(identical(other.isSyncing, isSyncing) ||
|
||||
other.isSyncing == isSyncing) &&
|
||||
(identical(other.progress, progress) ||
|
||||
other.progress == progress) &&
|
||||
(identical(other.currentStep, currentStep) ||
|
||||
other.currentStep == currentStep) &&
|
||||
(identical(other.message, message) || other.message == message) &&
|
||||
(identical(other.stats, stats) || other.stats == stats) &&
|
||||
(identical(other.errorMessage, errorMessage) ||
|
||||
other.errorMessage == errorMessage));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
isSyncing,
|
||||
progress,
|
||||
currentStep,
|
||||
message,
|
||||
stats,
|
||||
errorMessage,
|
||||
);
|
||||
|
||||
/// Create a copy of SyncState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SyncStateImplCopyWith<_$SyncStateImpl> get copyWith =>
|
||||
__$$SyncStateImplCopyWithImpl<_$SyncStateImpl>(this, _$identity);
|
||||
}
|
||||
|
||||
abstract class _SyncState implements SyncState {
|
||||
const factory _SyncState({
|
||||
final bool isSyncing,
|
||||
final double progress,
|
||||
final SyncStep? currentStep,
|
||||
final String? message,
|
||||
final SyncStats? stats,
|
||||
final String? errorMessage,
|
||||
}) = _$SyncStateImpl;
|
||||
|
||||
@override
|
||||
bool get isSyncing;
|
||||
@override
|
||||
double get progress;
|
||||
@override
|
||||
SyncStep? get currentStep;
|
||||
@override
|
||||
String? get message;
|
||||
@override
|
||||
SyncStats? get stats;
|
||||
@override
|
||||
String? get errorMessage;
|
||||
|
||||
/// Create a copy of SyncState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SyncStateImplCopyWith<_$SyncStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
part of 'sync_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class SyncEvent with _$SyncEvent {
|
||||
const factory SyncEvent.startSync() = _StartSync;
|
||||
const factory SyncEvent.cancelSync() = _CancelSync;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
part of 'sync_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class SyncState with _$SyncState {
|
||||
const factory SyncState({
|
||||
@Default(false) bool isSyncing,
|
||||
@Default(0.0) double progress,
|
||||
SyncStep? currentStep,
|
||||
String? message,
|
||||
SyncStats? stats,
|
||||
String? errorMessage,
|
||||
}) = _SyncState;
|
||||
|
||||
factory SyncState.initial() => const SyncState();
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/table/table.dart';
|
||||
|
||||
part 'table_form_event.dart';
|
||||
part 'table_form_state.dart';
|
||||
part 'table_form_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class TableFormBloc extends Bloc<TableFormEvent, TableFormState> {
|
||||
final ITableRepository _repository;
|
||||
TableFormBloc(this._repository) : super(TableFormState.initial()) {
|
||||
on<TableFormEvent>(_onTableFormEvent);
|
||||
}
|
||||
|
||||
Future<void> _onTableFormEvent(
|
||||
TableFormEvent event,
|
||||
Emitter<TableFormState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
nameChanged: (e) async {
|
||||
emit(state.copyWith(name: e.name));
|
||||
},
|
||||
capacityChanged: (e) async {
|
||||
emit(state.copyWith(capacity: int.tryParse(e.capacity) ?? 0));
|
||||
},
|
||||
created: (e) async {
|
||||
Either<TableFailure, Table> failureOrTable;
|
||||
|
||||
emit(state.copyWith(isCreating: true, failureOrTable: none()));
|
||||
|
||||
final isNameValid = state.name.isNotEmpty;
|
||||
final isCapacityValid = state.capacity > 0;
|
||||
|
||||
if (isNameValid && isCapacityValid) {
|
||||
failureOrTable = await _repository.createTable(
|
||||
name: state.name,
|
||||
capacity: state.capacity,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
failureOrTable: optionOf(failureOrTable),
|
||||
isCreating: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
emit(state.copyWith(failureOrTable: none(), isCreating: false));
|
||||
},
|
||||
updated: (e) async {
|
||||
emit(state.copyWith(isUpdating: true, failureOrTable: none()));
|
||||
|
||||
await _repository.updatePosition(id: e.id, position: e.position);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
// failureOrTable: optionOf(failureOrTable),
|
||||
isUpdating: false,
|
||||
),
|
||||
);
|
||||
},
|
||||
transfer: (e) async {
|
||||
Either<TableFailure, Unit> failureOrTableTransfer;
|
||||
|
||||
emit(
|
||||
state.copyWith(isTransfering: true, failureOrTableTransfer: none()),
|
||||
);
|
||||
|
||||
final isFromTableIdValid = e.fromTableId.isNotEmpty;
|
||||
final isToTableIdValid = e.toTableId.isNotEmpty;
|
||||
|
||||
if (isFromTableIdValid && isToTableIdValid) {
|
||||
failureOrTableTransfer = await _repository.transferTable(
|
||||
fromTableId: e.fromTableId,
|
||||
toTableId: e.toTableId,
|
||||
);
|
||||
|
||||
emit(
|
||||
state.copyWith(
|
||||
failureOrTableTransfer: optionOf(failureOrTableTransfer),
|
||||
isTransfering: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
emit(state.copyWith(failureOrTable: none(), isCreating: false));
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
part of 'table_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class TableFormEvent with _$TableFormEvent {
|
||||
const factory TableFormEvent.nameChanged(String name) = _NameChanged;
|
||||
const factory TableFormEvent.capacityChanged(String capacity) =
|
||||
_CapacityChanged;
|
||||
const factory TableFormEvent.created() = _Created;
|
||||
const factory TableFormEvent.updated({
|
||||
required String id,
|
||||
required Offset position,
|
||||
}) = _Updated;
|
||||
const factory TableFormEvent.transfer({
|
||||
required String fromTableId,
|
||||
required String toTableId,
|
||||
}) = _Transfer;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
part of 'table_form_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class TableFormState with _$TableFormState {
|
||||
factory TableFormState({
|
||||
required String name,
|
||||
required int capacity,
|
||||
required Option<Either<TableFailure, Table>> failureOrTable,
|
||||
required Option<Either<TableFailure, Unit>> failureOrTableTransfer,
|
||||
@Default(false) bool isUpdating,
|
||||
@Default(false) bool isCreating,
|
||||
@Default(false) bool isTransfering,
|
||||
}) = _TableFormState;
|
||||
|
||||
factory TableFormState.initial() => TableFormState(
|
||||
failureOrTable: none(),
|
||||
name: '',
|
||||
capacity: 0,
|
||||
failureOrTableTransfer: none(),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:dartz/dartz.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../../domain/table/table.dart';
|
||||
|
||||
part 'table_loader_event.dart';
|
||||
part 'table_loader_state.dart';
|
||||
part 'table_loader_bloc.freezed.dart';
|
||||
|
||||
@injectable
|
||||
class TableLoaderBloc extends Bloc<TableLoaderEvent, TableLoaderState> {
|
||||
final ITableRepository _repository;
|
||||
TableLoaderBloc(this._repository) : super(TableLoaderState.initial()) {
|
||||
on<TableLoaderEvent>(_onTableLoadedEvent);
|
||||
}
|
||||
|
||||
Future<void> _onTableLoadedEvent(
|
||||
TableLoaderEvent event,
|
||||
Emitter<TableLoaderState> emit,
|
||||
) {
|
||||
return event.map(
|
||||
setSelectedTable: (e) async {
|
||||
if (e.table == null) {
|
||||
emit(state.copyWith(selectedTable: null));
|
||||
} else {
|
||||
if (e.table?.status.isAvailable ?? false) {
|
||||
emit(state.copyWith(selectedTable: e.table));
|
||||
}
|
||||
}
|
||||
},
|
||||
fetched: (e) async {
|
||||
var newState = state;
|
||||
|
||||
if (e.isRefresh) {
|
||||
newState = newState.copyWith(isFetching: true);
|
||||
emit(newState);
|
||||
}
|
||||
|
||||
newState = await _mapFetchedToState(
|
||||
newState,
|
||||
isRefresh: e.isRefresh,
|
||||
status: e.status,
|
||||
);
|
||||
emit(newState);
|
||||
},
|
||||
updatedPostion: (e) async {
|
||||
final updatedTables = state.tables.map((table) {
|
||||
if (table.id == e.id) {
|
||||
return table.copyWith(
|
||||
positionX: e.position.dx,
|
||||
positionY: e.position.dy,
|
||||
);
|
||||
}
|
||||
return table;
|
||||
}).toList();
|
||||
|
||||
emit(state.copyWith(tables: updatedTables));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<TableLoaderState> _mapFetchedToState(
|
||||
TableLoaderState state, {
|
||||
bool isRefresh = false,
|
||||
String? status,
|
||||
}) async {
|
||||
state = state.copyWith(isFetching: false);
|
||||
|
||||
if (state.hasReachedMax && state.tables.isNotEmpty && !isRefresh) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (isRefresh) {
|
||||
state = state.copyWith(
|
||||
page: 1,
|
||||
failureOption: none(),
|
||||
hasReachedMax: false,
|
||||
tables: [],
|
||||
);
|
||||
}
|
||||
|
||||
final failureOrTable = await _repository.fetchTables(
|
||||
page: state.page,
|
||||
status: status,
|
||||
);
|
||||
|
||||
state = failureOrTable.fold(
|
||||
(f) {
|
||||
if (state.tables.isNotEmpty) {
|
||||
return state.copyWith(hasReachedMax: true);
|
||||
}
|
||||
return state.copyWith(failureOption: optionOf(f));
|
||||
},
|
||||
(tables) {
|
||||
return state.copyWith(
|
||||
tables: List.from(state.tables)..addAll(tables.tables),
|
||||
failureOption: none(),
|
||||
page: state.page + 1,
|
||||
hasReachedMax: tables.tables.length < 10,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
return state;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,856 @@
|
||||
// coverage:ignore-file
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint
|
||||
// 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 'table_loader_bloc.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// FreezedGenerator
|
||||
// **************************************************************************
|
||||
|
||||
T _$identity<T>(T value) => value;
|
||||
|
||||
final _privateConstructorUsedError = UnsupportedError(
|
||||
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models',
|
||||
);
|
||||
|
||||
/// @nodoc
|
||||
mixin _$TableLoaderEvent {
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh, String? status) fetched,
|
||||
required TResult Function(String id, Offset position) updatedPostion,
|
||||
required TResult Function(Table? table) setSelectedTable,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh, String? status)? fetched,
|
||||
TResult? Function(String id, Offset position)? updatedPostion,
|
||||
TResult? Function(Table? table)? setSelectedTable,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh, String? status)? fetched,
|
||||
TResult Function(String id, Offset position)? updatedPostion,
|
||||
TResult Function(Table? table)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_UpdatedPosition value) updatedPostion,
|
||||
required TResult Function(_SetSelectedTable value) setSelectedTable,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult? Function(_SetSelectedTable value)? setSelectedTable,
|
||||
}) => throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult Function(_SetSelectedTable value)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) => throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $TableLoaderEventCopyWith<$Res> {
|
||||
factory $TableLoaderEventCopyWith(
|
||||
TableLoaderEvent value,
|
||||
$Res Function(TableLoaderEvent) then,
|
||||
) = _$TableLoaderEventCopyWithImpl<$Res, TableLoaderEvent>;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TableLoaderEventCopyWithImpl<$Res, $Val extends TableLoaderEvent>
|
||||
implements $TableLoaderEventCopyWith<$Res> {
|
||||
_$TableLoaderEventCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$FetchedImplCopyWith<$Res> {
|
||||
factory _$$FetchedImplCopyWith(
|
||||
_$FetchedImpl value,
|
||||
$Res Function(_$FetchedImpl) then,
|
||||
) = __$$FetchedImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({bool isRefresh, String? status});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$FetchedImplCopyWithImpl<$Res>
|
||||
extends _$TableLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
|
||||
implements _$$FetchedImplCopyWith<$Res> {
|
||||
__$$FetchedImplCopyWithImpl(
|
||||
_$FetchedImpl _value,
|
||||
$Res Function(_$FetchedImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? isRefresh = null, Object? status = freezed}) {
|
||||
return _then(
|
||||
_$FetchedImpl(
|
||||
isRefresh: null == isRefresh
|
||||
? _value.isRefresh
|
||||
: isRefresh // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
status: freezed == status
|
||||
? _value.status
|
||||
: status // ignore: cast_nullable_to_non_nullable
|
||||
as String?,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$FetchedImpl implements _Fetched {
|
||||
const _$FetchedImpl({this.isRefresh = false, this.status});
|
||||
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isRefresh;
|
||||
@override
|
||||
final String? status;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableLoaderEvent.fetched(isRefresh: $isRefresh, status: $status)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$FetchedImpl &&
|
||||
(identical(other.isRefresh, isRefresh) ||
|
||||
other.isRefresh == isRefresh) &&
|
||||
(identical(other.status, status) || other.status == status));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, isRefresh, status);
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
__$$FetchedImplCopyWithImpl<_$FetchedImpl>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh, String? status) fetched,
|
||||
required TResult Function(String id, Offset position) updatedPostion,
|
||||
required TResult Function(Table? table) setSelectedTable,
|
||||
}) {
|
||||
return fetched(isRefresh, status);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh, String? status)? fetched,
|
||||
TResult? Function(String id, Offset position)? updatedPostion,
|
||||
TResult? Function(Table? table)? setSelectedTable,
|
||||
}) {
|
||||
return fetched?.call(isRefresh, status);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh, String? status)? fetched,
|
||||
TResult Function(String id, Offset position)? updatedPostion,
|
||||
TResult Function(Table? table)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(isRefresh, status);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_UpdatedPosition value) updatedPostion,
|
||||
required TResult Function(_SetSelectedTable value) setSelectedTable,
|
||||
}) {
|
||||
return fetched(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult? Function(_SetSelectedTable value)? setSelectedTable,
|
||||
}) {
|
||||
return fetched?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult Function(_SetSelectedTable value)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (fetched != null) {
|
||||
return fetched(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _Fetched implements TableLoaderEvent {
|
||||
const factory _Fetched({final bool isRefresh, final String? status}) =
|
||||
_$FetchedImpl;
|
||||
|
||||
bool get isRefresh;
|
||||
String? get status;
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$UpdatedPositionImplCopyWith<$Res> {
|
||||
factory _$$UpdatedPositionImplCopyWith(
|
||||
_$UpdatedPositionImpl value,
|
||||
$Res Function(_$UpdatedPositionImpl) then,
|
||||
) = __$$UpdatedPositionImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({String id, Offset position});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$UpdatedPositionImplCopyWithImpl<$Res>
|
||||
extends _$TableLoaderEventCopyWithImpl<$Res, _$UpdatedPositionImpl>
|
||||
implements _$$UpdatedPositionImplCopyWith<$Res> {
|
||||
__$$UpdatedPositionImplCopyWithImpl(
|
||||
_$UpdatedPositionImpl _value,
|
||||
$Res Function(_$UpdatedPositionImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? id = null, Object? position = null}) {
|
||||
return _then(
|
||||
_$UpdatedPositionImpl(
|
||||
id: null == id
|
||||
? _value.id
|
||||
: id // ignore: cast_nullable_to_non_nullable
|
||||
as String,
|
||||
position: null == position
|
||||
? _value.position
|
||||
: position // ignore: cast_nullable_to_non_nullable
|
||||
as Offset,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$UpdatedPositionImpl implements _UpdatedPosition {
|
||||
const _$UpdatedPositionImpl({required this.id, required this.position});
|
||||
|
||||
@override
|
||||
final String id;
|
||||
@override
|
||||
final Offset position;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableLoaderEvent.updatedPostion(id: $id, position: $position)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$UpdatedPositionImpl &&
|
||||
(identical(other.id, id) || other.id == id) &&
|
||||
(identical(other.position, position) ||
|
||||
other.position == position));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, id, position);
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$UpdatedPositionImplCopyWith<_$UpdatedPositionImpl> get copyWith =>
|
||||
__$$UpdatedPositionImplCopyWithImpl<_$UpdatedPositionImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh, String? status) fetched,
|
||||
required TResult Function(String id, Offset position) updatedPostion,
|
||||
required TResult Function(Table? table) setSelectedTable,
|
||||
}) {
|
||||
return updatedPostion(id, position);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh, String? status)? fetched,
|
||||
TResult? Function(String id, Offset position)? updatedPostion,
|
||||
TResult? Function(Table? table)? setSelectedTable,
|
||||
}) {
|
||||
return updatedPostion?.call(id, position);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh, String? status)? fetched,
|
||||
TResult Function(String id, Offset position)? updatedPostion,
|
||||
TResult Function(Table? table)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updatedPostion != null) {
|
||||
return updatedPostion(id, position);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_UpdatedPosition value) updatedPostion,
|
||||
required TResult Function(_SetSelectedTable value) setSelectedTable,
|
||||
}) {
|
||||
return updatedPostion(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult? Function(_SetSelectedTable value)? setSelectedTable,
|
||||
}) {
|
||||
return updatedPostion?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult Function(_SetSelectedTable value)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (updatedPostion != null) {
|
||||
return updatedPostion(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _UpdatedPosition implements TableLoaderEvent {
|
||||
const factory _UpdatedPosition({
|
||||
required final String id,
|
||||
required final Offset position,
|
||||
}) = _$UpdatedPositionImpl;
|
||||
|
||||
String get id;
|
||||
Offset get position;
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$UpdatedPositionImplCopyWith<_$UpdatedPositionImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$SetSelectedTableImplCopyWith<$Res> {
|
||||
factory _$$SetSelectedTableImplCopyWith(
|
||||
_$SetSelectedTableImpl value,
|
||||
$Res Function(_$SetSelectedTableImpl) then,
|
||||
) = __$$SetSelectedTableImplCopyWithImpl<$Res>;
|
||||
@useResult
|
||||
$Res call({Table? table});
|
||||
|
||||
$TableCopyWith<$Res>? get table;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$SetSelectedTableImplCopyWithImpl<$Res>
|
||||
extends _$TableLoaderEventCopyWithImpl<$Res, _$SetSelectedTableImpl>
|
||||
implements _$$SetSelectedTableImplCopyWith<$Res> {
|
||||
__$$SetSelectedTableImplCopyWithImpl(
|
||||
_$SetSelectedTableImpl _value,
|
||||
$Res Function(_$SetSelectedTableImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({Object? table = freezed}) {
|
||||
return _then(
|
||||
_$SetSelectedTableImpl(
|
||||
freezed == table
|
||||
? _value.table
|
||||
: table // ignore: cast_nullable_to_non_nullable
|
||||
as Table?,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$TableCopyWith<$Res>? get table {
|
||||
if (_value.table == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $TableCopyWith<$Res>(_value.table!, (value) {
|
||||
return _then(_value.copyWith(table: value));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$SetSelectedTableImpl implements _SetSelectedTable {
|
||||
const _$SetSelectedTableImpl(this.table);
|
||||
|
||||
@override
|
||||
final Table? table;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableLoaderEvent.setSelectedTable(table: $table)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$SetSelectedTableImpl &&
|
||||
(identical(other.table, table) || other.table == table));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(runtimeType, table);
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$SetSelectedTableImplCopyWith<_$SetSelectedTableImpl> get copyWith =>
|
||||
__$$SetSelectedTableImplCopyWithImpl<_$SetSelectedTableImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function(bool isRefresh, String? status) fetched,
|
||||
required TResult Function(String id, Offset position) updatedPostion,
|
||||
required TResult Function(Table? table) setSelectedTable,
|
||||
}) {
|
||||
return setSelectedTable(table);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? whenOrNull<TResult extends Object?>({
|
||||
TResult? Function(bool isRefresh, String? status)? fetched,
|
||||
TResult? Function(String id, Offset position)? updatedPostion,
|
||||
TResult? Function(Table? table)? setSelectedTable,
|
||||
}) {
|
||||
return setSelectedTable?.call(table);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function(bool isRefresh, String? status)? fetched,
|
||||
TResult Function(String id, Offset position)? updatedPostion,
|
||||
TResult Function(Table? table)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (setSelectedTable != null) {
|
||||
return setSelectedTable(table);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(_Fetched value) fetched,
|
||||
required TResult Function(_UpdatedPosition value) updatedPostion,
|
||||
required TResult Function(_SetSelectedTable value) setSelectedTable,
|
||||
}) {
|
||||
return setSelectedTable(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult? mapOrNull<TResult extends Object?>({
|
||||
TResult? Function(_Fetched value)? fetched,
|
||||
TResult? Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult? Function(_SetSelectedTable value)? setSelectedTable,
|
||||
}) {
|
||||
return setSelectedTable?.call(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(_Fetched value)? fetched,
|
||||
TResult Function(_UpdatedPosition value)? updatedPostion,
|
||||
TResult Function(_SetSelectedTable value)? setSelectedTable,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (setSelectedTable != null) {
|
||||
return setSelectedTable(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _SetSelectedTable implements TableLoaderEvent {
|
||||
const factory _SetSelectedTable(final Table? table) = _$SetSelectedTableImpl;
|
||||
|
||||
Table? get table;
|
||||
|
||||
/// Create a copy of TableLoaderEvent
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$SetSelectedTableImplCopyWith<_$SetSelectedTableImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
mixin _$TableLoaderState {
|
||||
List<Table> get tables => throw _privateConstructorUsedError;
|
||||
Option<TableFailure> get failureOption => throw _privateConstructorUsedError;
|
||||
Table? get selectedTable => throw _privateConstructorUsedError;
|
||||
bool get isFetching => throw _privateConstructorUsedError;
|
||||
bool get hasReachedMax => throw _privateConstructorUsedError;
|
||||
int get page => throw _privateConstructorUsedError;
|
||||
|
||||
/// Create a copy of TableLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
$TableLoaderStateCopyWith<TableLoaderState> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $TableLoaderStateCopyWith<$Res> {
|
||||
factory $TableLoaderStateCopyWith(
|
||||
TableLoaderState value,
|
||||
$Res Function(TableLoaderState) then,
|
||||
) = _$TableLoaderStateCopyWithImpl<$Res, TableLoaderState>;
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Table> tables,
|
||||
Option<TableFailure> failureOption,
|
||||
Table? selectedTable,
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
});
|
||||
|
||||
$TableCopyWith<$Res>? get selectedTable;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$TableLoaderStateCopyWithImpl<$Res, $Val extends TableLoaderState>
|
||||
implements $TableLoaderStateCopyWith<$Res> {
|
||||
_$TableLoaderStateCopyWithImpl(this._value, this._then);
|
||||
|
||||
// ignore: unused_field
|
||||
final $Val _value;
|
||||
// ignore: unused_field
|
||||
final $Res Function($Val) _then;
|
||||
|
||||
/// Create a copy of TableLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? tables = null,
|
||||
Object? failureOption = null,
|
||||
Object? selectedTable = freezed,
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_value.copyWith(
|
||||
tables: null == tables
|
||||
? _value.tables
|
||||
: tables // ignore: cast_nullable_to_non_nullable
|
||||
as List<Table>,
|
||||
failureOption: null == failureOption
|
||||
? _value.failureOption
|
||||
: failureOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<TableFailure>,
|
||||
selectedTable: freezed == selectedTable
|
||||
? _value.selectedTable
|
||||
: selectedTable // ignore: cast_nullable_to_non_nullable
|
||||
as Table?,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
)
|
||||
as $Val,
|
||||
);
|
||||
}
|
||||
|
||||
/// Create a copy of TableLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
$TableCopyWith<$Res>? get selectedTable {
|
||||
if (_value.selectedTable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $TableCopyWith<$Res>(_value.selectedTable!, (value) {
|
||||
return _then(_value.copyWith(selectedTable: value) as $Val);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class _$$TableLoaderStateImplCopyWith<$Res>
|
||||
implements $TableLoaderStateCopyWith<$Res> {
|
||||
factory _$$TableLoaderStateImplCopyWith(
|
||||
_$TableLoaderStateImpl value,
|
||||
$Res Function(_$TableLoaderStateImpl) then,
|
||||
) = __$$TableLoaderStateImplCopyWithImpl<$Res>;
|
||||
@override
|
||||
@useResult
|
||||
$Res call({
|
||||
List<Table> tables,
|
||||
Option<TableFailure> failureOption,
|
||||
Table? selectedTable,
|
||||
bool isFetching,
|
||||
bool hasReachedMax,
|
||||
int page,
|
||||
});
|
||||
|
||||
@override
|
||||
$TableCopyWith<$Res>? get selectedTable;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class __$$TableLoaderStateImplCopyWithImpl<$Res>
|
||||
extends _$TableLoaderStateCopyWithImpl<$Res, _$TableLoaderStateImpl>
|
||||
implements _$$TableLoaderStateImplCopyWith<$Res> {
|
||||
__$$TableLoaderStateImplCopyWithImpl(
|
||||
_$TableLoaderStateImpl _value,
|
||||
$Res Function(_$TableLoaderStateImpl) _then,
|
||||
) : super(_value, _then);
|
||||
|
||||
/// Create a copy of TableLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@pragma('vm:prefer-inline')
|
||||
@override
|
||||
$Res call({
|
||||
Object? tables = null,
|
||||
Object? failureOption = null,
|
||||
Object? selectedTable = freezed,
|
||||
Object? isFetching = null,
|
||||
Object? hasReachedMax = null,
|
||||
Object? page = null,
|
||||
}) {
|
||||
return _then(
|
||||
_$TableLoaderStateImpl(
|
||||
tables: null == tables
|
||||
? _value._tables
|
||||
: tables // ignore: cast_nullable_to_non_nullable
|
||||
as List<Table>,
|
||||
failureOption: null == failureOption
|
||||
? _value.failureOption
|
||||
: failureOption // ignore: cast_nullable_to_non_nullable
|
||||
as Option<TableFailure>,
|
||||
selectedTable: freezed == selectedTable
|
||||
? _value.selectedTable
|
||||
: selectedTable // ignore: cast_nullable_to_non_nullable
|
||||
as Table?,
|
||||
isFetching: null == isFetching
|
||||
? _value.isFetching
|
||||
: isFetching // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
hasReachedMax: null == hasReachedMax
|
||||
? _value.hasReachedMax
|
||||
: hasReachedMax // ignore: cast_nullable_to_non_nullable
|
||||
as bool,
|
||||
page: null == page
|
||||
? _value.page
|
||||
: page // ignore: cast_nullable_to_non_nullable
|
||||
as int,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$TableLoaderStateImpl implements _TableLoaderState {
|
||||
_$TableLoaderStateImpl({
|
||||
required final List<Table> tables,
|
||||
required this.failureOption,
|
||||
this.selectedTable,
|
||||
this.isFetching = false,
|
||||
this.hasReachedMax = false,
|
||||
this.page = 1,
|
||||
}) : _tables = tables;
|
||||
|
||||
final List<Table> _tables;
|
||||
@override
|
||||
List<Table> get tables {
|
||||
if (_tables is EqualUnmodifiableListView) return _tables;
|
||||
// ignore: implicit_dynamic_type
|
||||
return EqualUnmodifiableListView(_tables);
|
||||
}
|
||||
|
||||
@override
|
||||
final Option<TableFailure> failureOption;
|
||||
@override
|
||||
final Table? selectedTable;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool isFetching;
|
||||
@override
|
||||
@JsonKey()
|
||||
final bool hasReachedMax;
|
||||
@override
|
||||
@JsonKey()
|
||||
final int page;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'TableLoaderState(tables: $tables, failureOption: $failureOption, selectedTable: $selectedTable, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return identical(this, other) ||
|
||||
(other.runtimeType == runtimeType &&
|
||||
other is _$TableLoaderStateImpl &&
|
||||
const DeepCollectionEquality().equals(other._tables, _tables) &&
|
||||
(identical(other.failureOption, failureOption) ||
|
||||
other.failureOption == failureOption) &&
|
||||
(identical(other.selectedTable, selectedTable) ||
|
||||
other.selectedTable == selectedTable) &&
|
||||
(identical(other.isFetching, isFetching) ||
|
||||
other.isFetching == isFetching) &&
|
||||
(identical(other.hasReachedMax, hasReachedMax) ||
|
||||
other.hasReachedMax == hasReachedMax) &&
|
||||
(identical(other.page, page) || other.page == page));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode => Object.hash(
|
||||
runtimeType,
|
||||
const DeepCollectionEquality().hash(_tables),
|
||||
failureOption,
|
||||
selectedTable,
|
||||
isFetching,
|
||||
hasReachedMax,
|
||||
page,
|
||||
);
|
||||
|
||||
/// Create a copy of TableLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
@override
|
||||
@pragma('vm:prefer-inline')
|
||||
_$$TableLoaderStateImplCopyWith<_$TableLoaderStateImpl> get copyWith =>
|
||||
__$$TableLoaderStateImplCopyWithImpl<_$TableLoaderStateImpl>(
|
||||
this,
|
||||
_$identity,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class _TableLoaderState implements TableLoaderState {
|
||||
factory _TableLoaderState({
|
||||
required final List<Table> tables,
|
||||
required final Option<TableFailure> failureOption,
|
||||
final Table? selectedTable,
|
||||
final bool isFetching,
|
||||
final bool hasReachedMax,
|
||||
final int page,
|
||||
}) = _$TableLoaderStateImpl;
|
||||
|
||||
@override
|
||||
List<Table> get tables;
|
||||
@override
|
||||
Option<TableFailure> get failureOption;
|
||||
@override
|
||||
Table? get selectedTable;
|
||||
@override
|
||||
bool get isFetching;
|
||||
@override
|
||||
bool get hasReachedMax;
|
||||
@override
|
||||
int get page;
|
||||
|
||||
/// Create a copy of TableLoaderState
|
||||
/// with the given fields replaced by the non-null parameter values.
|
||||
@override
|
||||
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||
_$$TableLoaderStateImplCopyWith<_$TableLoaderStateImpl> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
part of 'table_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class TableLoaderEvent with _$TableLoaderEvent {
|
||||
const factory TableLoaderEvent.fetched({
|
||||
@Default(false) bool isRefresh,
|
||||
String? status,
|
||||
}) = _Fetched;
|
||||
const factory TableLoaderEvent.updatedPostion({
|
||||
required String id,
|
||||
required Offset position,
|
||||
}) = _UpdatedPosition;
|
||||
const factory TableLoaderEvent.setSelectedTable(Table? table) =
|
||||
_SetSelectedTable;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
part of 'table_loader_bloc.dart';
|
||||
|
||||
@freezed
|
||||
class TableLoaderState with _$TableLoaderState {
|
||||
factory TableLoaderState({
|
||||
required List<Table> tables,
|
||||
required Option<TableFailure> failureOption,
|
||||
Table? selectedTable,
|
||||
@Default(false) bool isFetching,
|
||||
@Default(false) bool hasReachedMax,
|
||||
@Default(1) int page,
|
||||
}) = _TableLoaderState;
|
||||
|
||||
factory TableLoaderState.initial() =>
|
||||
TableLoaderState(tables: [], failureOption: none());
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:awesome_dio_interceptor/awesome_dio_interceptor.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import '../../env.dart';
|
||||
import 'api_failure.dart';
|
||||
import 'errors/bad_network_error.dart';
|
||||
import 'errors/bad_request_error.dart';
|
||||
import 'errors/connection_timeout_error.dart';
|
||||
import 'errors/internal_server_error.dart';
|
||||
import 'errors/not_found_error.dart';
|
||||
import 'errors/unauthorized_error.dart';
|
||||
import 'interceptors/bad_network_interceptor.dart';
|
||||
import 'interceptors/bad_request_interceptor.dart';
|
||||
import 'interceptors/connection_timeout_interceptor.dart';
|
||||
import 'interceptors/crashlytic_interceptor.dart';
|
||||
import 'interceptors/internal_server_interceptor.dart';
|
||||
import 'interceptors/not_found_interceptor.dart';
|
||||
import 'interceptors/unauthorized_interceptor.dart';
|
||||
|
||||
@lazySingleton
|
||||
class ApiClient {
|
||||
final Dio _dio;
|
||||
final Env _env;
|
||||
|
||||
ApiClient(this._dio, this._env) {
|
||||
_dio.options.baseUrl = _env.baseUrl;
|
||||
_dio.options.connectTimeout = const Duration(seconds: 20);
|
||||
_dio.options.validateStatus = (status) =>
|
||||
status != null && status >= 200 && status < 500;
|
||||
_dio.interceptors.add(BadNetworkErrorInterceptor());
|
||||
_dio.interceptors.add(BadRequestErrorInterceptor());
|
||||
_dio.interceptors.add(InternalServerErrorInterceptor());
|
||||
_dio.interceptors.add(NotFoundErrorInterceptor());
|
||||
_dio.interceptors.add(UnauthorizedInterceptor());
|
||||
_dio.interceptors.add(ConnectionTimeoutErrorInterceptor());
|
||||
_dio.interceptors.add(CrashlyticsInterceptor());
|
||||
|
||||
if (kDebugMode) {
|
||||
_dio.interceptors.add(
|
||||
AwesomeDioInterceptor(
|
||||
logResponseHeaders: false,
|
||||
logRequestTimeout: false,
|
||||
logRequestHeaders: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Response> post(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? headers,
|
||||
Map<String, dynamic>? params,
|
||||
bool followRedirects = true,
|
||||
bool Function(int?)? validateStatus,
|
||||
String? contentType,
|
||||
}) async {
|
||||
try {
|
||||
return await _dio.post(
|
||||
path,
|
||||
data: data,
|
||||
options: Options(
|
||||
headers: headers,
|
||||
followRedirects: followRedirects,
|
||||
validateStatus: validateStatus,
|
||||
contentType: contentType,
|
||||
),
|
||||
queryParameters: params,
|
||||
);
|
||||
} on UnauthorizedError catch (e) {
|
||||
throw ApiFailure.unauthorized(e.messageError);
|
||||
} on InternalServerError {
|
||||
throw const ApiFailure.internalServerError();
|
||||
} on BadNetworkError {
|
||||
throw const ApiFailure.connectionError();
|
||||
} on BadRequestError catch (e) {
|
||||
throw ApiFailure.badRequest(e.messageError);
|
||||
} on NotFoundError catch (e) {
|
||||
throw ApiFailure.notFound(e.messageError);
|
||||
} on ConnectionTimeoutError {
|
||||
throw const ApiFailure.connectionTimeout();
|
||||
} on DioException catch (e) {
|
||||
var errorMessage =
|
||||
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error;
|
||||
|
||||
if (errorMessage.toString().contains('Connection reset')) {
|
||||
errorMessage = 'Connection reset';
|
||||
}
|
||||
|
||||
throw ApiFailure.serverError(
|
||||
statusCode: e.response?.statusCode ?? 0,
|
||||
errorMessage: errorMessage.toString(),
|
||||
);
|
||||
} catch (e, s) {
|
||||
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Response> get(
|
||||
String path, {
|
||||
Map<String, dynamic>? headers,
|
||||
Map<String, dynamic>? params,
|
||||
bool followRedirects = true,
|
||||
bool Function(int?)? validateStatus,
|
||||
String? contentType,
|
||||
}) async {
|
||||
try {
|
||||
return await _dio.get(
|
||||
path,
|
||||
options: Options(
|
||||
headers: headers,
|
||||
followRedirects: followRedirects,
|
||||
validateStatus: validateStatus,
|
||||
contentType: contentType,
|
||||
),
|
||||
queryParameters: params,
|
||||
);
|
||||
} on UnauthorizedError catch (e) {
|
||||
throw ApiFailure.unauthorized(e.messageError);
|
||||
} on InternalServerError {
|
||||
throw const ApiFailure.internalServerError();
|
||||
} on BadNetworkError {
|
||||
throw const ApiFailure.connectionError();
|
||||
} on BadRequestError catch (e) {
|
||||
throw ApiFailure.badRequest(e.messageError);
|
||||
} on NotFoundError catch (e) {
|
||||
throw ApiFailure.notFound(e.messageError);
|
||||
} on ConnectionTimeoutError {
|
||||
throw const ApiFailure.connectionTimeout();
|
||||
} on DioException catch (e) {
|
||||
var errorMessage =
|
||||
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error;
|
||||
|
||||
if (errorMessage.toString().contains('Connection reset')) {
|
||||
errorMessage = 'Connection reset';
|
||||
}
|
||||
|
||||
throw ApiFailure.serverError(
|
||||
statusCode: e.response?.statusCode ?? 0,
|
||||
errorMessage: errorMessage.toString(),
|
||||
);
|
||||
} catch (e, s) {
|
||||
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Response> put(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? headers,
|
||||
Map<String, dynamic>? params,
|
||||
bool followRedirects = true,
|
||||
bool Function(int?)? validateStatus,
|
||||
String? contentType,
|
||||
void Function(int count, int total)? onSendProgress,
|
||||
}) async {
|
||||
try {
|
||||
return await _dio.put(
|
||||
path,
|
||||
data: data,
|
||||
options: Options(
|
||||
headers: headers,
|
||||
followRedirects: followRedirects,
|
||||
validateStatus: validateStatus,
|
||||
contentType: contentType,
|
||||
),
|
||||
queryParameters: params,
|
||||
onSendProgress: onSendProgress,
|
||||
);
|
||||
} on UnauthorizedError catch (e) {
|
||||
throw ApiFailure.unauthorized(e.messageError);
|
||||
} on InternalServerError {
|
||||
throw const ApiFailure.internalServerError();
|
||||
} on BadNetworkError {
|
||||
throw const ApiFailure.connectionError();
|
||||
} on BadRequestError catch (e) {
|
||||
throw ApiFailure.badRequest(e.messageError);
|
||||
} on NotFoundError catch (e) {
|
||||
throw ApiFailure.notFound(e.messageError);
|
||||
} on ConnectionTimeoutError {
|
||||
throw const ApiFailure.connectionTimeout();
|
||||
} on DioException catch (e) {
|
||||
var errorMessage =
|
||||
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error;
|
||||
|
||||
if (errorMessage.toString().contains('Connection reset')) {
|
||||
errorMessage = 'Connection reset';
|
||||
}
|
||||
|
||||
throw ApiFailure.serverError(
|
||||
statusCode: e.response?.statusCode ?? 0,
|
||||
errorMessage: errorMessage.toString(),
|
||||
);
|
||||
} catch (e, s) {
|
||||
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
|
||||
}
|
||||
}
|
||||
|
||||
Future<Response> delete(
|
||||
String path, {
|
||||
dynamic data,
|
||||
Map<String, dynamic>? headers,
|
||||
Map<String, dynamic>? params,
|
||||
bool followRedirects = true,
|
||||
bool Function(int?)? validateStatus,
|
||||
String? contentType,
|
||||
}) async {
|
||||
try {
|
||||
return await _dio.delete(
|
||||
path,
|
||||
data: data,
|
||||
options: Options(
|
||||
headers: headers,
|
||||
followRedirects: followRedirects,
|
||||
validateStatus: validateStatus,
|
||||
contentType: contentType,
|
||||
),
|
||||
queryParameters: params,
|
||||
);
|
||||
} on UnauthorizedError catch (e) {
|
||||
throw ApiFailure.unauthorized(e.messageError);
|
||||
} on InternalServerError {
|
||||
throw const ApiFailure.internalServerError();
|
||||
} on BadNetworkError {
|
||||
throw const ApiFailure.connectionError();
|
||||
} on BadRequestError catch (e) {
|
||||
throw ApiFailure.badRequest(e.messageError);
|
||||
} on NotFoundError catch (e) {
|
||||
throw ApiFailure.notFound(e.messageError);
|
||||
} on DioException catch (e) {
|
||||
throw ApiFailure.serverError(
|
||||
statusCode: e.response?.statusCode ?? 0,
|
||||
errorMessage:
|
||||
e.response?.data['message'] ?? e.response?.statusMessage ?? e.error,
|
||||
);
|
||||
} catch (e, s) {
|
||||
throw ApiFailure.unexpectedError(errorMessage: e, stackTrace: s);
|
||||
}
|
||||
}
|
||||
}
|
||||