Compare commits

..
21 Commits
Author SHA1 Message Date
efrilm 0c8ca3c51b git push 2026-05-15 12:53:04 +07:00
Efril 96526c1972 update 2026-05-14 15:05:04 +07:00
Efril c4618bbc1b update pesanan 2026-05-14 14:55:49 +07:00
Efril 9f2097a268 add all outlet 2026-05-14 14:11:42 +07:00
efrilm 6fda0f5636 fix home 2026-05-13 15:31:14 +07:00
efrilm d7cd84e130 fix ios 2026-05-13 13:22:06 +07:00
efrilm ba2f0cd265 selected outlet 2026-05-12 17:09:50 +07:00
efrilm 3541fc725c outlet list 2026-05-12 16:47:36 +07:00
efrilm c2727a0995 update outlet card 2026-05-12 16:31:00 +07:00
efrilm 6e4b09f15e update home ui 2026-05-12 15:50:02 +07:00
efrilm 9076c9c66e update home ui 2026-05-12 15:47:38 +07:00
efrilm 86d581f5ea update remove animation 2026-05-12 14:48:53 +07:00
efrilm 411d1274bd add files ios 2026-05-12 02:01:15 +07:00
Efril a4a12c6763 add device info at login 2026-05-12 02:00:38 +07:00
Efril 9b6e9c591d update notification 2026-05-12 01:54:24 +07:00
Efril 3985611a0e update ios 2026-05-12 00:59:56 +07:00
Efril 61dd2bbb2c update api 2026-05-12 00:55:15 +07:00
Efril 91965667ec setup fcm 2026-05-12 00:52:14 +07:00
efrilm 9775e09659 feat: readme 2025-08-22 15:26:16 +07:00
efrilm 3f75bffd09 feat: pull to refresh on home 2025-08-20 13:57:00 +07:00
efrilm 5a83bc4049 feat: lang 2025-08-20 13:52:49 +07:00
163 changed files with 8836 additions and 1711 deletions
+541 -15
View File
@@ -1,39 +1,565 @@
# Apskel Owner App ## Apskel Owner Flutter
A Flutter-based Point of Sale (POS) application designed specifically for business owners. A POS (Point of Sale) application for business owners, built with Flutter. The project follows a layered architecture (presentation → application → domain → infrastructure) with dependency injection, state management, automated routing, internationalization, and code generation.
Helps manage sales, products, inventory, and business reports in real-time with a simple, easy-to-use interface.
## 🚀 Getting Started ---
### âś… Prerequisites ### Contents
- [Flutter](https://flutter.dev/docs/get-started/install) 3.32.8 or newer - Technical Summary
- Dart 3.8.1 or newer - Requirements & Setup
- Running the App
- Architecture Overview
- Project Structure
- Key Dependencies & Purpose
- Code Generation
- Internationalization (i18n)
- Theming & Assets
- Environment Configuration (`env.dart`)
- Development Practices
### đź›  Installation ---
```bash ## Technical Summary
git clone https://github.com/efrilm/frl-movie.git
```
```bash - SDK: Flutter (Material) with Dart ^3.8.1
cd app-path - Targets: Android, iOS, Web, Desktop (Windows, macOS, Linux)
``` - State management: `flutter_bloc`
- Routing: `auto_route`
- Dependency Injection: `get_it` + `injectable`
- HTTP Client: `dio` (+ `awesome_dio_interceptor`)
- Data class & serialization: `freezed` + `json_serializable`
- Localization: `flutter_localizations`, `l10n/*.arb`
- Assets generation: `flutter_gen`
---
## Requirements & Setup
### Prerequisites
- Flutter SDK installed as per the official guide (`https://flutter.dev/docs/get-started/install`)
- Dart version per constraint: ^3.8.1
### Installation
```bash ```bash
git clone <your-repo-url>
cd apskel_owner_flutter
flutter pub get flutter pub get
``` ```
### Code generation (required after clone or when annotations change)
```bash ```bash
flutter pub run build_runner build --delete-conflicting-outputs flutter pub run build_runner build --delete-conflicting-outputs
``` ```
> Re-run whenever you change files using `@RoutePage()`, `@injectable`, `@freezed`, or `@JsonSerializable`.
--- ---
## đź§Ş Running ## Running the App
```bash ```bash
flutter run flutter run
``` ```
Select a specific device/platform:
```bash
flutter run -d chrome
flutter run -d ios
flutter run -d android
```
Example release builds:
```bash
flutter build apk --release
flutter build ios --release
flutter build web --release
```
--- ---
## Architecture Overview
The codebase follows a clean, layered approach that separates concerns and keeps features modular and testable:
- Presentation (`lib/presentation`): Widgets, pages/screens, and the `AutoRoute` router. Contains only UI code and wiring to BLoC/Cubit.
- Application (`lib/application`): BLoC/Cubit and application-level orchestration. Holds input validation, state transitions, and calls into the Domain layer.
- Domain (`lib/domain`): Pure business logic. Entities, value objects, repository interfaces, and (optional) use-cases. No framework dependencies.
- Infrastructure (`lib/infrastructure`): Repository implementations, DTOs, and data sources (HTTP/DB). Performs `dio` calls and mappings between DTOs and Domain entities.
- Common (`lib/common`): Cross-cutting helpers such as API base, DI setup, constants, extensions, theme, validators, and utilities.
Data flow in a feature:
1. UI triggers an intent/event in Presentation →
2. Application layer BLoC/Cubit handles the event and calls a repository/use-case from Domain →
3. Infrastructure implements the repository, performs network calls via `dio`, and maps results →
4. Data is converted to Domain entities and returned to Application →
5. Application updates state, Presentation rebuilds UI accordingly.
Cross-cutting concerns:
- Dependency Injection: `get_it` + `injectable` auto-register services/repositories (`injection.dart`, `injection.config.dart`).
- Routing: `auto_route` defines typed routes, generated into router files in `presentation/router`.
- State: `flutter_bloc` models states/events and isolates side-effects in BLoCs/Cubits.
- Networking: `dio` with interceptors for logging and error handling.
- Error handling: functional style with `dartz` (`Either`, `Option`) or well-defined BLoC states.
- i18n: ARB files in `lib/l10n/` and generated localization delegates.
- Theming: centralized theme under `lib/common/theme/` with shared design tokens.
- Assets: managed under `assets/` and referenced via FlutterGen outputs at `lib/presentation/components/assets/`.
---
## Project Structure
```
lib/
application/ # BLoC/cubit per feature (analytic, auth, product, etc.)
common/
api/ # Base API client, endpoint helper
constant/ # Application constants
di/ # Dependency injection setup (get_it, injectable)
extension/ # Extensions
function/ # General utility functions
network/ # Connectivity checks, handlers
painter/ # Custom painters
theme/ # Colors, text styles, theming
url/ # Base URL/endpoints
utils/ # Other helpers
validator/ # Input validators
domain/
<feature>/ # Entities, repo interfaces, (use-cases if present)
infrastructure/
<feature>/ # Repo implementations, DTOs, API calls
l10n/ # ARB sources for i18n + generated localizations
presentation/
components/ # Reusable widgets
pages/ # Feature pages/screens
router/ # AutoRoute definitions
env.dart # Environment configuration (BASE_URL, etc.)
injection.dart # DI entry point
injection.config.dart # DI generated
main.dart # Application entry point
assets/
images/, icons/, json/, fonts/
```
---
## Key Dependencies & Purpose
Runtime:
- `auto_route`: Automated, typed routing based on annotations.
- `flutter_bloc`: State management with BLoC/Cubit.
- `get_it`, `injectable`: Service locator + codegen for DI.
- `dio`, `awesome_dio_interceptor`: HTTP client + logging interceptor.
- `freezed_annotation`, `json_annotation`: Annotations for immutable data classes & JSON.
- `dartz`: Functional types (Either, Option) for explicit error handling.
- `connectivity_plus`, `device_info_plus`, `package_info_plus`: Device and connectivity info.
- `shared_preferences`: Local key-value storage.
- `image_picker`, `permission_handler`, `open_file`, `url_launcher`: OS/device integrations.
- UI: `flutter_svg`, `line_icons`, `flutter_spinkit`, `fl_chart`, `another_flushbar`, `table_calendar`, `shimmer`, `cached_network_image`, `syncfusion_flutter_datepicker`, `pdf`.
Dev:
- `build_runner`: Code generation orchestration.
- `auto_route_generator`, `injectable_generator`, `freezed`, `json_serializable`: Related generators.
- `flutter_gen_runner`: Typed asset access generator.
- `flutter_lints`: Recommended Flutter lints.
- `flutter_launcher_icons`: Launcher icon generation.
Refer to `pubspec.yaml` for full version constraints.
---
## Code Generation
Common commands:
```bash
flutter pub run build_runner build --delete-conflicting-outputs
# or watch
flutter pub run build_runner watch --delete-conflicting-outputs
```
### Asset generation (flutter_gen_runner)
`flutter_gen_runner` is integrated with `build_runner`. Running the commands above will also generate typed accessors for assets based on the `flutter_gen` section in `pubspec.yaml`:
- Output path: `lib/presentation/components/assets/`
- SVG integration: enabled (`flutter_svg: true`)
Usage in code example (after generation):
```dart
// Example usage
// import 'presentation/components/assets/assets.gen.dart';
// Image.asset(Assets.images.logo.path);
```
Generators used:
- AutoRoute: Generates router and typed routes.
- Injectable: Generates DI registrations (`injection.config.dart`).
- Freezed: Generates immutable data classes, copyWith, unions, etc.
- Json Serializable: Generates toJson/fromJson for DTOs.
- FlutterGen: Generates static asset access under `lib/presentation/components/assets/`.
---
## Internationalization (i18n)
- Source files live in `lib/l10n/app_*.arb` (e.g., `app_en.arb`, `app_id.arb`).
- To add a language: create `app_<code>.arb`, then run code generation.
- Ensure `MaterialApp` is wired with `localizationsDelegates` and `supportedLocales` (already prepared).
---
## Theming & Assets
- Theme files live under `lib/common/theme/`.
- Fonts: `Quicksand` family is declared in `pubspec.yaml`.
- Assets: `assets/images/`, `assets/icons/`, `assets/json/` – referenced via FlutterGen outputs at `lib/presentation/components/assets/`.
---
## Environment Configuration (`env.dart`)
The `lib/env.dart` file stores configuration values such as base URLs and debug flags. Adjust per environment (development/production) using flavors, environment variables, or branching as preferred by the team.
---
## Development Practices
- Routing: Define routes in `presentation/router`, then run code generation.
- DI: Annotate services/repositories with `@injectable`/`@LazySingleton`, generate code, and call `configureDependencies()` early in app startup.
- BLoC: Keep UI logic in the `application` layer and use `BlocBuilder`/`BlocListener` in the `presentation` layer.
- DTO ↔ Entity: Mapping resides in the `infrastructure` layer to keep domain pure.
- Error handling: Prefer `Either`/`Option` (`dartz`) or well-structured BLoC states.
- Linting: Follow `analysis_options.yaml`.
---
## Useful Commands
```bash
# Install dependencies
flutter pub get
# Format & Analyze
flutter format .
flutter analyze
# Code generation (single run / watch)
flutter pub run build_runner build --delete-conflicting-outputs
flutter pub run build_runner watch --delete-conflicting-outputs
# Run by device
flutter devices
flutter run -d <device-id>
```
---
## Additional Notes
- Launcher icons configured via `launcher_icon.yaml`.
- Platform-specific configuration (Android/iOS/Web/Desktop) resides in respective platform folders.
- Review `analysis_options.yaml` for code style and lint rules.
---
## Launcher Icons
Configured via `launcher_icon.yaml` at the repository root. To (re)generate launcher icons, run:
```bash
dart run flutter_launcher_icons -f launcher_icon.yaml
```
If you prefer the Flutter shim:
```bash
flutter pub run flutter_launcher_icons -f launcher_icon.yaml
```
Ensure you have the package in `dev_dependencies` (`flutter_launcher_icons`).
## Contributing
1. Branch off `main`.
2. Make focused changes and provide a clear PR description.
3. Ensure build, lints, and codegen are clean before opening the PR.
---
## License
This project is private/internal. Contact the repository owner for usage permissions.
## Apskel Owner Flutter
Aplikasi Point of Sale (POS) untuk pemilik usaha, dibangun dengan Flutter. Proyek ini menerapkan arsitektur berlapis (presentation → application → domain → infrastructure) dengan dependency injection, state management, routing terotomasi, internationalization, dan code generation.
---
### Isi Dokumen
- Ringkasan Teknis
- Persyaratan & Setup
- Menjalankan Aplikasi
- Arsitektur & Alur
- Struktur Proyek
- Dependensi Utama & Fungsinya
- Code Generation
- Internationalization (i18n)
- Theming & Assets
- Konfigurasi Lingkungan (`env.dart`)
- Praktik Pengembangan
---
## Ringkasan Teknis
- SDK: Flutter (Material) dengan Dart ^3.8.1
- Target platform: Android, iOS, Web, Desktop (Windows, macOS, Linux)
- State management: `flutter_bloc`
- Routing: `auto_route`
- Dependency Injection: `get_it` + `injectable`
- HTTP Client: `dio` (+ `awesome_dio_interceptor`)
- Data class & serialization: `freezed` + `json_serializable`
- Localization: `flutter_localizations`, `l10n/*.arb`
- Assets generation: `flutter_gen`
---
## Persyaratan & Setup
### Prasyarat
- Flutter SDK terpasang sesuai panduan resmi (`https://flutter.dev/docs/get-started/install`)
- Versi Dart sesuai constraint: ^3.8.1
### Instalasi
```bash
git clone <repo-url-anda>
cd apskel_owner_flutter
flutter pub get
```
### Generate kode (wajib setelah clone atau mengubah anotasi)
```bash
flutter pub run build_runner build --delete-conflicting-outputs
```
> Jalankan ulang perintah di atas setiap kali Anda mengubah file yang menggunakan anotasi `@RoutePage()`, `@injectable`, `@freezed`, atau `@JsonSerializable`.
---
## Menjalankan Aplikasi
```bash
flutter run
```
Menentukan platform/target tertentu:
```bash
flutter run -d chrome
flutter run -d ios
flutter run -d android
```
Build release contoh:
```bash
flutter build apk --release
flutter build ios --release
flutter build web --release
```
---
## Arsitektur & Alur
Proyek mengikuti layering yang jelas:
- Presentation (`lib/presentation`): UI, widget, halaman, router.
- Application (`lib/application`): BLoC/cubit, use-case orkestra ringan, validasi input UI.
- Domain (`lib/domain`): Entitas, value object, repository interface, use-case (jika ada).
- Infrastructure (`lib/infrastructure`): Implementasi repository, data source (API/DB), mapping DTO.
- Common (`lib/common`): Utilitas umum, konstanta, theme, API base, DI bootstrap, extension, dll.
Alur umum:
1. UI memicu event →
2. BLoC di layer Application memanggil use-case/repo (Domain) →
3. Implementasi repo (Infrastructure) melakukan HTTP via `dio` →
4. Response dipetakan menjadi entity/domain →
5. State di-update kembali ke UI.
---
## Struktur Proyek
```
lib/
application/ # BLoC/cubit per fitur (analytic, auth, product, dst.)
common/
api/ # Base API client, endpoint helper
constant/ # Konstanta aplikasi
di/ # Setup dependency injection (get_it, injectable)
extension/ # Extension util
function/ # Fungsi util umum
network/ # Cek konektivitas, handler
painter/ # Custom painter
theme/ # Warna, text styles, theming
url/ # Base URL/endpoint
utils/ # Helper lain
validator/ # Validator input
domain/
<feature>/ # Entity, repo interface, (use-case bila ada)
infrastructure/
<feature>/ # Repo implementation, DTO, pemanggilan API
l10n/ # Berkas ARB untuk i18n + generated localizations
presentation/
components/ # Widget reusable
pages/ # Halaman/layar fitur
router/ # Definisi AutoRoute
env.dart # Konfigurasi environment (BASE_URL, dsb)
injection.dart # Entry point DI
injection.config.dart # DI generated
main.dart # Entrypoint aplikasi
assets/
images/, icons/, json/, fonts/
```
---
## Dependensi Utama & Fungsinya
Runtime:
- `auto_route`: Routing terotomasi berbasis anotasi.
- `flutter_bloc`: State management dengan BLoC/Cubit.
- `get_it`, `injectable`: Service locator + codegen untuk DI.
- `dio`, `awesome_dio_interceptor`: HTTP client + logging interceptor.
- `freezed_annotation`, `json_annotation`: Anotasi untuk data class immutable & JSON.
- `dartz`: Functional types (Either, Option) untuk error handling yang eksplisit.
- `connectivity_plus`, `device_info_plus`, `package_info_plus`: Info perangkat & konektivitas.
- `shared_preferences`: Penyimpanan key-value lokal.
- `image_picker`, `permission_handler`, `open_file`, `url_launcher`: Integrasi perangkat/OS.
- UI: `flutter_svg`, `line_icons`, `flutter_spinkit`, `fl_chart`, `another_flushbar`, `table_calendar`, `shimmer`, `cached_network_image`, `syncfusion_flutter_datepicker`, `pdf`.
Dev:
- `build_runner`: Orkestrasi code generation.
- `auto_route_generator`, `injectable_generator`, `freezed`, `json_serializable`: Generator terkait.
- `flutter_gen_runner`: Generator akses asset terketik.
- `flutter_lints`: Linter rekomendasi Flutter.
- `flutter_launcher_icons`: Generate icon launcher.
Catatan versi lengkap tersedia di `pubspec.yaml`.
---
## Code Generation
Perintah umum:
```bash
flutter pub run build_runner build --delete-conflicting-outputs
# atau untuk watch
flutter pub run build_runner watch --delete-conflicting-outputs
```
Generator yang digunakan:
- AutoRoute: menghasilkan deklarasi router & route.
- Injectable: menghasilkan registrasi DI (`injection.config.dart`).
- Freezed: menghasilkan data class immutable, copyWith, union, dsb.
- Json Serializable: menghasilkan toJson/fromJson untuk DTO.
- FlutterGen: menghasilkan akses asset statis di `lib/presentation/components/assets/`.
---
## Internationalization (i18n)
- Berkas sumber ada di `lib/l10n/app_*.arb` (contoh: `app_en.arb`, `app_id.arb`).
- Bahasa baru: tambahkan `app_<kode>.arb`, jalankan code generation.
- Pastikan `MaterialApp` menggunakan `localizationsDelegates` dan `supportedLocales` (sudah disiapkan).
---
## Theming & Assets
- Theme ada di `lib/common/theme/`.
- Font: keluarga `Quicksand` dideklarasikan di `pubspec.yaml`.
- Assets: `assets/images/`, `assets/icons/`, `assets/json/` – akses via FlutterGen yang dihasilkan ke `lib/presentation/components/assets/`.
---
## Konfigurasi Lingkungan (`env.dart`)
File `lib/env.dart` menyimpan nilai konfigurasi seperti base URL, flag debug, dll. Sesuaikan untuk development/production (bisa dengan flavor, env var, atau branch khusus sesuai kebutuhan tim).
---
## Praktik Pengembangan
- Routing: definisikan route di `presentation/router`, jalankan codegen.
- DI: daftarkan service/repository dengan anotasi `@injectable`/`@LazySingleton`, lalu generate, dan panggil `configureDependencies()` di awal aplikasi.
- BLoC: simpan logic UI di layer `application` dan gunakan `BlocBuilder`/`BlocListener` di layer `presentation`.
- DTO ↔ Entity: mapping berada di layer `infrastructure` untuk menjaga domain tetap bersih.
- Error handling: gunakan `Either`/`Option` (`dartz`) atau state terstruktur di BLoC.
- Lint: patuhi aturan `analysis_options.yaml`.
---
## Perintah Berguna
```bash
# Install dependencies
flutter pub get
# Format & Analyze
flutter format .
flutter analyze
# Code generation (sekali jalan / watch)
flutter pub run build_runner build --delete-conflicting-outputs
flutter pub run build_runner watch --delete-conflicting-outputs
# Run by device
flutter devices
flutter run -d <device-id>
```
---
## Catatan Tambahan
- Icon launcher dikonfigurasi di `launcher_icon.yaml` (gunakan `flutter pub run flutter_launcher_icons` bila diperlukan).
- Konfigurasi platform (Android/iOS/Web/Desktop) berada pada folder platform terkait.
- Pastikan meninjau `analysis_options.yaml` untuk standar code style dan lints.
---
## Kontribusi
1. Buat branch dari `main`.
2. Lakukan perubahan terfokus dan sertakan deskripsi yang jelas pada PR.
3. Pastikan build, lints, dan codegen bersih sebelum mengajukan PR.
---
## Lisensi
Proyek ini bersifat privat/internal. Hubungi pemilik repositori untuk detail izin penggunaan.
+1
View File
@@ -14,6 +14,7 @@ analyzer:
invalid_annotation_target: ignore invalid_annotation_target: ignore
use_build_context_synchronously: ignore use_build_context_synchronously: ignore
deprecated_member_use: ignore deprecated_member_use: ignore
depend_on_referenced_packages: ignore
exclude: exclude:
- test/generated/** - test/generated/**
- "**/**.g.dart" - "**/**.g.dart"
+8 -2
View File
@@ -3,14 +3,16 @@ plugins {
id("kotlin-android") id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin") id("dev.flutter.flutter-gradle-plugin")
id("com.google.gms.google-services")
} }
android { android {
namespace = "com.apskel.apskel_owner" namespace = "com.apskel.enaklo_owner"
compileSdk = flutter.compileSdkVersion compileSdk = flutter.compileSdkVersion
ndkVersion = "27.0.12077973" ndkVersion = "27.0.12077973"
compileOptions { compileOptions {
isCoreLibraryDesugaringEnabled = true
sourceCompatibility = JavaVersion.VERSION_11 sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_11
} }
@@ -21,7 +23,7 @@ android {
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.apskel.apskel_owner" applicationId = "com.apskel.enaklo_owner"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config. // For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion minSdk = flutter.minSdkVersion
@@ -42,3 +44,7 @@ android {
flutter { flutter {
source = "../.." source = "../.."
} }
dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.4")
}
+48
View File
@@ -0,0 +1,48 @@
{
"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:beffb797b781e715241e62",
"android_client_info": {
"package_name": "com.apskel.enaklo_owner"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAOZwVSQwUeeM9BjcyTOK9GUh8AmTWucuc"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_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"
}
+31 -1
View File
@@ -5,9 +5,15 @@
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/> <uses-permission android:name="android.permission.READ_MEDIA_VIDEO"/>
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/> <uses-permission android:name="android.permission.READ_MEDIA_AUDIO"/>
<!-- FCM: required for POST_NOTIFICATIONS on Android 13+ -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
<!-- FCM: allow background processing after device reboot -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- FCM: allow wake lock for background message processing -->
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<application <application
android:label="Apskel Owner" android:label="Enaklo Owner"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/launcher_icon"> android:icon="@mipmap/launcher_icon">
<activity <activity
@@ -37,6 +43,30 @@
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />
<!-- FCM: default notification channel for Android 8+ -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="high_importance_channel" />
<!-- FCM: default notification icon -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<!-- FCM: default notification color -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/notification_color" />
<!-- FCM: background message handler service -->
<service
android:name="com.google.firebase.messaging.FirebaseMessagingService"
android:exported="false">
<intent-filter android:priority="-500">
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
</application> </application>
<!-- Required to query activities that can process text, see: <!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and https://developer.android.com/training/package-visibility and
@@ -1,4 +1,4 @@
package com.apskel.apskel_owner package com.apskel.enaklo_owner
import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.android.FlutterActivity
Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 37 KiB

@@ -1,4 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="ic_launcher_background">#ffffff</color> <color name="ic_launcher_background">#ffffff</color>
<!-- FCM: notification accent color -->
<color name="notification_color">#FF6B35</color>
</resources> </resources>
+1
View File
@@ -20,6 +20,7 @@ plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0" id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false id("org.jetbrains.kotlin.android") version "2.1.0" apply false
id("com.google.gms.google-services") version "4.4.2" apply false
} }
include(":app") include(":app")
Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 1.4 MiB

+1 -1
View File
@@ -1,5 +1,5 @@
# Uncomment this line to define a global platform for your project # Uncomment this line to define a global platform for your project
# platform :ios, '12.0' platform :ios, '14.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency. # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true' ENV['COCOAPODS_DISABLE_STATS'] = 'true'
+181
View File
@@ -0,0 +1,181 @@
PODS:
- connectivity_plus (0.0.1):
- Flutter
- device_info_plus (0.0.1):
- Flutter
- Firebase/CoreOnly (10.25.0):
- FirebaseCore (= 10.25.0)
- Firebase/Messaging (10.25.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 10.25.0)
- firebase_core (2.32.0):
- Firebase/CoreOnly (= 10.25.0)
- Flutter
- firebase_messaging (14.7.10):
- Firebase/Messaging (= 10.25.0)
- firebase_core
- Flutter
- FirebaseCore (10.25.0):
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.12)
- GoogleUtilities/Logger (~> 7.12)
- FirebaseCoreInternal (10.29.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- FirebaseInstallations (10.29.0):
- FirebaseCore (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- PromisesObjC (~> 2.1)
- FirebaseMessaging (10.25.0):
- FirebaseCore (~> 10.0)
- FirebaseInstallations (~> 10.0)
- GoogleDataTransport (~> 9.3)
- GoogleUtilities/AppDelegateSwizzler (~> 7.8)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/Reachability (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
- nanopb (< 2.30911.0, >= 2.30908.0)
- Flutter (1.0.0)
- flutter_local_notifications (0.0.1):
- Flutter
- GoogleDataTransport (9.4.1):
- GoogleUtilities/Environment (~> 7.7)
- nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/AppDelegateSwizzler (7.13.3):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Privacy
- GoogleUtilities/Environment (7.13.3):
- GoogleUtilities/Privacy
- PromisesObjC (< 3.0, >= 1.2)
- GoogleUtilities/Logger (7.13.3):
- GoogleUtilities/Environment
- GoogleUtilities/Privacy
- GoogleUtilities/Network (7.13.3):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (7.13.3)":
- GoogleUtilities/Privacy
- GoogleUtilities/Privacy (7.13.3)
- GoogleUtilities/Reachability (7.13.3):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- GoogleUtilities/UserDefaults (7.13.3):
- GoogleUtilities/Logger
- GoogleUtilities/Privacy
- image_picker_ios (0.0.1):
- Flutter
- nanopb (2.30910.0):
- nanopb/decode (= 2.30910.0)
- nanopb/encode (= 2.30910.0)
- nanopb/decode (2.30910.0)
- nanopb/encode (2.30910.0)
- open_file_ios (0.0.1):
- Flutter
- package_info_plus (0.4.5):
- Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- permission_handler_apple (9.3.0):
- Flutter
- PromisesObjC (2.4.0)
- shared_preferences_foundation (0.0.1):
- Flutter
- FlutterMacOS
- sqflite_darwin (0.0.4):
- Flutter
- FlutterMacOS
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- open_file_ios (from `.symlinks/plugins/open_file_ios/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
SPEC REPOS:
trunk:
- Firebase
- FirebaseCore
- FirebaseCoreInternal
- FirebaseInstallations
- FirebaseMessaging
- GoogleDataTransport
- GoogleUtilities
- nanopb
- PromisesObjC
EXTERNAL SOURCES:
connectivity_plus:
:path: ".symlinks/plugins/connectivity_plus/ios"
device_info_plus:
:path: ".symlinks/plugins/device_info_plus/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios"
Flutter:
:path: Flutter
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
open_file_ios:
:path: ".symlinks/plugins/open_file_ios/ios"
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
shared_preferences_foundation:
:path: ".symlinks/plugins/shared_preferences_foundation/darwin"
sqflite_darwin:
:path: ".symlinks/plugins/sqflite_darwin/darwin"
url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
connectivity_plus: 2a701ffec2c0ae28a48cf7540e279787e77c447d
device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342
Firebase: 0312a2352584f782ea56f66d91606891d4607f06
firebase_core: a626d00494efa398e7c54f25f1454a64c8abf197
firebase_messaging: 1541105e2a2a6ef8bd869bcc44157d31e82f3a50
FirebaseCore: 7ec4d0484817f12c3373955bc87762d96842d483
FirebaseCoreInternal: df84dd300b561c27d5571684f389bf60b0a5c934
FirebaseInstallations: 913cf60d0400ebd5d6b63a28b290372ab44590dd
FirebaseMessaging: 88950ba9485052891ebe26f6c43a52bb62248952
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_local_notifications: df98d66e515e1ca797af436137b4459b160ad8c9
GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
GoogleUtilities: ea963c370a38a8069cc5f7ba4ca849a60b6d7d15
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
nanopb: 438bc412db1928dac798aa6fd75726007be04262
open_file_ios: 461db5853723763573e140de3193656f91990d9e
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: e30f02f9d1c72c47bb6344a0a748c9d268180865
COCOAPODS: 1.16.2
+145 -6
View File
@@ -8,12 +8,15 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
227E95452FB25185003AAE6C /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 227E95442FB25185003AAE6C /* GoogleService-Info.plist */; };
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
989F8AA016A730C566E93749 /* Pods_RunnerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3A6F295F1D6E4BB0819A8681 /* Pods_RunnerTests.framework */; };
F18848A41F5DE1108211F920 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B7ABC3D9AD3883EDD2E44FB /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@@ -40,14 +43,22 @@
/* End PBXCopyFilesBuildPhase section */ /* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
0B9C91DAD8EC48930CF79A70 /* Pods-RunnerTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.profile.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.profile.xcconfig"; sourceTree = "<group>"; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
159A415F4811E2794AA4092B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
1CE6759F37E82B0362B2E241 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
227E95442FB25185003AAE6C /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; }; 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
3A6F295F1D6E4BB0819A8681 /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
3B7ABC3D9AD3883EDD2E44FB /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3C70A9D33D5F6D7EAE05A508 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
7F8F2B65C01EDDD64346C756 /* Pods-RunnerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.release.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.release.xcconfig"; sourceTree = "<group>"; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -55,13 +66,23 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E6E423C7625C032FDEFB6799 /* Pods-RunnerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-RunnerTests.debug.xcconfig"; path = "Target Support Files/Pods-RunnerTests/Pods-RunnerTests.debug.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
6BBDF52C0DFCF2DFA69EB9C3 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
989F8AA016A730C566E93749 /* Pods_RunnerTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = { 97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
F18848A41F5DE1108211F920 /* Pods_Runner.framework in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@@ -76,6 +97,15 @@
path = RunnerTests; path = RunnerTests;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
4DBA9259FD070A034AF146BB /* Frameworks */ = {
isa = PBXGroup;
children = (
3B7ABC3D9AD3883EDD2E44FB /* Pods_Runner.framework */,
3A6F295F1D6E4BB0819A8681 /* Pods_RunnerTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9740EEB11CF90186004384FC /* Flutter */ = { 9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -94,6 +124,8 @@
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
331C8082294A63A400263BE5 /* RunnerTests */, 331C8082294A63A400263BE5 /* RunnerTests */,
F771B77E516695BE7A4B0AEA /* Pods */,
4DBA9259FD070A034AF146BB /* Frameworks */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
}; };
@@ -109,6 +141,7 @@
97C146F01CF9000F007C117D /* Runner */ = { 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
227E95442FB25185003AAE6C /* GoogleService-Info.plist */,
97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
@@ -121,6 +154,19 @@
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
F771B77E516695BE7A4B0AEA /* Pods */ = {
isa = PBXGroup;
children = (
3C70A9D33D5F6D7EAE05A508 /* Pods-Runner.debug.xcconfig */,
1CE6759F37E82B0362B2E241 /* Pods-Runner.release.xcconfig */,
159A415F4811E2794AA4092B /* Pods-Runner.profile.xcconfig */,
E6E423C7625C032FDEFB6799 /* Pods-RunnerTests.debug.xcconfig */,
7F8F2B65C01EDDD64346C756 /* Pods-RunnerTests.release.xcconfig */,
0B9C91DAD8EC48930CF79A70 /* Pods-RunnerTests.profile.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
@@ -128,8 +174,10 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
buildPhases = ( buildPhases = (
81D20024DBE321C19417AE73 /* [CP] Check Pods Manifest.lock */,
331C807D294A63A400263BE5 /* Sources */, 331C807D294A63A400263BE5 /* Sources */,
331C807F294A63A400263BE5 /* Resources */, 331C807F294A63A400263BE5 /* Resources */,
6BBDF52C0DFCF2DFA69EB9C3 /* Frameworks */,
); );
buildRules = ( buildRules = (
); );
@@ -145,12 +193,15 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
buildPhases = ( buildPhases = (
ACC8E6F2D63F11FFC05DF00A /* [CP] Check Pods Manifest.lock */,
9740EEB61CF901F6004384FC /* Run Script */, 9740EEB61CF901F6004384FC /* Run Script */,
97C146EA1CF9000F007C117D /* Sources */, 97C146EA1CF9000F007C117D /* Sources */,
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
77740562F72074B1BD58B4C5 /* [CP] Embed Pods Frameworks */,
E2768009FD8B9B6235B4E16A /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@@ -214,6 +265,7 @@
files = ( files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
227E95452FB25185003AAE6C /* GoogleService-Info.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
); );
@@ -238,6 +290,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
}; };
77740562F72074B1BD58B4C5 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
81D20024DBE321C19417AE73 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-RunnerTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1; alwaysOutOfDate = 1;
@@ -253,6 +344,45 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
ACC8E6F2D63F11FFC05DF00A /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
E2768009FD8B9B6235B4E16A /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
@@ -362,13 +492,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5TRC3M8UZG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.apskelOwnerFlutter; PRODUCT_BUNDLE_IDENTIFIER = com.apskel.enaklo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
@@ -378,13 +510,14 @@
}; };
331C8088294A63A400263BE5 /* Debug */ = { 331C8088294A63A400263BE5 /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = E6E423C7625C032FDEFB6799 /* Pods-RunnerTests.debug.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.apskelOwnerFlutter.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.apskel.enaklo.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -395,13 +528,14 @@
}; };
331C8089294A63A400263BE5 /* Release */ = { 331C8089294A63A400263BE5 /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7F8F2B65C01EDDD64346C756 /* Pods-RunnerTests.release.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.apskelOwnerFlutter.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.apskel.enaklo.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -410,13 +544,14 @@
}; };
331C808A294A63A400263BE5 /* Profile */ = { 331C808A294A63A400263BE5 /* Profile */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 0B9C91DAD8EC48930CF79A70 /* Pods-RunnerTests.profile.xcconfig */;
buildSettings = { buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)"; BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES; GENERATE_INFOPLIST_FILE = YES;
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.example.apskelOwnerFlutter.RunnerTests; PRODUCT_BUNDLE_IDENTIFIER = com.apskel.enaklo.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
@@ -541,13 +676,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5TRC3M8UZG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.apskelOwnerFlutter; PRODUCT_BUNDLE_IDENTIFIER = com.apskel.enaklo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -563,13 +700,15 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEVELOPMENT_TEAM = 5TRC3M8UZG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
PRODUCT_BUNDLE_IDENTIFIER = com.example.apskelOwnerFlutter; PRODUCT_BUNDLE_IDENTIFIER = com.apskel.enaklo;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
+3
View File
@@ -4,4 +4,7 @@
<FileRef <FileRef
location = "group:Runner.xcodeproj"> location = "group:Runner.xcodeproj">
</FileRef> </FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace> </Workspace>
+22
View File
@@ -1,5 +1,6 @@
import Flutter import Flutter
import UIKit import UIKit
import UserNotifications
@main @main
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate {
@@ -7,7 +8,28 @@ import UIKit
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
// Set notification delegate so notifications show in foreground & background
UNUserNotificationCenter.current().delegate = self
GeneratedPluginRegistrant.register(with: self) GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
// Called when a notification is delivered while app is in foreground
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
) {
completionHandler([.banner, .badge, .sound])
}
// Called when user taps a notification (foreground or background)
override func userNotificationCenter(
_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void
) {
completionHandler()
}
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 654 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 678 B

After

Width:  |  Height:  |  Size: 775 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

+30
View File
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>AIzaSyCb6teTjGKytZmAZc2aMJrpaW484tm93jY</string>
<key>GCM_SENDER_ID</key>
<string>765730035527</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>com.apskel.enaklo</string>
<key>PROJECT_ID</key>
<string>apskel-pos-v2</string>
<key>STORAGE_BUCKET</key>
<string>apskel-pos-v2.firebasestorage.app</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:765730035527:ios:c87f91e28b33766e241e62</string>
</dict>
</plist>
+7 -1
View File
@@ -5,7 +5,7 @@
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string> <string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key> <key>CFBundleDisplayName</key>
<string>Apskel Owner</string> <string>Enaklo Owner</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
@@ -45,5 +45,11 @@
<true/> <true/>
<key>UIApplicationSupportsIndirectInputEvents</key> <key>UIApplicationSupportsIndirectInputEvents</key>
<true/> <true/>
<!-- FCM: enable background fetch & remote notifications -->
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
</dict> </dict>
</plist> </plist>
@@ -14,7 +14,7 @@ class DashboardAnalyticLoaderState with _$DashboardAnalyticLoaderState {
DashboardAnalyticLoaderState( DashboardAnalyticLoaderState(
dashboardAnalytic: DashboardAnalytic.empty(), dashboardAnalytic: DashboardAnalytic.empty(),
failureOptionDashboardAnalytic: none(), failureOptionDashboardAnalytic: none(),
dateFrom: DateTime.now().subtract(const Duration(days: 30)), dateFrom: DateTime.now(),
dateTo: DateTime.now(), dateTo: DateTime.now(),
); );
} }
@@ -4,6 +4,8 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import '../../../common/utils/device_info_service.dart';
import '../../../common/utils/fcm_service.dart';
import '../../../domain/auth/auth.dart'; import '../../../domain/auth/auth.dart';
part 'login_form_event.dart'; part 'login_form_event.dart';
@@ -13,7 +15,11 @@ part 'login_form_bloc.freezed.dart';
@injectable @injectable
class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> { class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
final IAuthRepository _repository; final IAuthRepository _repository;
LoginFormBloc(this._repository) : super(LoginFormState.initial()) { final DeviceInfoService _deviceInfoService;
final FcmService _fcmService;
LoginFormBloc(this._repository, this._deviceInfoService, this._fcmService)
: super(LoginFormState.initial()) {
on<LoginFormEvent>(_onLoginFormEvent); on<LoginFormEvent>(_onLoginFormEvent);
} }
@@ -36,9 +42,25 @@ class LoginFormBloc extends Bloc<LoginFormEvent, LoginFormState> {
final passwordValid = state.password.isNotEmpty; final passwordValid = state.password.isNotEmpty;
if (emailValid && passwordValid) { if (emailValid && passwordValid) {
// Ambil device info dan FCM token secara paralel
final results = await Future.wait([
_deviceInfoService.getDeviceInfo(),
_fcmService.getToken(),
]);
final deviceInfo = results[0] as DeviceInfo;
final fcmToken = results[1] as String?;
failureOrAuth = await _repository.login( failureOrAuth = await _repository.login(
email: state.email, email: state.email,
password: state.password, password: state.password,
deviceId: deviceInfo.deviceId,
deviceName: deviceInfo.deviceName,
deviceType: deviceInfo.deviceType,
platform: deviceInfo.platform,
osVersion: deviceInfo.osVersion,
appVersion: deviceInfo.appVersion,
fcmToken: fcmToken,
); );
emit( emit(
state.copyWith( state.copyWith(
@@ -30,6 +30,9 @@ class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
searchChanged: (e) async { searchChanged: (e) async {
emit(state.copyWith(search: e.search)); emit(state.copyWith(search: e.search));
}, },
outletChanged: (e) async {
emit(state.copyWith(outletId: e.outletId));
},
fetched: (e) async { fetched: (e) async {
var newState = state; var newState = state;
@@ -69,6 +72,7 @@ class OrderLoaderBloc extends Bloc<OrderLoaderEvent, OrderLoaderState> {
status: state.status == 'all' ? null : state.status, status: state.status == 'all' ? null : state.status,
page: state.page, page: state.page,
search: state.search, search: state.search,
outletId: state.outletId,
dateFrom: state.dateFrom, dateFrom: state.dateFrom,
dateTo: state.dateTo, dateTo: state.dateTo,
); );
@@ -23,6 +23,7 @@ mixin _$OrderLoaderEvent {
rangeDateChanged, rangeDateChanged,
required TResult Function(String status) statusChanged, required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged, required TResult Function(String search) searchChanged,
required TResult Function(String? outletId) outletChanged,
required TResult Function(bool isRefresh) fetched, required TResult Function(bool isRefresh) fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@@ -30,6 +31,7 @@ mixin _$OrderLoaderEvent {
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function(String status)? statusChanged, TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged, TResult? Function(String search)? searchChanged,
TResult? Function(String? outletId)? outletChanged,
TResult? Function(bool isRefresh)? fetched, TResult? Function(bool isRefresh)? fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@@ -37,6 +39,7 @@ mixin _$OrderLoaderEvent {
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function(String status)? statusChanged, TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged, TResult Function(String search)? searchChanged,
TResult Function(String? outletId)? outletChanged,
TResult Function(bool isRefresh)? fetched, TResult Function(bool isRefresh)? fetched,
required TResult orElse(), required TResult orElse(),
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@@ -45,6 +48,7 @@ mixin _$OrderLoaderEvent {
required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_StatusChanged value) statusChanged, required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged, required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_OutletChanged value) outletChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@@ -52,6 +56,7 @@ mixin _$OrderLoaderEvent {
TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_StatusChanged value)? statusChanged, TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged, TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_OutletChanged value)? outletChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@@ -59,6 +64,7 @@ mixin _$OrderLoaderEvent {
TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_StatusChanged value)? statusChanged, TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged, TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_OutletChanged value)? outletChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) => throw _privateConstructorUsedError; }) => throw _privateConstructorUsedError;
@@ -171,6 +177,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
rangeDateChanged, rangeDateChanged,
required TResult Function(String status) statusChanged, required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged, required TResult Function(String search) searchChanged,
required TResult Function(String? outletId) outletChanged,
required TResult Function(bool isRefresh) fetched, required TResult Function(bool isRefresh) fetched,
}) { }) {
return rangeDateChanged(dateFrom, dateTo); return rangeDateChanged(dateFrom, dateTo);
@@ -182,6 +189,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function(String status)? statusChanged, TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged, TResult? Function(String search)? searchChanged,
TResult? Function(String? outletId)? outletChanged,
TResult? Function(bool isRefresh)? fetched, TResult? Function(bool isRefresh)? fetched,
}) { }) {
return rangeDateChanged?.call(dateFrom, dateTo); return rangeDateChanged?.call(dateFrom, dateTo);
@@ -193,6 +201,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function(String status)? statusChanged, TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged, TResult Function(String search)? searchChanged,
TResult Function(String? outletId)? outletChanged,
TResult Function(bool isRefresh)? fetched, TResult Function(bool isRefresh)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -208,6 +217,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_StatusChanged value) statusChanged, required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged, required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_OutletChanged value) outletChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) { }) {
return rangeDateChanged(this); return rangeDateChanged(this);
@@ -219,6 +229,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_StatusChanged value)? statusChanged, TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged, TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_OutletChanged value)? outletChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) { }) {
return rangeDateChanged?.call(this); return rangeDateChanged?.call(this);
@@ -230,6 +241,7 @@ class _$RangeDateChangedImpl implements _RangeDateChanged {
TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_StatusChanged value)? statusChanged, TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged, TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_OutletChanged value)? outletChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -330,6 +342,7 @@ class _$StatusChangedImpl implements _StatusChanged {
rangeDateChanged, rangeDateChanged,
required TResult Function(String status) statusChanged, required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged, required TResult Function(String search) searchChanged,
required TResult Function(String? outletId) outletChanged,
required TResult Function(bool isRefresh) fetched, required TResult Function(bool isRefresh) fetched,
}) { }) {
return statusChanged(status); return statusChanged(status);
@@ -341,6 +354,7 @@ class _$StatusChangedImpl implements _StatusChanged {
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function(String status)? statusChanged, TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged, TResult? Function(String search)? searchChanged,
TResult? Function(String? outletId)? outletChanged,
TResult? Function(bool isRefresh)? fetched, TResult? Function(bool isRefresh)? fetched,
}) { }) {
return statusChanged?.call(status); return statusChanged?.call(status);
@@ -352,6 +366,7 @@ class _$StatusChangedImpl implements _StatusChanged {
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function(String status)? statusChanged, TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged, TResult Function(String search)? searchChanged,
TResult Function(String? outletId)? outletChanged,
TResult Function(bool isRefresh)? fetched, TResult Function(bool isRefresh)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -367,6 +382,7 @@ class _$StatusChangedImpl implements _StatusChanged {
required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_StatusChanged value) statusChanged, required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged, required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_OutletChanged value) outletChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) { }) {
return statusChanged(this); return statusChanged(this);
@@ -378,6 +394,7 @@ class _$StatusChangedImpl implements _StatusChanged {
TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_StatusChanged value)? statusChanged, TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged, TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_OutletChanged value)? outletChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) { }) {
return statusChanged?.call(this); return statusChanged?.call(this);
@@ -389,6 +406,7 @@ class _$StatusChangedImpl implements _StatusChanged {
TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_StatusChanged value)? statusChanged, TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged, TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_OutletChanged value)? outletChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -485,6 +503,7 @@ class _$SearchChangedImpl implements _SearchChanged {
rangeDateChanged, rangeDateChanged,
required TResult Function(String status) statusChanged, required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged, required TResult Function(String search) searchChanged,
required TResult Function(String? outletId) outletChanged,
required TResult Function(bool isRefresh) fetched, required TResult Function(bool isRefresh) fetched,
}) { }) {
return searchChanged(search); return searchChanged(search);
@@ -496,6 +515,7 @@ class _$SearchChangedImpl implements _SearchChanged {
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function(String status)? statusChanged, TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged, TResult? Function(String search)? searchChanged,
TResult? Function(String? outletId)? outletChanged,
TResult? Function(bool isRefresh)? fetched, TResult? Function(bool isRefresh)? fetched,
}) { }) {
return searchChanged?.call(search); return searchChanged?.call(search);
@@ -507,6 +527,7 @@ class _$SearchChangedImpl implements _SearchChanged {
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function(String status)? statusChanged, TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged, TResult Function(String search)? searchChanged,
TResult Function(String? outletId)? outletChanged,
TResult Function(bool isRefresh)? fetched, TResult Function(bool isRefresh)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -522,6 +543,7 @@ class _$SearchChangedImpl implements _SearchChanged {
required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_StatusChanged value) statusChanged, required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged, required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_OutletChanged value) outletChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) { }) {
return searchChanged(this); return searchChanged(this);
@@ -533,6 +555,7 @@ class _$SearchChangedImpl implements _SearchChanged {
TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_StatusChanged value)? statusChanged, TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged, TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_OutletChanged value)? outletChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) { }) {
return searchChanged?.call(this); return searchChanged?.call(this);
@@ -544,6 +567,7 @@ class _$SearchChangedImpl implements _SearchChanged {
TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_StatusChanged value)? statusChanged, TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged, TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_OutletChanged value)? outletChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -566,6 +590,168 @@ abstract class _SearchChanged implements OrderLoaderEvent {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc
abstract class _$$OutletChangedImplCopyWith<$Res> {
factory _$$OutletChangedImplCopyWith(
_$OutletChangedImpl value,
$Res Function(_$OutletChangedImpl) then,
) = __$$OutletChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({String? outletId});
}
/// @nodoc
class __$$OutletChangedImplCopyWithImpl<$Res>
extends _$OrderLoaderEventCopyWithImpl<$Res, _$OutletChangedImpl>
implements _$$OutletChangedImplCopyWith<$Res> {
__$$OutletChangedImplCopyWithImpl(
_$OutletChangedImpl _value,
$Res Function(_$OutletChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? outletId = freezed}) {
return _then(
_$OutletChangedImpl(
freezed == outletId
? _value.outletId
: outletId // ignore: cast_nullable_to_non_nullable
as String?,
),
);
}
}
/// @nodoc
class _$OutletChangedImpl implements _OutletChanged {
const _$OutletChangedImpl(this.outletId);
@override
final String? outletId;
@override
String toString() {
return 'OrderLoaderEvent.outletChanged(outletId: $outletId)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$OutletChangedImpl &&
(identical(other.outletId, outletId) ||
other.outletId == outletId));
}
@override
int get hashCode => Object.hash(runtimeType, outletId);
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$OutletChangedImplCopyWith<_$OutletChangedImpl> get copyWith =>
__$$OutletChangedImplCopyWithImpl<_$OutletChangedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(DateTime dateFrom, DateTime dateTo)
rangeDateChanged,
required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged,
required TResult Function(String? outletId) outletChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return outletChanged(outletId);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged,
TResult? Function(String? outletId)? outletChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return outletChanged?.call(outletId);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged,
TResult Function(String? outletId)? outletChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (outletChanged != null) {
return outletChanged(outletId);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_OutletChanged value) outletChanged,
required TResult Function(_Fetched value) fetched,
}) {
return outletChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_OutletChanged value)? outletChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return outletChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_OutletChanged value)? outletChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (outletChanged != null) {
return outletChanged(this);
}
return orElse();
}
}
abstract class _OutletChanged implements OrderLoaderEvent {
const factory _OutletChanged(final String? outletId) = _$OutletChangedImpl;
String? get outletId;
/// Create a copy of OrderLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$OutletChangedImplCopyWith<_$OutletChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc /// @nodoc
abstract class _$$FetchedImplCopyWith<$Res> { abstract class _$$FetchedImplCopyWith<$Res> {
factory _$$FetchedImplCopyWith( factory _$$FetchedImplCopyWith(
@@ -642,6 +828,7 @@ class _$FetchedImpl implements _Fetched {
rangeDateChanged, rangeDateChanged,
required TResult Function(String status) statusChanged, required TResult Function(String status) statusChanged,
required TResult Function(String search) searchChanged, required TResult Function(String search) searchChanged,
required TResult Function(String? outletId) outletChanged,
required TResult Function(bool isRefresh) fetched, required TResult Function(bool isRefresh) fetched,
}) { }) {
return fetched(isRefresh); return fetched(isRefresh);
@@ -653,6 +840,7 @@ class _$FetchedImpl implements _Fetched {
TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult? Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult? Function(String status)? statusChanged, TResult? Function(String status)? statusChanged,
TResult? Function(String search)? searchChanged, TResult? Function(String search)? searchChanged,
TResult? Function(String? outletId)? outletChanged,
TResult? Function(bool isRefresh)? fetched, TResult? Function(bool isRefresh)? fetched,
}) { }) {
return fetched?.call(isRefresh); return fetched?.call(isRefresh);
@@ -664,6 +852,7 @@ class _$FetchedImpl implements _Fetched {
TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged, TResult Function(DateTime dateFrom, DateTime dateTo)? rangeDateChanged,
TResult Function(String status)? statusChanged, TResult Function(String status)? statusChanged,
TResult Function(String search)? searchChanged, TResult Function(String search)? searchChanged,
TResult Function(String? outletId)? outletChanged,
TResult Function(bool isRefresh)? fetched, TResult Function(bool isRefresh)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -679,6 +868,7 @@ class _$FetchedImpl implements _Fetched {
required TResult Function(_RangeDateChanged value) rangeDateChanged, required TResult Function(_RangeDateChanged value) rangeDateChanged,
required TResult Function(_StatusChanged value) statusChanged, required TResult Function(_StatusChanged value) statusChanged,
required TResult Function(_SearchChanged value) searchChanged, required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_OutletChanged value) outletChanged,
required TResult Function(_Fetched value) fetched, required TResult Function(_Fetched value) fetched,
}) { }) {
return fetched(this); return fetched(this);
@@ -690,6 +880,7 @@ class _$FetchedImpl implements _Fetched {
TResult? Function(_RangeDateChanged value)? rangeDateChanged, TResult? Function(_RangeDateChanged value)? rangeDateChanged,
TResult? Function(_StatusChanged value)? statusChanged, TResult? Function(_StatusChanged value)? statusChanged,
TResult? Function(_SearchChanged value)? searchChanged, TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_OutletChanged value)? outletChanged,
TResult? Function(_Fetched value)? fetched, TResult? Function(_Fetched value)? fetched,
}) { }) {
return fetched?.call(this); return fetched?.call(this);
@@ -701,6 +892,7 @@ class _$FetchedImpl implements _Fetched {
TResult Function(_RangeDateChanged value)? rangeDateChanged, TResult Function(_RangeDateChanged value)? rangeDateChanged,
TResult Function(_StatusChanged value)? statusChanged, TResult Function(_StatusChanged value)? statusChanged,
TResult Function(_SearchChanged value)? searchChanged, TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_OutletChanged value)? outletChanged,
TResult Function(_Fetched value)? fetched, TResult Function(_Fetched value)? fetched,
required TResult orElse(), required TResult orElse(),
}) { }) {
@@ -730,6 +922,7 @@ mixin _$OrderLoaderState {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
String get status => throw _privateConstructorUsedError; String get status => throw _privateConstructorUsedError;
String? get search => throw _privateConstructorUsedError; String? get search => throw _privateConstructorUsedError;
String? get outletId => throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError; bool get isFetching => throw _privateConstructorUsedError;
bool get hasReachedMax => throw _privateConstructorUsedError; bool get hasReachedMax => throw _privateConstructorUsedError;
int get page => throw _privateConstructorUsedError; int get page => throw _privateConstructorUsedError;
@@ -755,6 +948,7 @@ abstract class $OrderLoaderStateCopyWith<$Res> {
Option<OrderFailure> failureOptionOrder, Option<OrderFailure> failureOptionOrder,
String status, String status,
String? search, String? search,
String? outletId,
bool isFetching, bool isFetching,
bool hasReachedMax, bool hasReachedMax,
int page, int page,
@@ -782,6 +976,7 @@ class _$OrderLoaderStateCopyWithImpl<$Res, $Val extends OrderLoaderState>
Object? failureOptionOrder = null, Object? failureOptionOrder = null,
Object? status = null, Object? status = null,
Object? search = freezed, Object? search = freezed,
Object? outletId = freezed,
Object? isFetching = null, Object? isFetching = null,
Object? hasReachedMax = null, Object? hasReachedMax = null,
Object? page = null, Object? page = null,
@@ -806,6 +1001,10 @@ class _$OrderLoaderStateCopyWithImpl<$Res, $Val extends OrderLoaderState>
? _value.search ? _value.search
: search // ignore: cast_nullable_to_non_nullable : search // ignore: cast_nullable_to_non_nullable
as String?, as String?,
outletId: freezed == outletId
? _value.outletId
: outletId // ignore: cast_nullable_to_non_nullable
as String?,
isFetching: null == isFetching isFetching: null == isFetching
? _value.isFetching ? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable : isFetching // ignore: cast_nullable_to_non_nullable
@@ -846,6 +1045,7 @@ abstract class _$$OrderLoaderStateImplCopyWith<$Res>
Option<OrderFailure> failureOptionOrder, Option<OrderFailure> failureOptionOrder,
String status, String status,
String? search, String? search,
String? outletId,
bool isFetching, bool isFetching,
bool hasReachedMax, bool hasReachedMax,
int page, int page,
@@ -872,6 +1072,7 @@ class __$$OrderLoaderStateImplCopyWithImpl<$Res>
Object? failureOptionOrder = null, Object? failureOptionOrder = null,
Object? status = null, Object? status = null,
Object? search = freezed, Object? search = freezed,
Object? outletId = freezed,
Object? isFetching = null, Object? isFetching = null,
Object? hasReachedMax = null, Object? hasReachedMax = null,
Object? page = null, Object? page = null,
@@ -896,6 +1097,10 @@ class __$$OrderLoaderStateImplCopyWithImpl<$Res>
? _value.search ? _value.search
: search // ignore: cast_nullable_to_non_nullable : search // ignore: cast_nullable_to_non_nullable
as String?, as String?,
outletId: freezed == outletId
? _value.outletId
: outletId // ignore: cast_nullable_to_non_nullable
as String?,
isFetching: null == isFetching isFetching: null == isFetching
? _value.isFetching ? _value.isFetching
: isFetching // ignore: cast_nullable_to_non_nullable : isFetching // ignore: cast_nullable_to_non_nullable
@@ -929,6 +1134,7 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
required this.failureOptionOrder, required this.failureOptionOrder,
required this.status, required this.status,
this.search, this.search,
this.outletId,
this.isFetching = false, this.isFetching = false,
this.hasReachedMax = false, this.hasReachedMax = false,
this.page = 1, this.page = 1,
@@ -951,6 +1157,8 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
@override @override
final String? search; final String? search;
@override @override
final String? outletId;
@override
@JsonKey() @JsonKey()
final bool isFetching; final bool isFetching;
@override @override
@@ -966,7 +1174,7 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
@override @override
String toString() { String toString() {
return 'OrderLoaderState(orders: $orders, failureOptionOrder: $failureOptionOrder, status: $status, search: $search, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page, dateFrom: $dateFrom, dateTo: $dateTo)'; return 'OrderLoaderState(orders: $orders, failureOptionOrder: $failureOptionOrder, status: $status, search: $search, outletId: $outletId, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page, dateFrom: $dateFrom, dateTo: $dateTo)';
} }
@override @override
@@ -979,6 +1187,8 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
other.failureOptionOrder == failureOptionOrder) && other.failureOptionOrder == failureOptionOrder) &&
(identical(other.status, status) || other.status == status) && (identical(other.status, status) || other.status == status) &&
(identical(other.search, search) || other.search == search) && (identical(other.search, search) || other.search == search) &&
(identical(other.outletId, outletId) ||
other.outletId == outletId) &&
(identical(other.isFetching, isFetching) || (identical(other.isFetching, isFetching) ||
other.isFetching == isFetching) && other.isFetching == isFetching) &&
(identical(other.hasReachedMax, hasReachedMax) || (identical(other.hasReachedMax, hasReachedMax) ||
@@ -996,6 +1206,7 @@ class _$OrderLoaderStateImpl implements _OrderLoaderState {
failureOptionOrder, failureOptionOrder,
status, status,
search, search,
outletId,
isFetching, isFetching,
hasReachedMax, hasReachedMax,
page, page,
@@ -1021,6 +1232,7 @@ abstract class _OrderLoaderState implements OrderLoaderState {
required final Option<OrderFailure> failureOptionOrder, required final Option<OrderFailure> failureOptionOrder,
required final String status, required final String status,
final String? search, final String? search,
final String? outletId,
final bool isFetching, final bool isFetching,
final bool hasReachedMax, final bool hasReachedMax,
final int page, final int page,
@@ -1037,6 +1249,8 @@ abstract class _OrderLoaderState implements OrderLoaderState {
@override @override
String? get search; String? get search;
@override @override
String? get outletId;
@override
bool get isFetching; bool get isFetching;
@override @override
bool get hasReachedMax; bool get hasReachedMax;
@@ -8,6 +8,8 @@ class OrderLoaderEvent with _$OrderLoaderEvent {
) = _RangeDateChanged; ) = _RangeDateChanged;
const factory OrderLoaderEvent.statusChanged(String status) = _StatusChanged; const factory OrderLoaderEvent.statusChanged(String status) = _StatusChanged;
const factory OrderLoaderEvent.searchChanged(String search) = _SearchChanged; const factory OrderLoaderEvent.searchChanged(String search) = _SearchChanged;
const factory OrderLoaderEvent.outletChanged(String? outletId) =
_OutletChanged;
const factory OrderLoaderEvent.fetched({@Default(false) bool isRefresh}) = const factory OrderLoaderEvent.fetched({@Default(false) bool isRefresh}) =
_Fetched; _Fetched;
} }
@@ -7,6 +7,7 @@ class OrderLoaderState with _$OrderLoaderState {
required Option<OrderFailure> failureOptionOrder, required Option<OrderFailure> failureOptionOrder,
required String status, required String status,
String? search, String? search,
String? outletId,
@Default(false) bool isFetching, @Default(false) bool isFetching,
@Default(false) bool hasReachedMax, @Default(false) bool hasReachedMax,
@Default(1) int page, @Default(1) int page,
@@ -17,7 +18,7 @@ class OrderLoaderState with _$OrderLoaderState {
factory OrderLoaderState.initial() => OrderLoaderState( factory OrderLoaderState.initial() => OrderLoaderState(
orders: [], orders: [],
failureOptionOrder: none(), failureOptionOrder: none(),
dateFrom: DateTime.now().subtract(const Duration(days: 30)), dateFrom: DateTime.now(),
dateTo: DateTime.now(), dateTo: DateTime.now(),
status: 'all', status: 'all',
); );
@@ -0,0 +1,92 @@
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/outlet/outlet.dart';
part 'outlet_list_loader_event.dart';
part 'outlet_list_loader_state.dart';
part 'outlet_list_loader_bloc.freezed.dart';
@injectable
class OutletListLoaderBloc
extends Bloc<OutletListLoaderEvent, OutletListLoaderState> {
final IOutletRepository _outletRepository;
OutletListLoaderBloc(this._outletRepository)
: super(OutletListLoaderState.initial()) {
on<OutletListLoaderEvent>(_onOutletListLoaderEvent);
}
Future<void> _onOutletListLoaderEvent(
OutletListLoaderEvent event,
Emitter<OutletListLoaderState> emit,
) {
return event.map(
searchChanged: (e) async {
emit(state.copyWith(search: e.search));
},
isActiveChanged: (e) async {
emit(state.copyWith(isActive: e.isActive));
},
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<OutletListLoaderState> _mapFetchedToState(
OutletListLoaderState 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 failureOrOutlets = await _outletRepository.getList(
page: state.page,
search: state.search,
isActive: state.isActive,
);
state = failureOrOutlets.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,828 @@
// 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_list_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 _$OutletListLoaderEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String search) searchChanged,
required TResult Function(bool? isActive) isActiveChanged,
required TResult Function(bool isRefresh) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String search)? searchChanged,
TResult? Function(bool? isActive)? isActiveChanged,
TResult? Function(bool isRefresh)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String search)? searchChanged,
TResult Function(bool? isActive)? isActiveChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_IsActiveChanged value) isActiveChanged,
required TResult Function(_Fetched value) fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_IsActiveChanged value)? isActiveChanged,
TResult? Function(_Fetched value)? fetched,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_IsActiveChanged value)? isActiveChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $OutletListLoaderEventCopyWith<$Res> {
factory $OutletListLoaderEventCopyWith(
OutletListLoaderEvent value,
$Res Function(OutletListLoaderEvent) then,
) = _$OutletListLoaderEventCopyWithImpl<$Res, OutletListLoaderEvent>;
}
/// @nodoc
class _$OutletListLoaderEventCopyWithImpl<
$Res,
$Val extends OutletListLoaderEvent
>
implements $OutletListLoaderEventCopyWith<$Res> {
_$OutletListLoaderEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$SearchChangedImplCopyWith<$Res> {
factory _$$SearchChangedImplCopyWith(
_$SearchChangedImpl value,
$Res Function(_$SearchChangedImpl) then,
) = __$$SearchChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({String search});
}
/// @nodoc
class __$$SearchChangedImplCopyWithImpl<$Res>
extends _$OutletListLoaderEventCopyWithImpl<$Res, _$SearchChangedImpl>
implements _$$SearchChangedImplCopyWith<$Res> {
__$$SearchChangedImplCopyWithImpl(
_$SearchChangedImpl _value,
$Res Function(_$SearchChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? search = null}) {
return _then(
_$SearchChangedImpl(
null == search
? _value.search
: search // ignore: cast_nullable_to_non_nullable
as String,
),
);
}
}
/// @nodoc
class _$SearchChangedImpl implements _SearchChanged {
const _$SearchChangedImpl(this.search);
@override
final String search;
@override
String toString() {
return 'OutletListLoaderEvent.searchChanged(search: $search)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SearchChangedImpl &&
(identical(other.search, search) || other.search == search));
}
@override
int get hashCode => Object.hash(runtimeType, search);
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SearchChangedImplCopyWith<_$SearchChangedImpl> get copyWith =>
__$$SearchChangedImplCopyWithImpl<_$SearchChangedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String search) searchChanged,
required TResult Function(bool? isActive) isActiveChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return searchChanged(search);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String search)? searchChanged,
TResult? Function(bool? isActive)? isActiveChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return searchChanged?.call(search);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String search)? searchChanged,
TResult Function(bool? isActive)? isActiveChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (searchChanged != null) {
return searchChanged(search);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_IsActiveChanged value) isActiveChanged,
required TResult Function(_Fetched value) fetched,
}) {
return searchChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_IsActiveChanged value)? isActiveChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return searchChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_IsActiveChanged value)? isActiveChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (searchChanged != null) {
return searchChanged(this);
}
return orElse();
}
}
abstract class _SearchChanged implements OutletListLoaderEvent {
const factory _SearchChanged(final String search) = _$SearchChangedImpl;
String get search;
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SearchChangedImplCopyWith<_$SearchChangedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$IsActiveChangedImplCopyWith<$Res> {
factory _$$IsActiveChangedImplCopyWith(
_$IsActiveChangedImpl value,
$Res Function(_$IsActiveChangedImpl) then,
) = __$$IsActiveChangedImplCopyWithImpl<$Res>;
@useResult
$Res call({bool? isActive});
}
/// @nodoc
class __$$IsActiveChangedImplCopyWithImpl<$Res>
extends _$OutletListLoaderEventCopyWithImpl<$Res, _$IsActiveChangedImpl>
implements _$$IsActiveChangedImplCopyWith<$Res> {
__$$IsActiveChangedImplCopyWithImpl(
_$IsActiveChangedImpl _value,
$Res Function(_$IsActiveChangedImpl) _then,
) : super(_value, _then);
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? isActive = freezed}) {
return _then(
_$IsActiveChangedImpl(
freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
),
);
}
}
/// @nodoc
class _$IsActiveChangedImpl implements _IsActiveChanged {
const _$IsActiveChangedImpl(this.isActive);
@override
final bool? isActive;
@override
String toString() {
return 'OutletListLoaderEvent.isActiveChanged(isActive: $isActive)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$IsActiveChangedImpl &&
(identical(other.isActive, isActive) ||
other.isActive == isActive));
}
@override
int get hashCode => Object.hash(runtimeType, isActive);
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$IsActiveChangedImplCopyWith<_$IsActiveChangedImpl> get copyWith =>
__$$IsActiveChangedImplCopyWithImpl<_$IsActiveChangedImpl>(
this,
_$identity,
);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function(String search) searchChanged,
required TResult Function(bool? isActive) isActiveChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return isActiveChanged(isActive);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String search)? searchChanged,
TResult? Function(bool? isActive)? isActiveChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return isActiveChanged?.call(isActive);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String search)? searchChanged,
TResult Function(bool? isActive)? isActiveChanged,
TResult Function(bool isRefresh)? fetched,
required TResult orElse(),
}) {
if (isActiveChanged != null) {
return isActiveChanged(isActive);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_SearchChanged value) searchChanged,
required TResult Function(_IsActiveChanged value) isActiveChanged,
required TResult Function(_Fetched value) fetched,
}) {
return isActiveChanged(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_IsActiveChanged value)? isActiveChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return isActiveChanged?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_IsActiveChanged value)? isActiveChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (isActiveChanged != null) {
return isActiveChanged(this);
}
return orElse();
}
}
abstract class _IsActiveChanged implements OutletListLoaderEvent {
const factory _IsActiveChanged(final bool? isActive) = _$IsActiveChangedImpl;
bool? get isActive;
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$IsActiveChangedImplCopyWith<_$IsActiveChangedImpl> 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 _$OutletListLoaderEventCopyWithImpl<$Res, _$FetchedImpl>
implements _$$FetchedImplCopyWith<$Res> {
__$$FetchedImplCopyWithImpl(
_$FetchedImpl _value,
$Res Function(_$FetchedImpl) _then,
) : super(_value, _then);
/// Create a copy of OutletListLoaderEvent
/// 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 'OutletListLoaderEvent.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 OutletListLoaderEvent
/// 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(String search) searchChanged,
required TResult Function(bool? isActive) isActiveChanged,
required TResult Function(bool isRefresh) fetched,
}) {
return fetched(isRefresh);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function(String search)? searchChanged,
TResult? Function(bool? isActive)? isActiveChanged,
TResult? Function(bool isRefresh)? fetched,
}) {
return fetched?.call(isRefresh);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function(String search)? searchChanged,
TResult Function(bool? isActive)? isActiveChanged,
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(_SearchChanged value) searchChanged,
required TResult Function(_IsActiveChanged value) isActiveChanged,
required TResult Function(_Fetched value) fetched,
}) {
return fetched(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_SearchChanged value)? searchChanged,
TResult? Function(_IsActiveChanged value)? isActiveChanged,
TResult? Function(_Fetched value)? fetched,
}) {
return fetched?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_SearchChanged value)? searchChanged,
TResult Function(_IsActiveChanged value)? isActiveChanged,
TResult Function(_Fetched value)? fetched,
required TResult orElse(),
}) {
if (fetched != null) {
return fetched(this);
}
return orElse();
}
}
abstract class _Fetched implements OutletListLoaderEvent {
const factory _Fetched({final bool isRefresh}) = _$FetchedImpl;
bool get isRefresh;
/// Create a copy of OutletListLoaderEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$FetchedImplCopyWith<_$FetchedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
mixin _$OutletListLoaderState {
List<Outlet> get outlets => throw _privateConstructorUsedError;
Option<OutletFailure> get failureOptionOutlet =>
throw _privateConstructorUsedError;
String? get search => throw _privateConstructorUsedError;
bool? get isActive => throw _privateConstructorUsedError;
bool get isFetching => throw _privateConstructorUsedError;
bool get hasReachedMax => throw _privateConstructorUsedError;
int get page => throw _privateConstructorUsedError;
/// Create a copy of OutletListLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$OutletListLoaderStateCopyWith<OutletListLoaderState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $OutletListLoaderStateCopyWith<$Res> {
factory $OutletListLoaderStateCopyWith(
OutletListLoaderState value,
$Res Function(OutletListLoaderState) then,
) = _$OutletListLoaderStateCopyWithImpl<$Res, OutletListLoaderState>;
@useResult
$Res call({
List<Outlet> outlets,
Option<OutletFailure> failureOptionOutlet,
String? search,
bool? isActive,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class _$OutletListLoaderStateCopyWithImpl<
$Res,
$Val extends OutletListLoaderState
>
implements $OutletListLoaderStateCopyWith<$Res> {
_$OutletListLoaderStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of OutletListLoaderState
/// 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? search = freezed,
Object? isActive = freezed,
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>,
search: freezed == search
? _value.search
: search // ignore: cast_nullable_to_non_nullable
as String?,
isActive: freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
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 _$$OutletListLoaderStateImplCopyWith<$Res>
implements $OutletListLoaderStateCopyWith<$Res> {
factory _$$OutletListLoaderStateImplCopyWith(
_$OutletListLoaderStateImpl value,
$Res Function(_$OutletListLoaderStateImpl) then,
) = __$$OutletListLoaderStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({
List<Outlet> outlets,
Option<OutletFailure> failureOptionOutlet,
String? search,
bool? isActive,
bool isFetching,
bool hasReachedMax,
int page,
});
}
/// @nodoc
class __$$OutletListLoaderStateImplCopyWithImpl<$Res>
extends
_$OutletListLoaderStateCopyWithImpl<$Res, _$OutletListLoaderStateImpl>
implements _$$OutletListLoaderStateImplCopyWith<$Res> {
__$$OutletListLoaderStateImplCopyWithImpl(
_$OutletListLoaderStateImpl _value,
$Res Function(_$OutletListLoaderStateImpl) _then,
) : super(_value, _then);
/// Create a copy of OutletListLoaderState
/// 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? search = freezed,
Object? isActive = freezed,
Object? isFetching = null,
Object? hasReachedMax = null,
Object? page = null,
}) {
return _then(
_$OutletListLoaderStateImpl(
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>,
search: freezed == search
? _value.search
: search // ignore: cast_nullable_to_non_nullable
as String?,
isActive: freezed == isActive
? _value.isActive
: isActive // ignore: cast_nullable_to_non_nullable
as bool?,
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 _$OutletListLoaderStateImpl implements _OutletListLoaderState {
const _$OutletListLoaderStateImpl({
required final List<Outlet> outlets,
required this.failureOptionOutlet,
this.search,
this.isActive,
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
final String? search;
@override
final bool? isActive;
@override
@JsonKey()
final bool isFetching;
@override
@JsonKey()
final bool hasReachedMax;
@override
@JsonKey()
final int page;
@override
String toString() {
return 'OutletListLoaderState(outlets: $outlets, failureOptionOutlet: $failureOptionOutlet, search: $search, isActive: $isActive, isFetching: $isFetching, hasReachedMax: $hasReachedMax, page: $page)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$OutletListLoaderStateImpl &&
const DeepCollectionEquality().equals(other._outlets, _outlets) &&
(identical(other.failureOptionOutlet, failureOptionOutlet) ||
other.failureOptionOutlet == failureOptionOutlet) &&
(identical(other.search, search) || other.search == search) &&
(identical(other.isActive, isActive) ||
other.isActive == isActive) &&
(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,
search,
isActive,
isFetching,
hasReachedMax,
page,
);
/// Create a copy of OutletListLoaderState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$OutletListLoaderStateImplCopyWith<_$OutletListLoaderStateImpl>
get copyWith =>
__$$OutletListLoaderStateImplCopyWithImpl<_$OutletListLoaderStateImpl>(
this,
_$identity,
);
}
abstract class _OutletListLoaderState implements OutletListLoaderState {
const factory _OutletListLoaderState({
required final List<Outlet> outlets,
required final Option<OutletFailure> failureOptionOutlet,
final String? search,
final bool? isActive,
final bool isFetching,
final bool hasReachedMax,
final int page,
}) = _$OutletListLoaderStateImpl;
@override
List<Outlet> get outlets;
@override
Option<OutletFailure> get failureOptionOutlet;
@override
String? get search;
@override
bool? get isActive;
@override
bool get isFetching;
@override
bool get hasReachedMax;
@override
int get page;
/// Create a copy of OutletListLoaderState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$OutletListLoaderStateImplCopyWith<_$OutletListLoaderStateImpl>
get copyWith => throw _privateConstructorUsedError;
}
@@ -0,0 +1,12 @@
part of 'outlet_list_loader_bloc.dart';
@freezed
class OutletListLoaderEvent with _$OutletListLoaderEvent {
const factory OutletListLoaderEvent.searchChanged(String search) =
_SearchChanged;
const factory OutletListLoaderEvent.isActiveChanged(bool? isActive) =
_IsActiveChanged;
const factory OutletListLoaderEvent.fetched({
@Default(false) bool isRefresh,
}) = _Fetched;
}
@@ -0,0 +1,17 @@
part of 'outlet_list_loader_bloc.dart';
@freezed
class OutletListLoaderState with _$OutletListLoaderState {
const factory OutletListLoaderState({
required List<Outlet> outlets,
required Option<OutletFailure> failureOptionOutlet,
String? search,
bool? isActive,
@Default(false) bool isFetching,
@Default(false) bool hasReachedMax,
@Default(1) int page,
}) = _OutletListLoaderState;
factory OutletListLoaderState.initial() =>
OutletListLoaderState(outlets: [], failureOptionOutlet: none());
}
@@ -0,0 +1,46 @@
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:injectable/injectable.dart';
import '../../../domain/outlet/outlet.dart';
import '../../../infrastructure/outlet/datasource/local_data_provider.dart';
part 'selected_outlet_event.dart';
part 'selected_outlet_state.dart';
part 'selected_outlet_bloc.freezed.dart';
@injectable
class SelectedOutletBloc
extends Bloc<SelectedOutletEvent, SelectedOutletState> {
final OutletLocalDataProvider _localDataProvider;
SelectedOutletBloc(this._localDataProvider)
: super(SelectedOutletState.initial()) {
on<SelectedOutletEvent>(_onSelectedOutletEvent);
}
Future<void> _onSelectedOutletEvent(
SelectedOutletEvent event,
Emitter<SelectedOutletState> emit,
) {
return event.map(
loaded: (e) async {
final savedId = _localDataProvider.getSelectedOutletId();
emit(state.copyWith(selectedOutletId: savedId));
},
selected: (e) async {
await _localDataProvider.saveSelectedOutletId(e.outlet.id);
emit(
state.copyWith(
selectedOutlet: e.outlet,
selectedOutletId: e.outlet.id,
),
);
},
cleared: (e) async {
await _localDataProvider.deleteSelectedOutletId();
emit(SelectedOutletState.initial());
},
);
}
}
@@ -0,0 +1,649 @@
// 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 'selected_outlet_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 _$SelectedOutletEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() loaded,
required TResult Function(Outlet outlet) selected,
required TResult Function() cleared,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? loaded,
TResult? Function(Outlet outlet)? selected,
TResult? Function()? cleared,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? loaded,
TResult Function(Outlet outlet)? selected,
TResult Function()? cleared,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Loaded value) loaded,
required TResult Function(_Selected value) selected,
required TResult Function(_Cleared value) cleared,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Selected value)? selected,
TResult? Function(_Cleared value)? cleared,
}) => throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Loaded value)? loaded,
TResult Function(_Selected value)? selected,
TResult Function(_Cleared value)? cleared,
required TResult orElse(),
}) => throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SelectedOutletEventCopyWith<$Res> {
factory $SelectedOutletEventCopyWith(
SelectedOutletEvent value,
$Res Function(SelectedOutletEvent) then,
) = _$SelectedOutletEventCopyWithImpl<$Res, SelectedOutletEvent>;
}
/// @nodoc
class _$SelectedOutletEventCopyWithImpl<$Res, $Val extends SelectedOutletEvent>
implements $SelectedOutletEventCopyWith<$Res> {
_$SelectedOutletEventCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
abstract class _$$LoadedImplCopyWith<$Res> {
factory _$$LoadedImplCopyWith(
_$LoadedImpl value,
$Res Function(_$LoadedImpl) then,
) = __$$LoadedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$LoadedImplCopyWithImpl<$Res>
extends _$SelectedOutletEventCopyWithImpl<$Res, _$LoadedImpl>
implements _$$LoadedImplCopyWith<$Res> {
__$$LoadedImplCopyWithImpl(
_$LoadedImpl _value,
$Res Function(_$LoadedImpl) _then,
) : super(_value, _then);
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$LoadedImpl implements _Loaded {
const _$LoadedImpl();
@override
String toString() {
return 'SelectedOutletEvent.loaded()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$LoadedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() loaded,
required TResult Function(Outlet outlet) selected,
required TResult Function() cleared,
}) {
return loaded();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? loaded,
TResult? Function(Outlet outlet)? selected,
TResult? Function()? cleared,
}) {
return loaded?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? loaded,
TResult Function(Outlet outlet)? selected,
TResult Function()? cleared,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Loaded value) loaded,
required TResult Function(_Selected value) selected,
required TResult Function(_Cleared value) cleared,
}) {
return loaded(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Selected value)? selected,
TResult? Function(_Cleared value)? cleared,
}) {
return loaded?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Loaded value)? loaded,
TResult Function(_Selected value)? selected,
TResult Function(_Cleared value)? cleared,
required TResult orElse(),
}) {
if (loaded != null) {
return loaded(this);
}
return orElse();
}
}
abstract class _Loaded implements SelectedOutletEvent {
const factory _Loaded() = _$LoadedImpl;
}
/// @nodoc
abstract class _$$SelectedImplCopyWith<$Res> {
factory _$$SelectedImplCopyWith(
_$SelectedImpl value,
$Res Function(_$SelectedImpl) then,
) = __$$SelectedImplCopyWithImpl<$Res>;
@useResult
$Res call({Outlet outlet});
$OutletCopyWith<$Res> get outlet;
}
/// @nodoc
class __$$SelectedImplCopyWithImpl<$Res>
extends _$SelectedOutletEventCopyWithImpl<$Res, _$SelectedImpl>
implements _$$SelectedImplCopyWith<$Res> {
__$$SelectedImplCopyWithImpl(
_$SelectedImpl _value,
$Res Function(_$SelectedImpl) _then,
) : super(_value, _then);
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({Object? outlet = null}) {
return _then(
_$SelectedImpl(
null == outlet
? _value.outlet
: outlet // ignore: cast_nullable_to_non_nullable
as Outlet,
),
);
}
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$OutletCopyWith<$Res> get outlet {
return $OutletCopyWith<$Res>(_value.outlet, (value) {
return _then(_value.copyWith(outlet: value));
});
}
}
/// @nodoc
class _$SelectedImpl implements _Selected {
const _$SelectedImpl(this.outlet);
@override
final Outlet outlet;
@override
String toString() {
return 'SelectedOutletEvent.selected(outlet: $outlet)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SelectedImpl &&
(identical(other.outlet, outlet) || other.outlet == outlet));
}
@override
int get hashCode => Object.hash(runtimeType, outlet);
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SelectedImplCopyWith<_$SelectedImpl> get copyWith =>
__$$SelectedImplCopyWithImpl<_$SelectedImpl>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() loaded,
required TResult Function(Outlet outlet) selected,
required TResult Function() cleared,
}) {
return selected(outlet);
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? loaded,
TResult? Function(Outlet outlet)? selected,
TResult? Function()? cleared,
}) {
return selected?.call(outlet);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? loaded,
TResult Function(Outlet outlet)? selected,
TResult Function()? cleared,
required TResult orElse(),
}) {
if (selected != null) {
return selected(outlet);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Loaded value) loaded,
required TResult Function(_Selected value) selected,
required TResult Function(_Cleared value) cleared,
}) {
return selected(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Selected value)? selected,
TResult? Function(_Cleared value)? cleared,
}) {
return selected?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Loaded value)? loaded,
TResult Function(_Selected value)? selected,
TResult Function(_Cleared value)? cleared,
required TResult orElse(),
}) {
if (selected != null) {
return selected(this);
}
return orElse();
}
}
abstract class _Selected implements SelectedOutletEvent {
const factory _Selected(final Outlet outlet) = _$SelectedImpl;
Outlet get outlet;
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SelectedImplCopyWith<_$SelectedImpl> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$$ClearedImplCopyWith<$Res> {
factory _$$ClearedImplCopyWith(
_$ClearedImpl value,
$Res Function(_$ClearedImpl) then,
) = __$$ClearedImplCopyWithImpl<$Res>;
}
/// @nodoc
class __$$ClearedImplCopyWithImpl<$Res>
extends _$SelectedOutletEventCopyWithImpl<$Res, _$ClearedImpl>
implements _$$ClearedImplCopyWith<$Res> {
__$$ClearedImplCopyWithImpl(
_$ClearedImpl _value,
$Res Function(_$ClearedImpl) _then,
) : super(_value, _then);
/// Create a copy of SelectedOutletEvent
/// with the given fields replaced by the non-null parameter values.
}
/// @nodoc
class _$ClearedImpl implements _Cleared {
const _$ClearedImpl();
@override
String toString() {
return 'SelectedOutletEvent.cleared()';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType && other is _$ClearedImpl);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() loaded,
required TResult Function(Outlet outlet) selected,
required TResult Function() cleared,
}) {
return cleared();
}
@override
@optionalTypeArgs
TResult? whenOrNull<TResult extends Object?>({
TResult? Function()? loaded,
TResult? Function(Outlet outlet)? selected,
TResult? Function()? cleared,
}) {
return cleared?.call();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? loaded,
TResult Function(Outlet outlet)? selected,
TResult Function()? cleared,
required TResult orElse(),
}) {
if (cleared != null) {
return cleared();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Loaded value) loaded,
required TResult Function(_Selected value) selected,
required TResult Function(_Cleared value) cleared,
}) {
return cleared(this);
}
@override
@optionalTypeArgs
TResult? mapOrNull<TResult extends Object?>({
TResult? Function(_Loaded value)? loaded,
TResult? Function(_Selected value)? selected,
TResult? Function(_Cleared value)? cleared,
}) {
return cleared?.call(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Loaded value)? loaded,
TResult Function(_Selected value)? selected,
TResult Function(_Cleared value)? cleared,
required TResult orElse(),
}) {
if (cleared != null) {
return cleared(this);
}
return orElse();
}
}
abstract class _Cleared implements SelectedOutletEvent {
const factory _Cleared() = _$ClearedImpl;
}
/// @nodoc
mixin _$SelectedOutletState {
/// null berarti "Semua Outlet"
Outlet? get selectedOutlet => throw _privateConstructorUsedError;
String? get selectedOutletId => throw _privateConstructorUsedError;
/// Create a copy of SelectedOutletState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
$SelectedOutletStateCopyWith<SelectedOutletState> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $SelectedOutletStateCopyWith<$Res> {
factory $SelectedOutletStateCopyWith(
SelectedOutletState value,
$Res Function(SelectedOutletState) then,
) = _$SelectedOutletStateCopyWithImpl<$Res, SelectedOutletState>;
@useResult
$Res call({Outlet? selectedOutlet, String? selectedOutletId});
$OutletCopyWith<$Res>? get selectedOutlet;
}
/// @nodoc
class _$SelectedOutletStateCopyWithImpl<$Res, $Val extends SelectedOutletState>
implements $SelectedOutletStateCopyWith<$Res> {
_$SelectedOutletStateCopyWithImpl(this._value, this._then);
// ignore: unused_field
final $Val _value;
// ignore: unused_field
final $Res Function($Val) _then;
/// Create a copy of SelectedOutletState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? selectedOutlet = freezed,
Object? selectedOutletId = freezed,
}) {
return _then(
_value.copyWith(
selectedOutlet: freezed == selectedOutlet
? _value.selectedOutlet
: selectedOutlet // ignore: cast_nullable_to_non_nullable
as Outlet?,
selectedOutletId: freezed == selectedOutletId
? _value.selectedOutletId
: selectedOutletId // ignore: cast_nullable_to_non_nullable
as String?,
)
as $Val,
);
}
/// Create a copy of SelectedOutletState
/// with the given fields replaced by the non-null parameter values.
@override
@pragma('vm:prefer-inline')
$OutletCopyWith<$Res>? get selectedOutlet {
if (_value.selectedOutlet == null) {
return null;
}
return $OutletCopyWith<$Res>(_value.selectedOutlet!, (value) {
return _then(_value.copyWith(selectedOutlet: value) as $Val);
});
}
}
/// @nodoc
abstract class _$$SelectedOutletStateImplCopyWith<$Res>
implements $SelectedOutletStateCopyWith<$Res> {
factory _$$SelectedOutletStateImplCopyWith(
_$SelectedOutletStateImpl value,
$Res Function(_$SelectedOutletStateImpl) then,
) = __$$SelectedOutletStateImplCopyWithImpl<$Res>;
@override
@useResult
$Res call({Outlet? selectedOutlet, String? selectedOutletId});
@override
$OutletCopyWith<$Res>? get selectedOutlet;
}
/// @nodoc
class __$$SelectedOutletStateImplCopyWithImpl<$Res>
extends _$SelectedOutletStateCopyWithImpl<$Res, _$SelectedOutletStateImpl>
implements _$$SelectedOutletStateImplCopyWith<$Res> {
__$$SelectedOutletStateImplCopyWithImpl(
_$SelectedOutletStateImpl _value,
$Res Function(_$SelectedOutletStateImpl) _then,
) : super(_value, _then);
/// Create a copy of SelectedOutletState
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline')
@override
$Res call({
Object? selectedOutlet = freezed,
Object? selectedOutletId = freezed,
}) {
return _then(
_$SelectedOutletStateImpl(
selectedOutlet: freezed == selectedOutlet
? _value.selectedOutlet
: selectedOutlet // ignore: cast_nullable_to_non_nullable
as Outlet?,
selectedOutletId: freezed == selectedOutletId
? _value.selectedOutletId
: selectedOutletId // ignore: cast_nullable_to_non_nullable
as String?,
),
);
}
}
/// @nodoc
class _$SelectedOutletStateImpl implements _SelectedOutletState {
const _$SelectedOutletStateImpl({this.selectedOutlet, this.selectedOutletId});
/// null berarti "Semua Outlet"
@override
final Outlet? selectedOutlet;
@override
final String? selectedOutletId;
@override
String toString() {
return 'SelectedOutletState(selectedOutlet: $selectedOutlet, selectedOutletId: $selectedOutletId)';
}
@override
bool operator ==(Object other) {
return identical(this, other) ||
(other.runtimeType == runtimeType &&
other is _$SelectedOutletStateImpl &&
(identical(other.selectedOutlet, selectedOutlet) ||
other.selectedOutlet == selectedOutlet) &&
(identical(other.selectedOutletId, selectedOutletId) ||
other.selectedOutletId == selectedOutletId));
}
@override
int get hashCode =>
Object.hash(runtimeType, selectedOutlet, selectedOutletId);
/// Create a copy of SelectedOutletState
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@override
@pragma('vm:prefer-inline')
_$$SelectedOutletStateImplCopyWith<_$SelectedOutletStateImpl> get copyWith =>
__$$SelectedOutletStateImplCopyWithImpl<_$SelectedOutletStateImpl>(
this,
_$identity,
);
}
abstract class _SelectedOutletState implements SelectedOutletState {
const factory _SelectedOutletState({
final Outlet? selectedOutlet,
final String? selectedOutletId,
}) = _$SelectedOutletStateImpl;
/// null berarti "Semua Outlet"
@override
Outlet? get selectedOutlet;
@override
String? get selectedOutletId;
/// Create a copy of SelectedOutletState
/// with the given fields replaced by the non-null parameter values.
@override
@JsonKey(includeFromJson: false, includeToJson: false)
_$$SelectedOutletStateImplCopyWith<_$SelectedOutletStateImpl> get copyWith =>
throw _privateConstructorUsedError;
}
@@ -0,0 +1,13 @@
part of 'selected_outlet_bloc.dart';
@freezed
class SelectedOutletEvent with _$SelectedOutletEvent {
/// Load selected outlet id dari shared preferences
const factory SelectedOutletEvent.loaded() = _Loaded;
/// User memilih outlet tertentu
const factory SelectedOutletEvent.selected(Outlet outlet) = _Selected;
/// Reset ke "Semua Outlet"
const factory SelectedOutletEvent.cleared() = _Cleared;
}
@@ -0,0 +1,18 @@
part of 'selected_outlet_bloc.dart';
@freezed
class SelectedOutletState with _$SelectedOutletState {
const factory SelectedOutletState({
/// null berarti "Semua Outlet"
Outlet? selectedOutlet,
String? selectedOutletId,
}) = _SelectedOutletState;
factory SelectedOutletState.initial() => const SelectedOutletState();
}
extension SelectedOutletStateX on SelectedOutletState {
bool get isAllOutlets => selectedOutletId == null;
String get displayName => selectedOutlet?.name ?? 'Semua Outlet';
}
+1 -1
View File
@@ -1,3 +1,3 @@
class AppConstant { class AppConstant {
static const String appName = "Apskel Owner"; static const String appName = "Enaklo Owner";
} }
@@ -2,4 +2,5 @@ class LocalStorageKey {
static const String lang = 'lang'; static const String lang = 'lang';
static const String token = 'token'; static const String token = 'token';
static const String user = 'user'; static const String user = 'user';
static const String selectedOutletId = 'selected_outlet_id';
} }
+8
View File
@@ -0,0 +1,8 @@
import 'package:firebase_core/firebase_core.dart';
import 'package:injectable/injectable.dart';
@module
abstract class FirebaseDi {
@preResolve
Future<FirebaseApp> get firebaseApp => Firebase.initializeApp();
}
+5
View File
@@ -30,4 +30,9 @@ extension DateTimeIndonesia on DateTime {
String get toHourMinute { String get toHourMinute {
return DateFormat('HH:mm', 'id_ID').format(this); return DateFormat('HH:mm', 'id_ID').format(this);
} }
/// Format jam + detik: 14:30:05
String get toHourMinuteSecond {
return DateFormat('HH:mm:ss', 'id_ID').format(this);
}
} }
+5 -6
View File
@@ -2,9 +2,9 @@ part of 'theme.dart';
class AppColor { class AppColor {
// Primary Colors // Primary Colors
static const Color primary = Color(0xFF36175e); static const Color primary = Color.fromARGB(255, 196, 2, 2); // #d90000
static const Color primaryLight = Color(0xFF5a2d85); static const Color primaryLight = Color(0xFFFF4D4D); // merah terang
static const Color primaryDark = Color(0xFF1e0d35); static const Color primaryDark = Color(0xFF990000); // merah gelap
// Secondary Colors // Secondary Colors
static const Color secondary = Color(0xFF4CAF50); static const Color secondary = Color(0xFF4CAF50);
@@ -41,10 +41,9 @@ class AppColor {
// Gradient Colors // Gradient Colors
static const List<Color> primaryGradient = [ static const List<Color> primaryGradient = [
Color(0xFF36175e), Color(0xFFD90000), // primary
Color(0xFF5a2d85), Color(0xFF990000), // dark red
]; ];
static const List<Color> successGradient = [ static const List<Color> successGradient = [
Color(0xFF4CAF50), Color(0xFF4CAF50),
Color(0xFF81C784), Color(0xFF81C784),
+82
View File
@@ -0,0 +1,82 @@
import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:injectable/injectable.dart';
import 'package:package_info_plus/package_info_plus.dart';
class DeviceInfo {
final String deviceId;
final String deviceName;
final String deviceType;
final String platform;
final String osVersion;
final String appVersion;
const DeviceInfo({
required this.deviceId,
required this.deviceName,
required this.deviceType,
required this.platform,
required this.osVersion,
required this.appVersion,
});
Map<String, dynamic> toJson() => {
'device_id': deviceId,
'device_name': deviceName,
'device_type': deviceType,
'platform': platform,
'os_version': osVersion,
'app_version': appVersion,
};
}
@lazySingleton
class DeviceInfoService {
final DeviceInfoPlugin _deviceInfo = DeviceInfoPlugin();
Future<DeviceInfo> getDeviceInfo() async {
final packageInfo = await PackageInfo.fromPlatform();
final appVersion = packageInfo.version;
if (Platform.isAndroid) {
final info = await _deviceInfo.androidInfo;
return DeviceInfo(
deviceId: info.id,
deviceName: '${info.manufacturer} ${info.model}',
deviceType: _resolveDeviceType(info.model),
platform: 'android',
osVersion: 'Android ${info.version.release}',
appVersion: appVersion,
);
} else if (Platform.isIOS) {
final info = await _deviceInfo.iosInfo;
return DeviceInfo(
deviceId: info.identifierForVendor ?? '',
deviceName: info.name,
deviceType: _resolveDeviceType(info.model),
platform: 'ios',
osVersion: '${info.systemName} ${info.systemVersion}',
appVersion: appVersion,
);
}
// Fallback (web/desktop — tidak dipakai tapi aman)
return DeviceInfo(
deviceId: 'unknown',
deviceName: 'unknown',
deviceType: 'desktop',
platform: 'web',
osVersion: 'unknown',
appVersion: appVersion,
);
}
/// Tentukan device_type berdasarkan model name.
/// Nilai valid: 'mobile' | 'tablet' | 'desktop'
String _resolveDeviceType(String model) {
final lower = model.toLowerCase();
if (lower.contains('ipad') || lower.contains('tablet')) return 'tablet';
return 'mobile';
}
}
+200
View File
@@ -0,0 +1,200 @@
import 'dart:convert';
import 'dart:io';
import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
import 'package:injectable/injectable.dart';
/// Background message handler — must be a top-level function.
/// Firebase must be initialized here for background isolate.
@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(RemoteMessage message) async {
await Firebase.initializeApp();
debugPrint('[FCM] Background message: ${message.messageId}');
// Show local notification for data-only messages in background
await _showBackgroundNotification(message);
}
/// Standalone local notifications plugin for background isolate use.
final _backgroundLocalNotifications = FlutterLocalNotificationsPlugin();
Future<void> _showBackgroundNotification(RemoteMessage message) async {
const androidInit = AndroidInitializationSettings('@drawable/ic_notification');
await _backgroundLocalNotifications.initialize(
const InitializationSettings(android: androidInit),
);
final notification = message.notification;
// Only show manually for data-only messages (FCM auto-shows notification messages)
if (notification != null) return;
final title = message.data['title'] as String?;
final body = message.data['body'] as String?;
if (title == null && body == null) return;
await _backgroundLocalNotifications.show(
message.hashCode,
title,
body,
const NotificationDetails(
android: AndroidNotificationDetails(
'high_importance_channel',
'High Importance Notifications',
importance: Importance.high,
priority: Priority.high,
icon: '@drawable/ic_notification',
),
),
payload: jsonEncode(message.data),
);
}
@lazySingleton
class FcmService {
final FirebaseMessaging _messaging = FirebaseMessaging.instance;
final FlutterLocalNotificationsPlugin _localNotifications =
FlutterLocalNotificationsPlugin();
static const _androidChannel = AndroidNotificationChannel(
'high_importance_channel',
'High Importance Notifications',
description: 'This channel is used for important notifications.',
importance: Importance.max, // max agar banner (heads-up) muncul
playSound: true,
enableVibration: true,
enableLights: true,
);
/// Call this once during app startup (after Firebase.initializeApp).
Future<void> initialize({
void Function(RemoteMessage message)? onMessageTap,
}) async {
// 1. Request permission (iOS + Android 13+)
await _requestPermission();
// 2. Setup local notifications (needed to show heads-up on Android)
await _setupLocalNotifications();
// 3. Register background handler
FirebaseMessaging.onBackgroundMessage(firebaseMessagingBackgroundHandler);
// 4. Foreground message handler
FirebaseMessaging.onMessage.listen((message) {
debugPrint('[FCM] Foreground message: ${message.messageId}');
_showLocalNotification(message);
});
// 5. App opened from notification (background → foreground)
FirebaseMessaging.onMessageOpenedApp.listen((message) {
debugPrint('[FCM] Notification tapped (background): ${message.messageId}');
onMessageTap?.call(message);
});
// 6. App launched from terminated state via notification
final initialMessage = await _messaging.getInitialMessage();
if (initialMessage != null) {
debugPrint('[FCM] App launched from notification: ${initialMessage.messageId}');
onMessageTap?.call(initialMessage);
}
// 7. Print FCM token for debugging
final token = await getToken();
debugPrint('[FCM] Token: $token');
}
Future<void> _requestPermission() async {
final settings = await _messaging.requestPermission(
alert: true,
badge: true,
sound: true,
);
debugPrint('[FCM] Permission status: ${settings.authorizationStatus}');
}
Future<void> _setupLocalNotifications() async {
// Android init
const androidInit = AndroidInitializationSettings('@mipmap/launcher_icon');
// iOS init
const iosInit = DarwinInitializationSettings(
requestAlertPermission: false,
requestBadgePermission: false,
requestSoundPermission: false,
);
const initSettings = InitializationSettings(
android: androidInit,
iOS: iosInit,
);
await _localNotifications.initialize(
initSettings,
onDidReceiveNotificationResponse: (details) {
debugPrint('[FCM] Local notification tapped: ${details.payload}');
},
);
// Create Android notification channel
if (Platform.isAndroid) {
await _localNotifications
.resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>()
?.createNotificationChannel(_androidChannel);
}
// iOS: show notification even when app is in foreground
await _messaging.setForegroundNotificationPresentationOptions(
alert: true,
badge: true,
sound: true,
);
}
void _showLocalNotification(RemoteMessage message) {
final notification = message.notification;
if (notification == null) return;
_localNotifications.show(
notification.hashCode,
notification.title,
notification.body,
NotificationDetails(
android: AndroidNotificationDetails(
_androidChannel.id,
_androidChannel.name,
channelDescription: _androidChannel.description,
icon: '@drawable/ic_notification',
importance: Importance.max,
priority: Priority.high,
playSound: true,
enableVibration: true,
// Heads-up notification (banner)
fullScreenIntent: false,
),
iOS: const DarwinNotificationDetails(
presentAlert: true,
presentBadge: true,
presentSound: true,
),
),
payload: jsonEncode(message.data),
);
}
/// Returns the FCM registration token for this device.
Future<String?> getToken() => _messaging.getToken();
/// Subscribe to a topic (e.g. 'all', 'promo').
Future<void> subscribeToTopic(String topic) =>
_messaging.subscribeToTopic(topic);
/// Unsubscribe from a topic.
Future<void> unsubscribeFromTopic(String topic) =>
_messaging.unsubscribeFromTopic(topic);
/// Listen for token refresh.
Stream<String> get onTokenRefresh => _messaging.onTokenRefresh;
}
@@ -6,35 +6,42 @@ abstract class IAnalyticRepository {
Future<Either<AnalyticFailure, SalesAnalytic>> getSales({ Future<Either<AnalyticFailure, SalesAnalytic>> getSales({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({ Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
Future<Either<AnalyticFailure, CategoryAnalytic>> getCategory({ Future<Either<AnalyticFailure, CategoryAnalytic>> getCategory({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
Future<Either<AnalyticFailure, InventoryAnalytic>> getInventory({ Future<Either<AnalyticFailure, InventoryAnalytic>> getInventory({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
Future<Either<AnalyticFailure, DashboardAnalytic>> getDashboard({ Future<Either<AnalyticFailure, DashboardAnalytic>> getDashboard({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
Future<Either<AnalyticFailure, ProductAnalytic>> getProduct({ Future<Either<AnalyticFailure, ProductAnalytic>> getProduct({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
Future<Either<AnalyticFailure, PaymentMethodAnalytic>> getPaymentMethod({ Future<Either<AnalyticFailure, PaymentMethodAnalytic>> getPaymentMethod({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}); });
} }
@@ -4,6 +4,13 @@ abstract class IAuthRepository {
Future<Either<AuthFailure, Auth>> login({ Future<Either<AuthFailure, Auth>> login({
required String email, required String email,
required String password, required String password,
required String deviceId,
required String deviceName,
required String deviceType,
required String platform,
required String osVersion,
required String appVersion,
String? fcmToken,
}); });
Future<bool> hasToken(); Future<bool> hasToken();
Future<Either<AuthFailure, User>> currentUser(); Future<Either<AuthFailure, User>> currentUser();
@@ -6,6 +6,7 @@ abstract class IOrderRepository {
int limit = 10, int limit = 10,
String? status, String? status,
String? search, String? search,
String? outletId,
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
}); });
@@ -2,4 +2,11 @@ part of '../outlet.dart';
abstract class IOutletRepository { abstract class IOutletRepository {
Future<Either<OutletFailure, Outlet>> currentOutlet(); Future<Either<OutletFailure, Outlet>> currentOutlet();
Future<Either<OutletFailure, List<Outlet>>> getList({
int page = 1,
int limit = 10,
String? search,
bool? isActive,
});
} }
+2 -2
View File
@@ -9,12 +9,12 @@ abstract class Env {
@dev @dev
class DevEnv implements Env { class DevEnv implements Env {
@override @override
String get baseUrl => 'https://enaklo-pos-be.altru.id'; // example value String get baseUrl => 'https://api-pos.apskel.id'; // example value
} }
@Injectable(as: Env) @Injectable(as: Env)
@prod @prod
class ProdEnv implements Env { class ProdEnv implements Env {
@override @override
String get baseUrl => 'https://enaklo-pos-be.altru.id'; String get baseUrl => 'https://api-pos.apskel.id';
} }
@@ -21,14 +21,18 @@ class AnalyticRemoteDataProvider {
Future<DC<AnalyticFailure, SalesAnalyticDto>> fetchSales({ Future<DC<AnalyticFailure, SalesAnalyticDto>> fetchSales({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final response = await _apiClient.get( final Map<String, dynamic> params = {
ApiPath.salesAnalytic,
params: {
'date_from': dateFrom.toServerDate, 'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate, 'date_to': dateTo.toServerDate,
}, };
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.salesAnalytic,
params: params,
headers: getAuthorizationHeader(), headers: getAuthorizationHeader(),
); );
@@ -48,14 +52,18 @@ class AnalyticRemoteDataProvider {
Future<DC<AnalyticFailure, ProfitLossAnalyticDto>> fetchProfitLoss({ Future<DC<AnalyticFailure, ProfitLossAnalyticDto>> fetchProfitLoss({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final response = await _apiClient.get( final Map<String, dynamic> params = {
ApiPath.profitLossAnalytic,
params: {
'date_from': dateFrom.toServerDate, 'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate, 'date_to': dateTo.toServerDate,
}, };
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.profitLossAnalytic,
params: params,
headers: getAuthorizationHeader(), headers: getAuthorizationHeader(),
); );
@@ -75,14 +83,18 @@ class AnalyticRemoteDataProvider {
Future<DC<AnalyticFailure, CategoryAnalyticDto>> fetchCategory({ Future<DC<AnalyticFailure, CategoryAnalyticDto>> fetchCategory({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final response = await _apiClient.get( final Map<String, dynamic> params = {
ApiPath.categoryAnalytic,
params: {
'date_from': dateFrom.toServerDate, 'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate, 'date_to': dateTo.toServerDate,
}, };
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.categoryAnalytic,
params: params,
headers: getAuthorizationHeader(), headers: getAuthorizationHeader(),
); );
@@ -128,17 +140,20 @@ class AnalyticRemoteDataProvider {
} }
Future<DC<AnalyticFailure, DashboardAnalyticDto>> fetchDashboard({ Future<DC<AnalyticFailure, DashboardAnalyticDto>> fetchDashboard({
required String outletId,
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final response = await _apiClient.get( final Map<String, dynamic> params = {
ApiPath.dashboardAnalytic,
params: {
'date_from': dateFrom.toServerDate, 'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate, 'date_to': dateTo.toServerDate,
}, };
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.dashboardAnalytic,
params: params,
headers: getAuthorizationHeader(), headers: getAuthorizationHeader(),
); );
@@ -156,17 +171,20 @@ class AnalyticRemoteDataProvider {
} }
Future<DC<AnalyticFailure, ProductAnalyticDto>> fetchProduct({ Future<DC<AnalyticFailure, ProductAnalyticDto>> fetchProduct({
required String outletId,
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final response = await _apiClient.get( final Map<String, dynamic> params = {
ApiPath.productAnalytic,
params: {
'date_from': dateFrom.toServerDate, 'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate, 'date_to': dateTo.toServerDate,
}, };
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.productAnalytic,
params: params,
headers: getAuthorizationHeader(), headers: getAuthorizationHeader(),
); );
@@ -184,17 +202,20 @@ class AnalyticRemoteDataProvider {
} }
Future<DC<AnalyticFailure, PaymentMethodAnalyticDto>> fetchPaymentMethod({ Future<DC<AnalyticFailure, PaymentMethodAnalyticDto>> fetchPaymentMethod({
required String outletId,
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final response = await _apiClient.get( final Map<String, dynamic> params = {
ApiPath.paymentMethodAnalytic,
params: {
'date_from': dateFrom.toServerDate, 'date_from': dateFrom.toServerDate,
'date_to': dateTo.toServerDate, 'date_to': dateTo.toServerDate,
}, };
if (outletId != null) params['outlet_id'] = outletId;
final response = await _apiClient.get(
ApiPath.paymentMethodAnalytic,
params: params,
headers: getAuthorizationHeader(), headers: getAuthorizationHeader(),
); );
@@ -5,36 +5,43 @@ import 'package:injectable/injectable.dart';
import '../../../domain/analytic/analytic.dart'; import '../../../domain/analytic/analytic.dart';
import '../../../domain/analytic/repositories/i_analytic_repository.dart'; import '../../../domain/analytic/repositories/i_analytic_repository.dart';
import '../../../domain/user/user.dart';
import '../../auth/datasources/local_data_provider.dart'; import '../../auth/datasources/local_data_provider.dart';
import '../../outlet/datasource/local_data_provider.dart';
import '../datasource/remote_data_provider.dart'; import '../datasource/remote_data_provider.dart';
@Injectable(as: IAnalyticRepository) @Injectable(as: IAnalyticRepository)
class AnalyticRepository implements IAnalyticRepository { class AnalyticRepository implements IAnalyticRepository {
final AnalyticRemoteDataProvider _dataProvider; final AnalyticRemoteDataProvider _dataProvider;
final AuthLocalDataProvider _authLocalDataProvider; final AuthLocalDataProvider _authLocalDataProvider;
final OutletLocalDataProvider _outletLocalDataProvider;
final String _logName = 'AnalyticRepository'; final String _logName = 'AnalyticRepository';
AnalyticRepository(this._dataProvider, this._authLocalDataProvider); AnalyticRepository(
this._dataProvider,
this._authLocalDataProvider,
this._outletLocalDataProvider,
);
/// Resolves outlet_id: pakai param jika ada, fallback ke shared pref
String? _resolveOutletId(String? outletId) {
return outletId ?? _outletLocalDataProvider.getSelectedOutletId();
}
@override @override
Future<Either<AnalyticFailure, SalesAnalytic>> getSales({ Future<Either<AnalyticFailure, SalesAnalytic>> getSales({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final result = await _dataProvider.fetchSales( final result = await _dataProvider.fetchSales(
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
outletId: _resolveOutletId(outletId),
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getSalesError', name: _logName, error: e, stackTrace: s); log('getSalesError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -45,20 +52,17 @@ class AnalyticRepository implements IAnalyticRepository {
Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({ Future<Either<AnalyticFailure, ProfitLossAnalytic>> getProfitLoss({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final result = await _dataProvider.fetchProfitLoss( final result = await _dataProvider.fetchProfitLoss(
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
outletId: _resolveOutletId(outletId),
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getProfitLossError', name: _logName, error: e, stackTrace: s); log('getProfitLossError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -69,20 +73,17 @@ class AnalyticRepository implements IAnalyticRepository {
Future<Either<AnalyticFailure, CategoryAnalytic>> getCategory({ Future<Either<AnalyticFailure, CategoryAnalytic>> getCategory({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
final result = await _dataProvider.fetchCategory( final result = await _dataProvider.fetchCategory(
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
outletId: _resolveOutletId(outletId),
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getCategoryError', name: _logName, error: e, stackTrace: s); log('getCategoryError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -93,23 +94,20 @@ class AnalyticRepository implements IAnalyticRepository {
Future<Either<AnalyticFailure, InventoryAnalytic>> getInventory({ Future<Either<AnalyticFailure, InventoryAnalytic>> getInventory({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
User currentUser = await _authLocalDataProvider.currentUser(); final currentUser = await _authLocalDataProvider.currentUser();
final resolvedId = _resolveOutletId(outletId) ?? currentUser.outletId;
final result = await _dataProvider.fetchInventory( final result = await _dataProvider.fetchInventory(
outletId: currentUser.outletId, outletId: resolvedId,
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getInventoryError', name: _logName, error: e, stackTrace: s); log('getInventoryError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -120,23 +118,17 @@ class AnalyticRepository implements IAnalyticRepository {
Future<Either<AnalyticFailure, DashboardAnalytic>> getDashboard({ Future<Either<AnalyticFailure, DashboardAnalytic>> getDashboard({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
User currentUser = await _authLocalDataProvider.currentUser();
final result = await _dataProvider.fetchDashboard( final result = await _dataProvider.fetchDashboard(
outletId: currentUser.outletId,
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
outletId: _resolveOutletId(outletId),
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getDashboardError', name: _logName, error: e, stackTrace: s); log('getDashboardError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -147,23 +139,17 @@ class AnalyticRepository implements IAnalyticRepository {
Future<Either<AnalyticFailure, ProductAnalytic>> getProduct({ Future<Either<AnalyticFailure, ProductAnalytic>> getProduct({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
User currentUser = await _authLocalDataProvider.currentUser();
final result = await _dataProvider.fetchProduct( final result = await _dataProvider.fetchProduct(
outletId: currentUser.outletId,
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
outletId: _resolveOutletId(outletId),
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getProductError', name: _logName, error: e, stackTrace: s); log('getProductError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -174,23 +160,17 @@ class AnalyticRepository implements IAnalyticRepository {
Future<Either<AnalyticFailure, PaymentMethodAnalytic>> getPaymentMethod({ Future<Either<AnalyticFailure, PaymentMethodAnalytic>> getPaymentMethod({
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
String? outletId,
}) async { }) async {
try { try {
User currentUser = await _authLocalDataProvider.currentUser();
final result = await _dataProvider.fetchPaymentMethod( final result = await _dataProvider.fetchPaymentMethod(
outletId: currentUser.outletId,
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
outletId: _resolveOutletId(outletId),
); );
if (result.hasError) { if (result.hasError) return left(result.error!);
return left(result.error!); return right(result.data!.toDomain());
}
final auth = result.data!.toDomain();
return right(auth);
} catch (e, s) { } catch (e, s) {
log('getPaymentMethodError', name: _logName, error: e, stackTrace: s); log('getPaymentMethodError', name: _logName, error: e, stackTrace: s);
return left(const AnalyticFailure.unexpectedError()); return left(const AnalyticFailure.unexpectedError());
@@ -21,11 +21,28 @@ class AuthRemoteDataProvider {
Future<DC<AuthFailure, AuthDto>> login({ Future<DC<AuthFailure, AuthDto>> login({
required String email, required String email,
required String password, required String password,
required String deviceId,
required String deviceName,
required String deviceType,
required String platform,
required String osVersion,
required String appVersion,
String? fcmToken,
}) async { }) async {
try { try {
final response = await _apiClient.post( final response = await _apiClient.post(
ApiPath.login, ApiPath.login,
data: {'email': email, 'password': password}, data: {
'email': email,
'password': password,
'device_id': deviceId,
'device_name': deviceName,
'device_type': deviceType,
'platform': platform,
'os_version': osVersion,
'app_version': appVersion,
if (fcmToken != null) 'fcm_token': fcmToken,
},
); );
if (response.data['code'] == 401) { if (response.data['code'] == 401) {
@@ -21,11 +21,25 @@ class AuthRepository implements IAuthRepository {
Future<Either<AuthFailure, Auth>> login({ Future<Either<AuthFailure, Auth>> login({
required String email, required String email,
required String password, required String password,
required String deviceId,
required String deviceName,
required String deviceType,
required String platform,
required String osVersion,
required String appVersion,
String? fcmToken,
}) async { }) async {
try { try {
final result = await _remoteDataProvider.login( final result = await _remoteDataProvider.login(
email: email, email: email,
password: password, password: password,
deviceId: deviceId,
deviceName: deviceName,
deviceType: deviceType,
platform: platform,
osVersion: osVersion,
appVersion: appVersion,
fcmToken: fcmToken,
); );
if (result.hasError) { if (result.hasError) {
@@ -23,6 +23,7 @@ class OrderRemoteDataProvider {
int limit = 10, int limit = 10,
String? status, String? status,
String? search, String? search,
String? outletId,
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
}) async { }) async {
@@ -42,6 +43,10 @@ class OrderRemoteDataProvider {
params['search'] = search; params['search'] = search;
} }
// if (outletId != null) {
// params['outlet_id'] = outletId;
// }
final response = await _apiClient.get( final response = await _apiClient.get(
ApiPath.order, ApiPath.order,
params: params, params: params,
@@ -4,14 +4,16 @@ import 'package:dartz/dartz.dart' hide Order;
import 'package:injectable/injectable.dart' hide Order; import 'package:injectable/injectable.dart' hide Order;
import '../../../domain/order/order.dart'; import '../../../domain/order/order.dart';
import '../../outlet/datasource/local_data_provider.dart';
import '../datasource/remote_data_provider.dart'; import '../datasource/remote_data_provider.dart';
@Injectable(as: IOrderRepository) @Injectable(as: IOrderRepository)
class OrderRepository implements IOrderRepository { class OrderRepository implements IOrderRepository {
final OrderRemoteDataProvider _dataProvider; final OrderRemoteDataProvider _dataProvider;
final OutletLocalDataProvider _outletLocalDataProvider;
final String _logName = 'OrderRepository'; final String _logName = 'OrderRepository';
OrderRepository(this._dataProvider); OrderRepository(this._dataProvider, this._outletLocalDataProvider);
@override @override
Future<Either<OrderFailure, List<Order>>> get({ Future<Either<OrderFailure, List<Order>>> get({
@@ -19,15 +21,20 @@ class OrderRepository implements IOrderRepository {
int limit = 20, int limit = 20,
String? status, String? status,
String? search, String? search,
String? outletId,
required DateTime dateFrom, required DateTime dateFrom,
required DateTime dateTo, required DateTime dateTo,
}) async { }) async {
try { try {
final resolvedOutletId =
outletId ?? _outletLocalDataProvider.getSelectedOutletId();
final result = await _dataProvider.fetch( final result = await _dataProvider.fetch(
page: page, page: page,
limit: limit, limit: limit,
status: status, status: status,
search: search, search: search,
outletId: resolvedOutletId,
dateFrom: dateFrom, dateFrom: dateFrom,
dateTo: dateTo, dateTo: dateTo,
); );
@@ -36,9 +43,9 @@ class OrderRepository implements IOrderRepository {
return left(result.error!); return left(result.error!);
} }
final auth = result.data!.map((e) => e.toDomain()).toList(); final orders = result.data!.map((e) => e.toDomain()).toList();
return right(auth); return right(orders);
} catch (e, s) { } catch (e, s) {
log('getOrderError', name: _logName, error: e, stackTrace: s); log('getOrderError', name: _logName, error: e, stackTrace: s);
return left(const OrderFailure.unexpectedError()); return left(const OrderFailure.unexpectedError());
@@ -0,0 +1,26 @@
import 'package:injectable/injectable.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../../../common/constant/local_storage_key.dart';
@injectable
class OutletLocalDataProvider {
final SharedPreferences _sharedPreferences;
OutletLocalDataProvider(this._sharedPreferences);
Future<void> saveSelectedOutletId(String outletId) async {
await _sharedPreferences.setString(
LocalStorageKey.selectedOutletId,
outletId,
);
}
String? getSelectedOutletId() {
return _sharedPreferences.getString(LocalStorageKey.selectedOutletId);
}
Future<void> deleteSelectedOutletId() async {
await _sharedPreferences.remove(LocalStorageKey.selectedOutletId);
}
}
@@ -36,4 +36,39 @@ class OutletRemoteDataProvider {
return DC.error(OutletFailure.serverError(e)); return DC.error(OutletFailure.serverError(e));
} }
} }
Future<DC<OutletFailure, List<OutletDto>>> fetchList({
int page = 1,
int limit = 10,
String? search,
bool? isActive,
}) async {
try {
final Map<String, dynamic> params = {
'page': page,
'limit': limit,
'search': search ?? 'null',
'is_active': isActive != null ? isActive.toString() : 'null',
};
final response = await _apiClient.get(
'${ApiPath.outlet}/list',
params: params,
headers: getAuthorizationHeader(),
);
if (response.data['data'] == null) {
return DC.error(OutletFailure.empty());
}
final dto = (response.data['data']['outlets'] as List)
.map((item) => OutletDto.fromJson(item))
.toList();
return DC.data(dto);
} on ApiFailure catch (e, s) {
log('fetchOutletListError', name: _logName, error: e, stackTrace: s);
return DC.error(OutletFailure.serverError(e));
}
}
} }
@@ -33,4 +33,32 @@ class OutletRepository implements IOutletRepository {
return left(const OutletFailure.unexpectedError()); return left(const OutletFailure.unexpectedError());
} }
} }
@override
Future<Either<OutletFailure, List<Outlet>>> getList({
int page = 1,
int limit = 10,
String? search,
bool? isActive,
}) async {
try {
final result = await _dataProvider.fetchList(
page: page,
limit: limit,
search: search,
isActive: isActive,
);
if (result.hasError) {
return left(result.error!);
}
final outlets = result.data!.map((e) => e.toDomain()).toList();
return right(outlets);
} catch (e, s) {
log('getOutletListError', name: _logName, error: e, stackTrace: s);
return left(const OutletFailure.unexpectedError());
}
}
} }
+85 -48
View File
@@ -39,6 +39,10 @@ import 'package:apskel_owner_flutter/application/order/order_loader/order_loader
as _i1058; as _i1058;
import 'package:apskel_owner_flutter/application/outlet/current_outlet_loader/current_outlet_loader_bloc.dart' import 'package:apskel_owner_flutter/application/outlet/current_outlet_loader/current_outlet_loader_bloc.dart'
as _i337; as _i337;
import 'package:apskel_owner_flutter/application/outlet/outlet_list_loader/outlet_list_loader_bloc.dart'
as _i877;
import 'package:apskel_owner_flutter/application/outlet/selected_outlet/selected_outlet_bloc.dart'
as _i678;
import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart' import 'package:apskel_owner_flutter/application/product/product_loader/product_loader_bloc.dart'
as _i458; as _i458;
import 'package:apskel_owner_flutter/application/report/inventory_report/inventory_report_bloc.dart' import 'package:apskel_owner_flutter/application/report/inventory_report/inventory_report_bloc.dart'
@@ -53,11 +57,15 @@ import 'package:apskel_owner_flutter/common/api/api_client.dart' as _i115;
import 'package:apskel_owner_flutter/common/di/di_auto_route.dart' as _i311; import 'package:apskel_owner_flutter/common/di/di_auto_route.dart' as _i311;
import 'package:apskel_owner_flutter/common/di/di_connectivity.dart' as _i586; import 'package:apskel_owner_flutter/common/di/di_connectivity.dart' as _i586;
import 'package:apskel_owner_flutter/common/di/di_dio.dart' as _i103; import 'package:apskel_owner_flutter/common/di/di_dio.dart' as _i103;
import 'package:apskel_owner_flutter/common/di/di_firebase.dart' as _i73;
import 'package:apskel_owner_flutter/common/di/di_package_info.dart' as _i227; import 'package:apskel_owner_flutter/common/di/di_package_info.dart' as _i227;
import 'package:apskel_owner_flutter/common/di/di_shared_preferences.dart' import 'package:apskel_owner_flutter/common/di/di_shared_preferences.dart'
as _i402; as _i402;
import 'package:apskel_owner_flutter/common/network/network_client.dart' import 'package:apskel_owner_flutter/common/network/network_client.dart'
as _i543; as _i543;
import 'package:apskel_owner_flutter/common/utils/device_info_service.dart'
as _i902;
import 'package:apskel_owner_flutter/common/utils/fcm_service.dart' as _i179;
import 'package:apskel_owner_flutter/domain/analytic/repositories/i_analytic_repository.dart' import 'package:apskel_owner_flutter/domain/analytic/repositories/i_analytic_repository.dart'
as _i477; as _i477;
import 'package:apskel_owner_flutter/domain/auth/auth.dart' as _i49; import 'package:apskel_owner_flutter/domain/auth/auth.dart' as _i49;
@@ -90,6 +98,8 @@ import 'package:apskel_owner_flutter/infrastructure/order/datasource/remote_data
as _i130; as _i130;
import 'package:apskel_owner_flutter/infrastructure/order/repositories/order_repository.dart' import 'package:apskel_owner_flutter/infrastructure/order/repositories/order_repository.dart'
as _i641; as _i641;
import 'package:apskel_owner_flutter/infrastructure/outlet/datasource/local_data_provider.dart'
as _i850;
import 'package:apskel_owner_flutter/infrastructure/outlet/datasource/remote_data_provider.dart' import 'package:apskel_owner_flutter/infrastructure/outlet/datasource/remote_data_provider.dart'
as _i27; as _i27;
import 'package:apskel_owner_flutter/infrastructure/outlet/repositories/outlet_repository.dart' import 'package:apskel_owner_flutter/infrastructure/outlet/repositories/outlet_repository.dart'
@@ -106,6 +116,7 @@ import 'package:apskel_owner_flutter/presentation/router/app_router.dart'
as _i258; as _i258;
import 'package:connectivity_plus/connectivity_plus.dart' as _i895; import 'package:connectivity_plus/connectivity_plus.dart' as _i895;
import 'package:dio/dio.dart' as _i361; import 'package:dio/dio.dart' as _i361;
import 'package:firebase_core/firebase_core.dart' as _i982;
import 'package:get_it/get_it.dart' as _i174; import 'package:get_it/get_it.dart' as _i174;
import 'package:injectable/injectable.dart' as _i526; import 'package:injectable/injectable.dart' as _i526;
import 'package:package_info_plus/package_info_plus.dart' as _i655; import 'package:package_info_plus/package_info_plus.dart' as _i655;
@@ -121,22 +132,29 @@ extension GetItInjectableX on _i174.GetIt {
_i526.EnvironmentFilter? environmentFilter, _i526.EnvironmentFilter? environmentFilter,
}) async { }) async {
final gh = _i526.GetItHelper(this, environment, environmentFilter); final gh = _i526.GetItHelper(this, environment, environmentFilter);
final firebaseDi = _$FirebaseDi();
final sharedPreferencesDi = _$SharedPreferencesDi(); final sharedPreferencesDi = _$SharedPreferencesDi();
final dioDi = _$DioDi();
final autoRouteDi = _$AutoRouteDi(); final autoRouteDi = _$AutoRouteDi();
final connectivityDi = _$ConnectivityDi(); final connectivityDi = _$ConnectivityDi();
final dioDi = _$DioDi();
final packageInfoDi = _$PackageInfoDi(); final packageInfoDi = _$PackageInfoDi();
await gh.factoryAsync<_i982.FirebaseApp>(
() => firebaseDi.firebaseApp,
preResolve: true,
);
await gh.factoryAsync<_i460.SharedPreferences>( await gh.factoryAsync<_i460.SharedPreferences>(
() => sharedPreferencesDi.prefs, () => sharedPreferencesDi.prefs,
preResolve: true, preResolve: true,
); );
gh.lazySingleton<_i361.Dio>(() => dioDi.dio);
gh.lazySingleton<_i258.AppRouter>(() => autoRouteDi.appRouter); gh.lazySingleton<_i258.AppRouter>(() => autoRouteDi.appRouter);
gh.lazySingleton<_i895.Connectivity>(() => connectivityDi.connectivity); gh.lazySingleton<_i895.Connectivity>(() => connectivityDi.connectivity);
gh.lazySingleton<_i361.Dio>(() => dioDi.dio);
await gh.lazySingletonAsync<_i655.PackageInfo>( await gh.lazySingletonAsync<_i655.PackageInfo>(
() => packageInfoDi.packageInfo, () => packageInfoDi.packageInfo,
preResolve: true, preResolve: true,
); );
gh.lazySingleton<_i902.DeviceInfoService>(() => _i902.DeviceInfoService());
gh.lazySingleton<_i179.FcmService>(() => _i179.FcmService());
gh.lazySingleton<_i543.NetworkClient>( gh.lazySingleton<_i543.NetworkClient>(
() => _i543.NetworkClient(gh<_i895.Connectivity>()), () => _i543.NetworkClient(gh<_i895.Connectivity>()),
); );
@@ -147,46 +165,49 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i991.AuthLocalDataProvider>( gh.factory<_i991.AuthLocalDataProvider>(
() => _i991.AuthLocalDataProvider(gh<_i460.SharedPreferences>()), () => _i991.AuthLocalDataProvider(gh<_i460.SharedPreferences>()),
); );
gh.factory<_i850.OutletLocalDataProvider>(
() => _i850.OutletLocalDataProvider(gh<_i460.SharedPreferences>()),
);
gh.lazySingleton<_i115.ApiClient>( gh.lazySingleton<_i115.ApiClient>(
() => _i115.ApiClient(gh<_i361.Dio>(), gh<_i6.Env>()), () => _i115.ApiClient(gh<_i361.Dio>(), gh<_i6.Env>()),
); );
gh.factory<_i6.Env>(() => _i6.ProdEnv(), registerFor: {_prod}); gh.factory<_i6.Env>(() => _i6.ProdEnv(), registerFor: {_prod});
gh.factory<_i130.OrderRemoteDataProvider>( gh.factory<_i866.AnalyticRemoteDataProvider>(
() => _i130.OrderRemoteDataProvider(gh<_i115.ApiClient>()), () => _i866.AnalyticRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i333.CategoryRemoteDataProvider>(
() => _i333.CategoryRemoteDataProvider(gh<_i115.ApiClient>()),
); );
gh.factory<_i17.AuthRemoteDataProvider>( gh.factory<_i17.AuthRemoteDataProvider>(
() => _i17.AuthRemoteDataProvider(gh<_i115.ApiClient>()), () => _i17.AuthRemoteDataProvider(gh<_i115.ApiClient>()),
); );
gh.factory<_i785.UserRemoteDataProvider>( gh.factory<_i333.CategoryRemoteDataProvider>(
() => _i785.UserRemoteDataProvider(gh<_i115.ApiClient>()), () => _i333.CategoryRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i823.ProductRemoteDataProvider>(
() => _i823.ProductRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i27.OutletRemoteDataProvider>(
() => _i27.OutletRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i866.AnalyticRemoteDataProvider>(
() => _i866.AnalyticRemoteDataProvider(gh<_i115.ApiClient>()),
); );
gh.factory<_i1006.CustomerRemoteDataProvider>( gh.factory<_i1006.CustomerRemoteDataProvider>(
() => _i1006.CustomerRemoteDataProvider(gh<_i115.ApiClient>()), () => _i1006.CustomerRemoteDataProvider(gh<_i115.ApiClient>()),
); );
gh.factory<_i130.OrderRemoteDataProvider>(
() => _i130.OrderRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i27.OutletRemoteDataProvider>(
() => _i27.OutletRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i823.ProductRemoteDataProvider>(
() => _i823.ProductRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i785.UserRemoteDataProvider>(
() => _i785.UserRemoteDataProvider(gh<_i115.ApiClient>()),
);
gh.factory<_i48.ICustomerRepository>( gh.factory<_i48.ICustomerRepository>(
() => _i550.CustomerRepository(gh<_i1006.CustomerRemoteDataProvider>()), () => _i550.CustomerRepository(gh<_i1006.CustomerRemoteDataProvider>()),
); );
gh.factory<_i219.IOrderRepository>(
() => _i641.OrderRepository(gh<_i130.OrderRemoteDataProvider>()),
);
gh.factory<_i49.IAuthRepository>( gh.factory<_i49.IAuthRepository>(
() => _i1035.AuthRepository( () => _i1035.AuthRepository(
gh<_i991.AuthLocalDataProvider>(), gh<_i991.AuthLocalDataProvider>(),
gh<_i17.AuthRemoteDataProvider>(), gh<_i17.AuthRemoteDataProvider>(),
), ),
); );
gh.factory<_i678.SelectedOutletBloc>(
() => _i678.SelectedOutletBloc(gh<_i850.OutletLocalDataProvider>()),
);
gh.factory<_i635.IUserRepository>( gh.factory<_i635.IUserRepository>(
() => _i754.UserRepository( () => _i754.UserRepository(
gh<_i785.UserRemoteDataProvider>(), gh<_i785.UserRemoteDataProvider>(),
@@ -196,15 +217,15 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i419.IProductRepository>( gh.factory<_i419.IProductRepository>(
() => _i121.ProductRepository(gh<_i823.ProductRemoteDataProvider>()), () => _i121.ProductRepository(gh<_i823.ProductRemoteDataProvider>()),
); );
gh.factory<_i219.IOrderRepository>(
() => _i641.OrderRepository(
gh<_i130.OrderRemoteDataProvider>(),
gh<_i850.OutletLocalDataProvider>(),
),
);
gh.factory<_i972.CustomerLoaderBloc>( gh.factory<_i972.CustomerLoaderBloc>(
() => _i972.CustomerLoaderBloc(gh<_i48.ICustomerRepository>()), () => _i972.CustomerLoaderBloc(gh<_i48.ICustomerRepository>()),
); );
gh.factory<_i477.IAnalyticRepository>(
() => _i393.AnalyticRepository(
gh<_i866.AnalyticRemoteDataProvider>(),
gh<_i991.AuthLocalDataProvider>(),
),
);
gh.factory<_i1020.ICategoryRepository>( gh.factory<_i1020.ICategoryRepository>(
() => _i869.CategoryRepository(gh<_i333.CategoryRemoteDataProvider>()), () => _i869.CategoryRepository(gh<_i333.CategoryRemoteDataProvider>()),
); );
@@ -220,17 +241,30 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i183.CategoryLoaderBloc>( gh.factory<_i183.CategoryLoaderBloc>(
() => _i183.CategoryLoaderBloc(gh<_i1020.ICategoryRepository>()), () => _i183.CategoryLoaderBloc(gh<_i1020.ICategoryRepository>()),
); );
gh.factory<_i473.HomeBloc>( gh.factory<_i477.IAnalyticRepository>(
() => _i473.HomeBloc(gh<_i477.IAnalyticRepository>()), () => _i393.AnalyticRepository(
gh<_i866.AnalyticRemoteDataProvider>(),
gh<_i991.AuthLocalDataProvider>(),
gh<_i850.OutletLocalDataProvider>(),
),
); );
gh.factory<_i889.SalesLoaderBloc>( gh.factory<_i889.SalesLoaderBloc>(
() => _i889.SalesLoaderBloc(gh<_i477.IAnalyticRepository>()), () => _i889.SalesLoaderBloc(gh<_i477.IAnalyticRepository>()),
); );
gh.factory<_i473.HomeBloc>(
() => _i473.HomeBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i877.OutletListLoaderBloc>(
() => _i877.OutletListLoaderBloc(gh<_i197.IOutletRepository>()),
);
gh.factory<_i337.CurrentOutletLoaderBloc>( gh.factory<_i337.CurrentOutletLoaderBloc>(
() => _i337.CurrentOutletLoaderBloc(gh<_i197.IOutletRepository>()), () => _i337.CurrentOutletLoaderBloc(gh<_i197.IOutletRepository>()),
); );
gh.factory<_i221.ProductAnalyticLoaderBloc>( gh.factory<_i1038.CategoryAnalyticLoaderBloc>(
() => _i221.ProductAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), () => _i1038.CategoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i516.DashboardAnalyticLoaderBloc>(
() => _i516.DashboardAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
); );
gh.factory<_i785.InventoryAnalyticLoaderBloc>( gh.factory<_i785.InventoryAnalyticLoaderBloc>(
() => _i785.InventoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), () => _i785.InventoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
@@ -240,18 +274,12 @@ extension GetItInjectableX on _i174.GetIt {
gh<_i477.IAnalyticRepository>(), gh<_i477.IAnalyticRepository>(),
), ),
); );
gh.factory<_i1038.CategoryAnalyticLoaderBloc>( gh.factory<_i221.ProductAnalyticLoaderBloc>(
() => _i1038.CategoryAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()), () => _i221.ProductAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
); );
gh.factory<_i11.ProfitLossLoaderBloc>( gh.factory<_i11.ProfitLossLoaderBloc>(
() => _i11.ProfitLossLoaderBloc(gh<_i477.IAnalyticRepository>()), () => _i11.ProfitLossLoaderBloc(gh<_i477.IAnalyticRepository>()),
); );
gh.factory<_i516.DashboardAnalyticLoaderBloc>(
() => _i516.DashboardAnalyticLoaderBloc(gh<_i477.IAnalyticRepository>()),
);
gh.factory<_i775.LoginFormBloc>(
() => _i775.LoginFormBloc(gh<_i49.IAuthRepository>()),
);
gh.factory<_i945.AuthBloc>( gh.factory<_i945.AuthBloc>(
() => _i945.AuthBloc(gh<_i49.IAuthRepository>()), () => _i945.AuthBloc(gh<_i49.IAuthRepository>()),
); );
@@ -261,16 +289,17 @@ extension GetItInjectableX on _i174.GetIt {
gh.factory<_i1058.OrderLoaderBloc>( gh.factory<_i1058.OrderLoaderBloc>(
() => _i1058.OrderLoaderBloc(gh<_i219.IOrderRepository>()), () => _i1058.OrderLoaderBloc(gh<_i219.IOrderRepository>()),
); );
gh.factory<_i147.UserEditFormBloc>(
() => _i147.UserEditFormBloc(gh<_i635.IUserRepository>()),
);
gh.factory<_i1030.ChangePasswordFormBloc>( gh.factory<_i1030.ChangePasswordFormBloc>(
() => _i1030.ChangePasswordFormBloc(gh<_i635.IUserRepository>()), () => _i1030.ChangePasswordFormBloc(gh<_i635.IUserRepository>()),
); );
gh.factory<_i605.TransactionReportBloc>( gh.factory<_i147.UserEditFormBloc>(
() => _i605.TransactionReportBloc( () => _i147.UserEditFormBloc(gh<_i635.IUserRepository>()),
gh<_i477.IAnalyticRepository>(), );
gh<_i197.IOutletRepository>(), gh.factory<_i775.LoginFormBloc>(
() => _i775.LoginFormBloc(
gh<_i49.IAuthRepository>(),
gh<_i902.DeviceInfoService>(),
gh<_i179.FcmService>(),
), ),
); );
gh.factory<_i346.InventoryReportBloc>( gh.factory<_i346.InventoryReportBloc>(
@@ -279,16 +308,24 @@ extension GetItInjectableX on _i174.GetIt {
gh<_i197.IOutletRepository>(), gh<_i197.IOutletRepository>(),
), ),
); );
gh.factory<_i605.TransactionReportBloc>(
() => _i605.TransactionReportBloc(
gh<_i477.IAnalyticRepository>(),
gh<_i197.IOutletRepository>(),
),
);
return this; return this;
} }
} }
class _$SharedPreferencesDi extends _i402.SharedPreferencesDi {} class _$FirebaseDi extends _i73.FirebaseDi {}
class _$DioDi extends _i103.DioDi {} class _$SharedPreferencesDi extends _i402.SharedPreferencesDi {}
class _$AutoRouteDi extends _i311.AutoRouteDi {} class _$AutoRouteDi extends _i311.AutoRouteDi {}
class _$ConnectivityDi extends _i586.ConnectivityDi {} class _$ConnectivityDi extends _i586.ConnectivityDi {}
class _$DioDi extends _i103.DioDi {}
class _$PackageInfoDi extends _i227.PackageInfoDi {} class _$PackageInfoDi extends _i227.PackageInfoDi {}
+383 -1
View File
@@ -49,5 +49,387 @@
"profile": "Profile", "profile": "Profile",
"@profile": {}, "@profile": {},
"sales_today": "Sales today", "sales_today": "Sales today",
"@sales_today": {} "@sales_today": {},
"order": "Order",
"@order": {},
"sales": "Sales",
"@sales": {},
"finance": "Finance",
"@finance": {},
"product": "Product",
"@product": {},
"form": "Form",
"@form": {},
"schedule": "Schedule",
"@schedule": {},
"inventory": "Inventory",
"@inventory": {},
"customer": "Customer",
"@customer": {},
"purchase": "Purchase",
"@purchase": {},
"today_summary": "Today's Summary",
"@today_summary": {},
"today": "Today",
"@today": {},
"new_customer": "New Customer",
"@new_customer": {},
"refund": "Refund",
"@refund": {},
"void_text": "Void",
"@void_text": {},
"increase": "Increase",
"@increase": {},
"today_top_product": "Today's Top Product",
"@today_top_product": {},
"rank": "Rank",
"@rank": {},
"quantity_sold": "Quantity Sold",
"@quantity_sold": {},
"total_orders": "Total Orders",
"@total_orders": {},
"average_price": "Average Price",
"@average_price": {},
"perfomance": "Performance",
"@perfomance": {},
"total_sales": "Total Sales",
"@total_sales": {},
"total_items": "Total Items",
"@total_items": {},
"summary": "Summary",
"@summary": {},
"net_sales": "Net Sales",
"@net_sales": {},
"daily_breakdown": "Daily Breakdown",
"@daily_breakdown": {},
"orders": "Orders",
"@orders": {},
"items": "Items",
"@items": {},
"tax": "Tax",
"@tax": {},
"discount": "Discount",
"@discount": {},
"total_purchase": "Total Purchase",
"@total_purchase": {},
"pending_order": "Pending Order",
"@pending_order": {},
"history_purchase": "History Purchase",
"@history_purchase": {},
"all": "All",
"@all": {},
"select_date_range": "Select Date Range",
"@select_date_range": {},
"no_date_selected": "No date has been selected yet",
"@no_date_selected": {},
"selected_date": "Selected Date",
"@selected_date": {},
"select": "Select",
"@select": {},
"cancel": "Cancel",
"@cancel": {},
"total_revenue": "Total Revenue",
"@total_revenue": {},
"total_expenditures": "Total Expenditures",
"@total_expenditures": {},
"net_profit": "Net Profit",
"@net_profit": {},
"margin_profit": "Margin Profit",
"@margin_profit": {},
"cash_flow_analysis": "Cash Flow Analysis",
"@cash_flow_analysis": {},
"cash_in": "Cash In",
"@cash_in": {},
"cash_out": "Cash Out",
"@cash_out": {},
"net_flow": "Net Flow",
"@net_flow": {},
"cash_flow_chart": "Cash Flow Chart for {days} Last Days",
"@cash_flow_chart": {
"placeholders": {
"days": {
"type": "int",
"example": "7"
}
}
},
"profit_loss_detail": "Profit & Loss Details",
"@profit_loss_detail": {},
"gross_sales": "Gross Sales",
"@gross_sales": {},
"return_text": "Return",
"@return_text": {},
"cogs": "COGS",
"@cogs": {},
"cost_of_goods_sold": "Cost of goods sold",
"@cost_of_goods_sold": {},
"gross_profit": "Gross Profit",
"@gross_profit": {},
"operating_costs": "Operating Costs",
"@operating_costs": {},
"sales_category": "Sales Category",
"@sales_category": {},
"unit": "Unit",
"@unit": {},
"category_no_data": "There are no data categories yet",
"@category_no_data": {},
"category_no_data_desc": "Sales category data will appear here",
"@category_no_data_desc": {},
"product_analytic": "Product Analytic",
"@product_analytic": {},
"view_all": "View All",
"@view_all": {},
"sold": "Sold",
"@sold": {},
"revenue": "Revenue",
"@revenue": {},
"cost": "Cost",
"@cost": {},
"profit_per_unit": "Profit per unit",
"@profit_per_unit": {},
"total_sold": "Total Sold",
"@total_sold": {},
"ingredients": "Ingredients",
"@ingredients": {},
"low_stock": "Low Stock",
"@low_stock": {},
"zero_stock": "Zero Stock",
"@zero_stock": {},
"stock": "Stock",
"@stock": {},
"price": "Price",
"@price": {},
"out_of_stock": "Out of stock",
"@out_of_stock": {},
"out_of_stock_desc": "Product not available for sale",
"@out_of_stock_desc": {},
"in_text": "In",
"@in_text": {},
"out_text": "Out",
"@out_text": {},
"available": "Available",
"@available": {},
"total_products": "Total Products",
"@total_products": {},
"total_ingredients": "Total Ingredients",
"@total_ingredients": {},
"products": "Products",
"@products": {},
"value_text": "Value",
"@value_text": {},
"low_stock_desc": "Immediately reorder at least {stock} pcs",
"@low_stock_desc": {
"placeholders": {
"stock": {
"type": "String",
"example": "0"
}
}
},
"joined": "Joined",
"@joined": {},
"ago": "ago",
"@ago": {},
"active": "Active",
"@active": {},
"inactive": "Inactive",
"@inactive": {},
"total_amount": "Total Amount",
"@total_amount": {},
"table": "Table",
"@table": {},
"remaining": "Remaining",
"@remaining": {},
"payment": "Payment",
"@payment": {},
"completed": "Completed",
"@completed": {},
"pending": "Pending",
"@pending": {},
"no_order_with_status": "No {status} orders found",
"@no_order_with_status": {
"placeholders": {
"status": {
"type": "String",
"example": "pending"
}
}
},
"order_details": "Order Details",
"@order_details": {},
"order_number": "Order Number",
"@order_number": {},
"order_status": "Order Status",
"@order_status": {},
"order_information": "Order Information",
"@order_information": {},
"order_type": "Order Type",
"@order_type": {},
"payment_status": "Payment Status",
"@payment_status": {},
"created": "Created",
"@created": {},
"order_item": "Order Item",
"@order_item": {},
"item": "Item",
"@item": {},
"each": "Each",
"@each": {},
"total_item": "Total Item",
"@total_item": {},
"payment_summary": "Payment Summary",
"@payment_summary": {},
"subtotal": "Subtotal",
"@subtotal": {},
"paid": "Paid",
"@paid": {},
"total": "Total",
"@total": {},
"payment_method": "Payment Method",
"@payment_method": {},
"dine_in": "Dine In",
"@dine_in": {},
"dine_in_experience": "Dine In Experience",
"@dine_in_experience": {},
"note": "Note",
"@note": {},
"sales_chart": "Sales Chart",
"@sales_chart": {},
"no_data_available": "No Data Avaiable",
"@no_data_available": {},
"total_days_overview": "{days} days overview",
"@total_days_overview": {
"placeholders": {
"days": {
"type": "int",
"example": "0"
}
}
},
"sales_data": "Sales Data",
"@sales_data": {},
"no_sales_data": "No Sales Data",
"@no_sales_data": {},
"no_sales_data_desc": "Sales data will appear here once transactions are recorded",
"@no_sales_data_desc": {},
"payment_methods": "Payment Methods",
"@payment_methods": {},
"payment_methods_desc": "Revenue breakdown by payment method ",
"@payment_methods_desc": {},
"revenue_share": "Revenue Share",
"@revenue_share": {},
"no_payment_methods": "No Payment Methods",
"@no_payment_methods": {},
"no_payment_methods_desc": "Payment method data will appear here once transactions are made",
"@no_payment_methods_desc": {},
"best_selling_products": "Best Selling Products",
"@best_selling_products": {},
"highest_sales_ranking": "Highest sales ranking",
"@highest_sales_ranking": {},
"best_seller": "Best Seller",
"@best_seller": {},
"top_performer": "Top Performer",
"@top_performer": {},
"account_information": "Account Information",
"@account_information": {},
"member_since": "Member Since",
"@member_since": {},
"edit_profile": "Edit Profile",
"@edit_profile": {},
"edit_profile_desc": "Update your profile information",
"@edit_profile_desc": {},
"change_password": "Change Password",
"@change_password": {},
"change_password_desc": "Update your password",
"@change_password_desc": {},
"business_settings": "Business Settings",
"@business_settings": {},
"outlet_information": "Outlet Information",
"@outlet_information": {},
"outlet_informatio_desc": "Manage your outlet details",
"@outlet_informatio_desc": {},
"staff_management": "Staff Management",
"@staff_management": {},
"staff_management_desc": "Manage your staff",
"@staff_management_desc": {},
"manage_your_products": "Manage Your Products",
"@manage_your_products": {},
"download_report": "Download Report",
"@download_report": {},
"download_report_desc": "Download your sales report or inventory report",
"@download_report_desc": {},
"app_settings": "App Settings",
"@app_settings": {},
"language_desc": "Select your preferred language",
"@language_desc": {},
"support": "Support",
"@support": {},
"help_center": "Help Center",
"@help_center": {},
"help_center_desc": "Get help from our support team",
"@help_center_desc": {},
"about": "About",
"@about": {},
"about_desc": "Learn more about our app",
"@about_desc": {},
"logout": "Logout",
"@logout": {},
"logout_desc": "Logout of your account",
"@logout_desc": {},
"save": "Save",
"@save": {},
"name": "Name",
"@name": {},
"name_placeholder": "Please enter your name",
"@name_placeholder": {},
"password_changed": "Password Changed",
"@password_changed": {},
"current_password": "Current Password",
"@current_password": {},
"current_password_placeholder": "Please enter your current password",
"@current_password_placeholder": {},
"new_password": "New Password",
"@new_password": {},
"new_password_placeholder": "Please enter your new password",
"@new_password_placeholder": {},
"new_password_not_same": "New password cannot be same as current password",
"@new_password_not_same": {},
"general_information": "General Information",
"@general_information": {},
"address": "Address",
"@address": {},
"phone_number": "Phone Number",
"@phone_number": {},
"currency": "Currency",
"@currency": {},
"tax_rate": "Tax Rate",
"@tax_rate": {},
"status_text": "Status",
"@status_text": {},
"coming_soon": "Coming Soon",
"@coming_soon": {},
"coming_soon_desc": "Something amazing is brewing!\nStay tuned for the big reveal.",
"@coming_soon_desc": {},
"transaction_report": "Transaction Report",
"@transaction_report": {},
"transaction_report_desc": "Export all transaction data with detailed analytics",
"@transaction_report_desc": {},
"invetory_report": "Inventory Report",
"@invetory_report": {},
"invetory_report_desc": "Export inventory and stock data with trends",
"@invetory_report_desc": {},
"about_app": "About App",
"@about_app": {},
"app_information": "App Information",
"@app_information": {},
"app_name": "App Name",
"@app_name": {},
"build_number": "Build Number",
"@build_number": {},
"package_name": "Package Name",
"@package_name": {},
"device": "Device",
"@device": {},
"profit_loss": "Laba Rugi",
"@profit_loss": {}
} }
+383 -1
View File
@@ -49,5 +49,387 @@
"profile": "Profil", "profile": "Profil",
"@profile": {}, "@profile": {},
"sales_today": "Penjualan hari ini", "sales_today": "Penjualan hari ini",
"@sales_today": {} "@sales_today": {},
"order": "Pesanan",
"@order": {},
"sales": "Penjualan",
"@sales": {},
"finance": "Keuangan",
"@finance": {},
"product": "Produk",
"@product": {},
"form": "Form",
"@form": {},
"schedule": "Jadwal",
"@schedule": {},
"inventory": "Inventaris",
"@inventory": {},
"customer": "Pelanggan",
"@customer": {},
"purchase": "Pembelian",
"@purchase": {},
"today_summary": "Ringkasan Hari Ini",
"@today_summary": {},
"today": "Hari ini",
"@today": {},
"new_customer": "Pelanggan baru",
"@new_customer": {},
"refund": "Pengembalian dana",
"@refund": {},
"void_text": "Dibatalkan",
"@void_text": {},
"increase": "Bertambah",
"@increase": {},
"today_top_product": "Produk teratas hari ini",
"@today_top_product": {},
"rank": "Pangkat",
"@rank": {},
"quantity_sold": "Kuantiti Terjual",
"@quantity_sold": {},
"total_orders": "Jumlah Pesanan",
"@total_orders": {},
"average_price": "Harga Rata-rata",
"@average_price": {},
"perfomance": "Performa",
"@perfomance": {},
"total_sales": "Jumlah Penjualan",
"@total_sales": {},
"total_items": "Jumlah Barang",
"@total_items": {},
"summary": "Ringkasan",
"@summary": {},
"net_sales": "Penjualan Bersih",
"@net_sales": {},
"daily_breakdown": "Perincian Harian",
"@daily_breakdown": {},
"orders": "Pesanan",
"@orders": {},
"items": "Barang",
"@items": {},
"tax": "Pajak",
"@tax": {},
"discount": "Diskon",
"@discount": {},
"total_purchase": "Jumlah Pembelian",
"@total_purchase": {},
"pending_order": "Pesanan Menunggu",
"@pending_order": {},
"history_purchase": "Riwayat Pembelian",
"@history_purchase": {},
"all": "Semua",
"@all": {},
"select_date_range": "Pilih Rentang Tanggal",
"@select_date_range": {},
"no_date_selected": "Belum ada tanggal dipilih",
"@no_date_selected": {},
"selected_date": "Tanggal Terpilih",
"@selected_date": {},
"select": "Pilih",
"@select": {},
"cancel": "Batal",
"@cancel": {},
"total_revenue": "Jumlah Pendapatan",
"@total_revenue": {},
"total_expenditures": "Jumlah Pengeluaran",
"@total_expenditures": {},
"net_profit": "Keuntungan Bersih",
"@net_profit": {},
"margin_profit": "Keuntungan Margin",
"@margin_profit": {},
"cash_flow_analysis": "Analisis Arus Kas",
"@cash_flow_analysis": {},
"cash_in": "Uang Masuk",
"@cash_in": {},
"cash_out": "Uang Keluar",
"@cash_out": {},
"net_flow": "Arus Bersih",
"@net_flow": {},
"cash_flow_chart": "Grafik Cash Flow ${days} Hari Terakhir",
"@cash_flow_chart": {
"placeholders": {
"days": {
"type": "int",
"example": "7"
}
}
},
"profit_loss_detail": "Detail Untung & Rugi",
"@profit_loss_detail": {},
"gross_sales": "Penjualan Kotor",
"@gross_sales": {},
"return_text": "Retur",
"@return_text": {},
"cogs": "HPP",
"@cogs": {},
"cost_of_goods_sold": "Harga Pokok Penjualan",
"@cost_of_goods_sold": {},
"gross_profit": "Keuntungan Kotor",
"@gross_profit": {},
"operating_costs": "Biaya Operasional",
"@operating_costs": {},
"sales_category": "Kategori Penjualan",
"@sales_category": {},
"unit": "Unit",
"@unit": {},
"category_no_data": "Belum ada data kategori",
"@category_no_data": {},
"category_no_data_desc": "Data kategori penjualan akan muncul di sini",
"@category_no_data_desc": {},
"product_analytic": "Analisis Produk",
"@product_analytic": {},
"view_all": "Lihat Semua",
"@view_all": {},
"sold": "Terjual",
"@sold": {},
"revenue": "Pendapatan",
"@revenue": {},
"cost": "Biaya",
"@cost": {},
"profit_per_unit": "Keuntungan per unit",
"@profit_per_unit": {},
"total_sold": "Jumlah Terjual",
"@total_sold": {},
"ingredients": "Bahan Baku",
"@ingredients": {},
"low_stock": "Stok Rendah",
"@low_stock": {},
"zero_stock": "Stok Kosong",
"@zero_stock": {},
"stock": "Stok",
"@stock": {},
"price": "Harga",
"@price": {},
"out_of_stock": "Stok habis",
"@out_of_stock": {},
"out_of_stock_desc": "Produk tidak tersedia untuk dijual",
"@out_of_stock_desc": {},
"in_text": "Masuk",
"@in_text": {},
"out_text": "Keluar",
"@out_text": {},
"available": "Tersedia",
"@available": {},
"total_products": "Jumlah Produk",
"@total_products": {},
"total_ingredients": "Jumlah Bahan Baku",
"@total_ingredients": {},
"products": "Produk",
"@products": {},
"value_text": "Nilai",
"@value_text": {},
"low_stock_desc": "Segera reorder minimal {stock} pcs",
"@low_stock_desc": {
"placeholders": {
"stock": {
"type": "String",
"example": "0"
}
}
},
"joined": "Bergabung",
"@joined": {},
"ago": "lalu",
"@ago": {},
"active": "Aktif",
"@active": {},
"inactive": "Tidak Aktif",
"@inactive": {},
"total_amount": "Jumlah Total",
"@total_amount": {},
"table": "Meja",
"@table": {},
"remaining": "Sisa",
"@remaining": {},
"payment": "Pembayaran",
"@payment": {},
"completed": "Selesai",
"@completed": {},
"pending": "Menunggu",
"@pending": {},
"no_order_with_status": "Tidak ada pesanan {status} yang ditemukan",
"@no_order_with_status": {
"placeholders": {
"status": {
"type": "String",
"example": "pending"
}
}
},
"order_details": "Detail Pesanan",
"@order_details": {},
"order_number": "Nomor Pesanan",
"@order_number": {},
"order_status": "Status Pesanan",
"@order_status": {},
"order_information": "Informasi Pesanan",
"@order_information": {},
"order_type": "Tipe Pesanan",
"@order_type": {},
"payment_status": "Status Pembayaran",
"@payment_status": {},
"created": "Dibuat",
"@created": {},
"order_item": "Item Pesanan",
"@order_item": {},
"item": "Item",
"@item": {},
"each": "Setiap",
"@each": {},
"total_item": "Jumlah Item",
"@total_item": {},
"payment_summary": "Ringkasan Pembayaran",
"@payment_summary": {},
"subtotal": "Subtotal",
"@subtotal": {},
"paid": "Dibayar",
"@paid": {},
"total": "Jumlah",
"@total": {},
"payment_method": "Metode Pembayaran",
"@payment_method": {},
"dine_in": "Makan di Tempat",
"@dine_in": {},
"dine_in_experience": "Pengalaman Bersantap Di Tempat",
"@dine_in_experience": {},
"note": "Catatan",
"@note": {},
"sales_chart": "Bagan Penjualan",
"@sales_chart": {},
"no_data_available": "Tidak Ada Data Tersedia",
"@no_data_available": {},
"total_days_overview": "ikhtisar {days} hari",
"@total_days_overview": {
"placeholders": {
"days": {
"type": "int",
"example": "0"
}
}
},
"sales_data": "Data Penjualan",
"@sales_data": {},
"no_sales_data": "Tidak ada data penjualan",
"@no_sales_data": {},
"no_sales_data_desc": "Data penjualan akan muncul di sini setelah transaksi dicatat",
"@no_sales_data_desc": {},
"payment_methods": "Metode Pembayaran",
"@payment_methods": {},
"payment_methods_desc": "Rincian pendapatan berdasarkan metode pembayaran ",
"@payment_methods_desc": {},
"revenue_share": "Bagi Hasil",
"@revenue_share": {},
"no_payment_methods": "Tidak Ada Metode Pembayaran",
"@no_payment_methods": {},
"no_payment_methods_desc": "Data metode pembayaran akan muncul di sini setelah transaksi dilakukan",
"@no_payment_methods_desc": {},
"best_selling_products": "Produk Terlaris",
"@best_selling_products": {},
"highest_sales_ranking": "Ranking penjualan tertinggi",
"@highest_sales_ranking": {},
"best_seller": "Penjual Terbaik",
"@best_seller": {},
"top_performer": "Berkinerja Terbaik",
"@top_performer": {},
"account_information": "Informasi Akun",
"@account_information": {},
"member_since": "Member Sejak",
"@member_since": {},
"edit_profile": "Ubah Profil",
"@edit_profile": {},
"edit_profile_desc": "Update informasi profil Anda",
"@edit_profile_desc": {},
"change_password": "Ubah Kata Sandi",
"@change_password": {},
"change_password_desc": "Update kata sandi Anda",
"@change_password_desc": {},
"business_settings": "Pengaturan Bisnis",
"@business_settings": {},
"outlet_information": "Informasi Outlet",
"@outlet_information": {},
"outlet_informatio_desc": "Kelola informasi outlet Anda",
"@outlet_informatio_desc": {},
"staff_management": "Manajemen Staff",
"@staff_management": {},
"staff_management_desc": "Kelola staff Anda",
"@staff_management_desc": {},
"manage_your_products": "Kelola Produk Anda",
"@manage_your_products": {},
"download_report": "Unduh Laporan",
"@download_report": {},
"download_report_desc": "Unduh laporan penjualan atau stok",
"@download_report_desc": {},
"app_settings": "Pengaturan Aplikasi",
"@app_settings": {},
"language_desc": "Pilih bahasa aplikasi Anda",
"@language_desc": {},
"support": "Dukungan",
"@support": {},
"help_center": "Pusat Bantuan",
"@help_center": {},
"help_center_desc": "Hubungi tim dukungan kami",
"@help_center_desc": {},
"about": "Tentang",
"@about": {},
"about_desc": "Tentang Aplikasi",
"@about_desc": {},
"logout": "Keluar",
"@logout": {},
"logout_desc": "Keluar dari akun Anda",
"@logout_desc": {},
"save": "Simpan",
"@save": {},
"name": "Nama",
"@name": {},
"name_placeholder": "Masukkan nama Anda",
"@name_placeholder": {},
"password_changed": "Kata Sandi Berubah",
"@password_changed": {},
"current_password": "Kata Sandi Saat Ini",
"@current_password": {},
"current_password_placeholder": "Masukkan kata sandi saat ini",
"@current_password_placeholder": {},
"new_password": "Kata Sandi Baru",
"@new_password": {},
"new_password_placeholder": "Masukkan kata sandi baru",
"@new_password_placeholder": {},
"new_password_not_same": "Kata Sandi Baru Tidak Sama Dengan Kata Sandi Saat Ini",
"@new_password_not_same": {},
"general_information": "Informasi Umum",
"@general_information": {},
"address": "Alamat",
"@address": {},
"phone_number": "Nomor Telepon",
"@phone_number": {},
"currency": "Mata Uang",
"@currency": {},
"tax_rate": "Tarif Pajak",
"@tax_rate": {},
"status_text": "Status",
"@status_text": {},
"coming_soon": "Segera Hadir",
"@coming_soon": {},
"coming_soon_desc": "Sesuatu yang menakjubkan sedang terjadi!\nNantikan pengungkapan besarnya.",
"@coming_soon_desc": {},
"transaction_report": "Laporan Transaksi",
"@transaction_report": {},
"transaction_report_desc": "Ekspor semua data transaksi dengan analitik terperinci",
"@transaction_report_desc": {},
"invetory_report": "Laporan Inventaris",
"@invetory_report": {},
"invetory_report_desc": "Ekspor inventaris dan data stok dengan tren",
"@invetory_report_desc": {},
"about_app": "Tentang Aplikasi",
"@about_app": {},
"app_information": "Informasi Aplikasi",
"@app_information": {},
"app_name": "Nama Aplikasi",
"@app_name": {},
"build_number": "Nomor Build",
"@build_number": {},
"package_name": "Nama Paket",
"@package_name": {},
"device": "Perangkat",
"@device": {},
"profit_loss": "Laba Rugi",
"@profit_loss": {}
} }
File diff suppressed because it is too large Load Diff
+539
View File
@@ -82,4 +82,543 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get sales_today => 'Sales today'; String get sales_today => 'Sales today';
@override
String get order => 'Order';
@override
String get sales => 'Sales';
@override
String get finance => 'Finance';
@override
String get product => 'Product';
@override
String get form => 'Form';
@override
String get schedule => 'Schedule';
@override
String get inventory => 'Inventory';
@override
String get customer => 'Customer';
@override
String get purchase => 'Purchase';
@override
String get today_summary => 'Today\'s Summary';
@override
String get today => 'Today';
@override
String get new_customer => 'New Customer';
@override
String get refund => 'Refund';
@override
String get void_text => 'Void';
@override
String get increase => 'Increase';
@override
String get today_top_product => 'Today\'s Top Product';
@override
String get rank => 'Rank';
@override
String get quantity_sold => 'Quantity Sold';
@override
String get total_orders => 'Total Orders';
@override
String get average_price => 'Average Price';
@override
String get perfomance => 'Performance';
@override
String get total_sales => 'Total Sales';
@override
String get total_items => 'Total Items';
@override
String get summary => 'Summary';
@override
String get net_sales => 'Net Sales';
@override
String get daily_breakdown => 'Daily Breakdown';
@override
String get orders => 'Orders';
@override
String get items => 'Items';
@override
String get tax => 'Tax';
@override
String get discount => 'Discount';
@override
String get total_purchase => 'Total Purchase';
@override
String get pending_order => 'Pending Order';
@override
String get history_purchase => 'History Purchase';
@override
String get all => 'All';
@override
String get select_date_range => 'Select Date Range';
@override
String get no_date_selected => 'No date has been selected yet';
@override
String get selected_date => 'Selected Date';
@override
String get select => 'Select';
@override
String get cancel => 'Cancel';
@override
String get total_revenue => 'Total Revenue';
@override
String get total_expenditures => 'Total Expenditures';
@override
String get net_profit => 'Net Profit';
@override
String get margin_profit => 'Margin Profit';
@override
String get cash_flow_analysis => 'Cash Flow Analysis';
@override
String get cash_in => 'Cash In';
@override
String get cash_out => 'Cash Out';
@override
String get net_flow => 'Net Flow';
@override
String cash_flow_chart(int days) {
return 'Cash Flow Chart for $days Last Days';
}
@override
String get profit_loss_detail => 'Profit & Loss Details';
@override
String get gross_sales => 'Gross Sales';
@override
String get return_text => 'Return';
@override
String get cogs => 'COGS';
@override
String get cost_of_goods_sold => 'Cost of goods sold';
@override
String get gross_profit => 'Gross Profit';
@override
String get operating_costs => 'Operating Costs';
@override
String get sales_category => 'Sales Category';
@override
String get unit => 'Unit';
@override
String get category_no_data => 'There are no data categories yet';
@override
String get category_no_data_desc => 'Sales category data will appear here';
@override
String get product_analytic => 'Product Analytic';
@override
String get view_all => 'View All';
@override
String get sold => 'Sold';
@override
String get revenue => 'Revenue';
@override
String get cost => 'Cost';
@override
String get profit_per_unit => 'Profit per unit';
@override
String get total_sold => 'Total Sold';
@override
String get ingredients => 'Ingredients';
@override
String get low_stock => 'Low Stock';
@override
String get zero_stock => 'Zero Stock';
@override
String get stock => 'Stock';
@override
String get price => 'Price';
@override
String get out_of_stock => 'Out of stock';
@override
String get out_of_stock_desc => 'Product not available for sale';
@override
String get in_text => 'In';
@override
String get out_text => 'Out';
@override
String get available => 'Available';
@override
String get total_products => 'Total Products';
@override
String get total_ingredients => 'Total Ingredients';
@override
String get products => 'Products';
@override
String get value_text => 'Value';
@override
String low_stock_desc(String stock) {
return 'Immediately reorder at least $stock pcs';
}
@override
String get joined => 'Joined';
@override
String get ago => 'ago';
@override
String get active => 'Active';
@override
String get inactive => 'Inactive';
@override
String get total_amount => 'Total Amount';
@override
String get table => 'Table';
@override
String get remaining => 'Remaining';
@override
String get payment => 'Payment';
@override
String get completed => 'Completed';
@override
String get pending => 'Pending';
@override
String no_order_with_status(String status) {
return 'No $status orders found';
}
@override
String get order_details => 'Order Details';
@override
String get order_number => 'Order Number';
@override
String get order_status => 'Order Status';
@override
String get order_information => 'Order Information';
@override
String get order_type => 'Order Type';
@override
String get payment_status => 'Payment Status';
@override
String get created => 'Created';
@override
String get order_item => 'Order Item';
@override
String get item => 'Item';
@override
String get each => 'Each';
@override
String get total_item => 'Total Item';
@override
String get payment_summary => 'Payment Summary';
@override
String get subtotal => 'Subtotal';
@override
String get paid => 'Paid';
@override
String get total => 'Total';
@override
String get payment_method => 'Payment Method';
@override
String get dine_in => 'Dine In';
@override
String get dine_in_experience => 'Dine In Experience';
@override
String get note => 'Note';
@override
String get sales_chart => 'Sales Chart';
@override
String get no_data_available => 'No Data Avaiable';
@override
String total_days_overview(int days) {
return '$days days overview';
}
@override
String get sales_data => 'Sales Data';
@override
String get no_sales_data => 'No Sales Data';
@override
String get no_sales_data_desc => 'Sales data will appear here once transactions are recorded';
@override
String get payment_methods => 'Payment Methods';
@override
String get payment_methods_desc => 'Revenue breakdown by payment method ';
@override
String get revenue_share => 'Revenue Share';
@override
String get no_payment_methods => 'No Payment Methods';
@override
String get no_payment_methods_desc => 'Payment method data will appear here once transactions are made';
@override
String get best_selling_products => 'Best Selling Products';
@override
String get highest_sales_ranking => 'Highest sales ranking';
@override
String get best_seller => 'Best Seller';
@override
String get top_performer => 'Top Performer';
@override
String get account_information => 'Account Information';
@override
String get member_since => 'Member Since';
@override
String get edit_profile => 'Edit Profile';
@override
String get edit_profile_desc => 'Update your profile information';
@override
String get change_password => 'Change Password';
@override
String get change_password_desc => 'Update your password';
@override
String get business_settings => 'Business Settings';
@override
String get outlet_information => 'Outlet Information';
@override
String get outlet_informatio_desc => 'Manage your outlet details';
@override
String get staff_management => 'Staff Management';
@override
String get staff_management_desc => 'Manage your staff';
@override
String get manage_your_products => 'Manage Your Products';
@override
String get download_report => 'Download Report';
@override
String get download_report_desc => 'Download your sales report or inventory report';
@override
String get app_settings => 'App Settings';
@override
String get language_desc => 'Select your preferred language';
@override
String get support => 'Support';
@override
String get help_center => 'Help Center';
@override
String get help_center_desc => 'Get help from our support team';
@override
String get about => 'About';
@override
String get about_desc => 'Learn more about our app';
@override
String get logout => 'Logout';
@override
String get logout_desc => 'Logout of your account';
@override
String get save => 'Save';
@override
String get name => 'Name';
@override
String get name_placeholder => 'Please enter your name';
@override
String get password_changed => 'Password Changed';
@override
String get current_password => 'Current Password';
@override
String get current_password_placeholder => 'Please enter your current password';
@override
String get new_password => 'New Password';
@override
String get new_password_placeholder => 'Please enter your new password';
@override
String get new_password_not_same => 'New password cannot be same as current password';
@override
String get general_information => 'General Information';
@override
String get address => 'Address';
@override
String get phone_number => 'Phone Number';
@override
String get currency => 'Currency';
@override
String get tax_rate => 'Tax Rate';
@override
String get status_text => 'Status';
@override
String get coming_soon => 'Coming Soon';
@override
String get coming_soon_desc => 'Something amazing is brewing!\nStay tuned for the big reveal.';
@override
String get transaction_report => 'Transaction Report';
@override
String get transaction_report_desc => 'Export all transaction data with detailed analytics';
@override
String get invetory_report => 'Inventory Report';
@override
String get invetory_report_desc => 'Export inventory and stock data with trends';
@override
String get about_app => 'About App';
@override
String get app_information => 'App Information';
@override
String get app_name => 'App Name';
@override
String get build_number => 'Build Number';
@override
String get package_name => 'Package Name';
@override
String get device => 'Device';
@override
String get profit_loss => 'Laba Rugi';
} }
+539
View File
@@ -82,4 +82,543 @@ class AppLocalizationsId extends AppLocalizations {
@override @override
String get sales_today => 'Penjualan hari ini'; String get sales_today => 'Penjualan hari ini';
@override
String get order => 'Pesanan';
@override
String get sales => 'Penjualan';
@override
String get finance => 'Keuangan';
@override
String get product => 'Produk';
@override
String get form => 'Form';
@override
String get schedule => 'Jadwal';
@override
String get inventory => 'Inventaris';
@override
String get customer => 'Pelanggan';
@override
String get purchase => 'Pembelian';
@override
String get today_summary => 'Ringkasan Hari Ini';
@override
String get today => 'Hari ini';
@override
String get new_customer => 'Pelanggan baru';
@override
String get refund => 'Pengembalian dana';
@override
String get void_text => 'Dibatalkan';
@override
String get increase => 'Bertambah';
@override
String get today_top_product => 'Produk teratas hari ini';
@override
String get rank => 'Pangkat';
@override
String get quantity_sold => 'Kuantiti Terjual';
@override
String get total_orders => 'Jumlah Pesanan';
@override
String get average_price => 'Harga Rata-rata';
@override
String get perfomance => 'Performa';
@override
String get total_sales => 'Jumlah Penjualan';
@override
String get total_items => 'Jumlah Barang';
@override
String get summary => 'Ringkasan';
@override
String get net_sales => 'Penjualan Bersih';
@override
String get daily_breakdown => 'Perincian Harian';
@override
String get orders => 'Pesanan';
@override
String get items => 'Barang';
@override
String get tax => 'Pajak';
@override
String get discount => 'Diskon';
@override
String get total_purchase => 'Jumlah Pembelian';
@override
String get pending_order => 'Pesanan Menunggu';
@override
String get history_purchase => 'Riwayat Pembelian';
@override
String get all => 'Semua';
@override
String get select_date_range => 'Pilih Rentang Tanggal';
@override
String get no_date_selected => 'Belum ada tanggal dipilih';
@override
String get selected_date => 'Tanggal Terpilih';
@override
String get select => 'Pilih';
@override
String get cancel => 'Batal';
@override
String get total_revenue => 'Jumlah Pendapatan';
@override
String get total_expenditures => 'Jumlah Pengeluaran';
@override
String get net_profit => 'Keuntungan Bersih';
@override
String get margin_profit => 'Keuntungan Margin';
@override
String get cash_flow_analysis => 'Analisis Arus Kas';
@override
String get cash_in => 'Uang Masuk';
@override
String get cash_out => 'Uang Keluar';
@override
String get net_flow => 'Arus Bersih';
@override
String cash_flow_chart(int days) {
return 'Grafik Cash Flow \$$days Hari Terakhir';
}
@override
String get profit_loss_detail => 'Detail Untung & Rugi';
@override
String get gross_sales => 'Penjualan Kotor';
@override
String get return_text => 'Retur';
@override
String get cogs => 'HPP';
@override
String get cost_of_goods_sold => 'Harga Pokok Penjualan';
@override
String get gross_profit => 'Keuntungan Kotor';
@override
String get operating_costs => 'Biaya Operasional';
@override
String get sales_category => 'Kategori Penjualan';
@override
String get unit => 'Unit';
@override
String get category_no_data => 'Belum ada data kategori';
@override
String get category_no_data_desc => 'Data kategori penjualan akan muncul di sini';
@override
String get product_analytic => 'Analisis Produk';
@override
String get view_all => 'Lihat Semua';
@override
String get sold => 'Terjual';
@override
String get revenue => 'Pendapatan';
@override
String get cost => 'Biaya';
@override
String get profit_per_unit => 'Keuntungan per unit';
@override
String get total_sold => 'Jumlah Terjual';
@override
String get ingredients => 'Bahan Baku';
@override
String get low_stock => 'Stok Rendah';
@override
String get zero_stock => 'Stok Kosong';
@override
String get stock => 'Stok';
@override
String get price => 'Harga';
@override
String get out_of_stock => 'Stok habis';
@override
String get out_of_stock_desc => 'Produk tidak tersedia untuk dijual';
@override
String get in_text => 'Masuk';
@override
String get out_text => 'Keluar';
@override
String get available => 'Tersedia';
@override
String get total_products => 'Jumlah Produk';
@override
String get total_ingredients => 'Jumlah Bahan Baku';
@override
String get products => 'Produk';
@override
String get value_text => 'Nilai';
@override
String low_stock_desc(String stock) {
return 'Segera reorder minimal $stock pcs';
}
@override
String get joined => 'Bergabung';
@override
String get ago => 'lalu';
@override
String get active => 'Aktif';
@override
String get inactive => 'Tidak Aktif';
@override
String get total_amount => 'Jumlah Total';
@override
String get table => 'Meja';
@override
String get remaining => 'Sisa';
@override
String get payment => 'Pembayaran';
@override
String get completed => 'Selesai';
@override
String get pending => 'Menunggu';
@override
String no_order_with_status(String status) {
return 'Tidak ada pesanan $status yang ditemukan';
}
@override
String get order_details => 'Detail Pesanan';
@override
String get order_number => 'Nomor Pesanan';
@override
String get order_status => 'Status Pesanan';
@override
String get order_information => 'Informasi Pesanan';
@override
String get order_type => 'Tipe Pesanan';
@override
String get payment_status => 'Status Pembayaran';
@override
String get created => 'Dibuat';
@override
String get order_item => 'Item Pesanan';
@override
String get item => 'Item';
@override
String get each => 'Setiap';
@override
String get total_item => 'Jumlah Item';
@override
String get payment_summary => 'Ringkasan Pembayaran';
@override
String get subtotal => 'Subtotal';
@override
String get paid => 'Dibayar';
@override
String get total => 'Jumlah';
@override
String get payment_method => 'Metode Pembayaran';
@override
String get dine_in => 'Makan di Tempat';
@override
String get dine_in_experience => 'Pengalaman Bersantap Di Tempat';
@override
String get note => 'Catatan';
@override
String get sales_chart => 'Bagan Penjualan';
@override
String get no_data_available => 'Tidak Ada Data Tersedia';
@override
String total_days_overview(int days) {
return 'ikhtisar $days hari';
}
@override
String get sales_data => 'Data Penjualan';
@override
String get no_sales_data => 'Tidak ada data penjualan';
@override
String get no_sales_data_desc => 'Data penjualan akan muncul di sini setelah transaksi dicatat';
@override
String get payment_methods => 'Metode Pembayaran';
@override
String get payment_methods_desc => 'Rincian pendapatan berdasarkan metode pembayaran ';
@override
String get revenue_share => 'Bagi Hasil';
@override
String get no_payment_methods => 'Tidak Ada Metode Pembayaran';
@override
String get no_payment_methods_desc => 'Data metode pembayaran akan muncul di sini setelah transaksi dilakukan';
@override
String get best_selling_products => 'Produk Terlaris';
@override
String get highest_sales_ranking => 'Ranking penjualan tertinggi';
@override
String get best_seller => 'Penjual Terbaik';
@override
String get top_performer => 'Berkinerja Terbaik';
@override
String get account_information => 'Informasi Akun';
@override
String get member_since => 'Member Sejak';
@override
String get edit_profile => 'Ubah Profil';
@override
String get edit_profile_desc => 'Update informasi profil Anda';
@override
String get change_password => 'Ubah Kata Sandi';
@override
String get change_password_desc => 'Update kata sandi Anda';
@override
String get business_settings => 'Pengaturan Bisnis';
@override
String get outlet_information => 'Informasi Outlet';
@override
String get outlet_informatio_desc => 'Kelola informasi outlet Anda';
@override
String get staff_management => 'Manajemen Staff';
@override
String get staff_management_desc => 'Kelola staff Anda';
@override
String get manage_your_products => 'Kelola Produk Anda';
@override
String get download_report => 'Unduh Laporan';
@override
String get download_report_desc => 'Unduh laporan penjualan atau stok';
@override
String get app_settings => 'Pengaturan Aplikasi';
@override
String get language_desc => 'Pilih bahasa aplikasi Anda';
@override
String get support => 'Dukungan';
@override
String get help_center => 'Pusat Bantuan';
@override
String get help_center_desc => 'Hubungi tim dukungan kami';
@override
String get about => 'Tentang';
@override
String get about_desc => 'Tentang Aplikasi';
@override
String get logout => 'Keluar';
@override
String get logout_desc => 'Keluar dari akun Anda';
@override
String get save => 'Simpan';
@override
String get name => 'Nama';
@override
String get name_placeholder => 'Masukkan nama Anda';
@override
String get password_changed => 'Kata Sandi Berubah';
@override
String get current_password => 'Kata Sandi Saat Ini';
@override
String get current_password_placeholder => 'Masukkan kata sandi saat ini';
@override
String get new_password => 'Kata Sandi Baru';
@override
String get new_password_placeholder => 'Masukkan kata sandi baru';
@override
String get new_password_not_same => 'Kata Sandi Baru Tidak Sama Dengan Kata Sandi Saat Ini';
@override
String get general_information => 'Informasi Umum';
@override
String get address => 'Alamat';
@override
String get phone_number => 'Nomor Telepon';
@override
String get currency => 'Mata Uang';
@override
String get tax_rate => 'Tarif Pajak';
@override
String get status_text => 'Status';
@override
String get coming_soon => 'Segera Hadir';
@override
String get coming_soon_desc => 'Sesuatu yang menakjubkan sedang terjadi!\nNantikan pengungkapan besarnya.';
@override
String get transaction_report => 'Laporan Transaksi';
@override
String get transaction_report_desc => 'Ekspor semua data transaksi dengan analitik terperinci';
@override
String get invetory_report => 'Laporan Inventaris';
@override
String get invetory_report_desc => 'Ekspor inventaris dan data stok dengan tren';
@override
String get about_app => 'Tentang Aplikasi';
@override
String get app_information => 'Informasi Aplikasi';
@override
String get app_name => 'Nama Aplikasi';
@override
String get build_number => 'Nomor Build';
@override
String get package_name => 'Nama Paket';
@override
String get device => 'Perangkat';
@override
String get profit_loss => 'Laba Rugi';
} }
+8
View File
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:injectable/injectable.dart'; import 'package:injectable/injectable.dart';
import 'common/utils/fcm_service.dart';
import 'injection.dart'; import 'injection.dart';
import 'presentation/app_widget.dart'; import 'presentation/app_widget.dart';
@@ -24,5 +25,12 @@ void main() async {
kReleaseMode ? Environment.prod : Environment.dev, kReleaseMode ? Environment.prod : Environment.dev,
); );
// Initialize FCM after dependencies are ready
await getIt<FcmService>().initialize(
onMessageTap: (message) {
debugPrint('[FCM] Navigate based on: ${message.data}');
},
);
runApp(const AppWidget()); runApp(const AppWidget());
} }
+51 -123
View File
@@ -1,76 +1,21 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'dart:math' as math;
import '../../../../common/theme/theme.dart';
import '../../../common/painter/wave_painter.dart'; import '../../../common/painter/wave_painter.dart';
import '../../../common/theme/theme.dart';
class CustomAppBar extends StatefulWidget { class CustomAppBar extends StatelessWidget {
final String title; final String title;
final bool isBack; final bool isBack;
const CustomAppBar({super.key, required this.title, this.isBack = true}); const CustomAppBar({super.key, required this.title, this.isBack = true});
@override
State<CustomAppBar> createState() => _CustomAppBarState();
}
class _CustomAppBarState extends State<CustomAppBar>
with TickerProviderStateMixin {
late AnimationController _particleController;
late AnimationController _waveController;
late AnimationController _breathController;
late Animation<double> _particleAnimation;
late Animation<double> _waveAnimation;
late Animation<double> _breathAnimation;
@override
void initState() {
super.initState();
_particleController = AnimationController(
duration: const Duration(seconds: 8),
vsync: this,
)..repeat();
_waveController = AnimationController(
duration: const Duration(seconds: 6),
vsync: this,
)..repeat();
_breathController = AnimationController(
duration: const Duration(seconds: 4),
vsync: this,
)..repeat(reverse: true);
_particleAnimation = Tween<double>(
begin: 0.0,
end: 2 * math.pi,
).animate(_particleController);
_waveAnimation = Tween<double>(
begin: 0.0,
end: 2 * math.pi,
).animate(_waveController);
_breathAnimation = Tween<double>(begin: 0.8, end: 1.2).animate(
CurvedAnimation(parent: _breathController, curve: Curves.easeInOut),
);
}
@override
void dispose() {
_particleController.dispose();
_waveController.dispose();
_breathController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return FlexibleSpaceBar( return FlexibleSpaceBar(
titlePadding: EdgeInsets.only(left: widget.isBack ? 50 : 20, bottom: 16), titlePadding: EdgeInsets.only(left: isBack ? 50 : 20, bottom: 16),
title: Text( title: Text(
widget.title, title,
style: AppStyle.xl.copyWith( style: AppStyle.xl.copyWith(
color: AppColor.textWhite, color: AppColor.textWhite,
fontSize: 18, fontSize: 18,
@@ -85,90 +30,71 @@ class _CustomAppBarState extends State<CustomAppBar>
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
), ),
), ),
child: AnimatedBuilder( child: Stack(
animation: Listenable.merge([
_particleController,
_waveController,
_breathController,
]),
builder: (context, child) {
return Stack(
children: [ children: [
// Animated background elements // Static decorative circles (right side)
_buildAnimatedBackground(context), Positioned(
], top: -20,
); right: -30,
},
),
),
);
}
Widget _buildAnimatedBackground(BuildContext context) {
final size = MediaQuery.of(context).size;
return Stack(
children: [
// Floating particles with orbital motion
...List.generate(8, (index) {
final double radius = 40 + (index * 15);
final double angle = _particleAnimation.value + (index * 0.8);
final double centerX = size.width * 0.7;
final double centerY = 60;
return Positioned(
left: centerX + math.cos(angle) * radius - 3,
top: centerY + math.sin(angle) * (radius * 0.5) - 3,
child: Transform.scale(
scale: _breathAnimation.value * 0.5,
child: Container( child: Container(
width: 4 + (index % 3), width: 120,
height: 4 + (index % 3), height: 120,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
color: AppColor.textWhite.withOpacity(0.6), color: AppColor.textWhite.withOpacity(0.08),
boxShadow: [
BoxShadow(
color: AppColor.textWhite.withOpacity(0.3),
blurRadius: 6,
spreadRadius: 1,
),
],
), ),
), ),
), ),
); Positioned(
}), top: 30,
right: 20,
// Wave patterns child: Container(
Positioned.fill( width: 60,
child: CustomPaint( height: 60,
painter: WavePainter( decoration: BoxDecoration(
animation: _waveAnimation.value, shape: BoxShape.circle,
color: AppColor.textWhite.withOpacity(0.1), color: AppColor.textWhite.withOpacity(0.05),
), ),
), ),
), ),
// Sparkle effects // Static decorative circles (left side)
Positioned(
top: 10,
left: -20,
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: AppColor.textWhite.withOpacity(0.04),
),
),
),
// Static sparkle icons
...List.generate(4, (index) { ...List.generate(4, (index) {
return Positioned( return Positioned(
left: (index * 90.0) % size.width, left: (index * 90.0) % size.width,
top: 20 + (index * 25.0), top: 20 + (index * 25.0),
child: Transform.rotate(
angle: _particleAnimation.value * 2 + index,
child: Transform.scale(
scale: math.sin(_particleAnimation.value + index) * 0.5 + 1,
child: Icon( child: Icon(
Icons.auto_awesome, Icons.auto_awesome,
size: 10 + (index % 3) * 3, size: 10 + (index % 3) * 3,
color: AppColor.textWhite.withOpacity(0.4), color: AppColor.textWhite.withOpacity(0.2),
),
),
), ),
); );
}), }),
// Wave pattern (static)
Positioned.fill(
child: CustomPaint(
painter: WavePainter(
animation: 0.0,
color: AppColor.textWhite.withOpacity(0.1),
),
),
),
// Gradient overlay for depth // Gradient overlay for depth
Container( Container(
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -184,6 +110,8 @@ class _CustomAppBarState extends State<CustomAppBar>
), ),
), ),
], ],
),
),
); );
} }
} }
@@ -11,19 +11,52 @@
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
class $AssetsIconsGen {
const $AssetsIconsGen();
/// File path: assets/icons/ic-report-product.png
AssetGenImage get icReportProduct =>
const AssetGenImage('assets/icons/ic-report-product.png');
/// File path: assets/icons/ic-report-profit-loss.png
AssetGenImage get icReportProfitLoss =>
const AssetGenImage('assets/icons/ic-report-profit-loss.png');
/// File path: assets/icons/ic-report-purchase.png
AssetGenImage get icReportPurchase =>
const AssetGenImage('assets/icons/ic-report-purchase.png');
/// File path: assets/icons/ic-report-sales.png
AssetGenImage get icReportSales =>
const AssetGenImage('assets/icons/ic-report-sales.png');
/// List of all assets
List<AssetGenImage> get values => [
icReportProduct,
icReportProfitLoss,
icReportPurchase,
icReportSales,
];
}
class $AssetsImagesGen { class $AssetsImagesGen {
const $AssetsImagesGen(); const $AssetsImagesGen();
/// File path: assets/images/ic_notification.png
AssetGenImage get icNotification =>
const AssetGenImage('assets/images/ic_notification.png');
/// File path: assets/images/logo.png /// File path: assets/images/logo.png
AssetGenImage get logo => const AssetGenImage('assets/images/logo.png'); AssetGenImage get logo => const AssetGenImage('assets/images/logo.png');
/// List of all assets /// List of all assets
List<AssetGenImage> get values => [logo]; List<AssetGenImage> get values => [icNotification, logo];
} }
class Assets { class Assets {
const Assets._(); const Assets._();
static const $AssetsIconsGen icons = $AssetsIconsGen();
static const $AssetsImagesGen images = $AssetsImagesGen(); static const $AssetsImagesGen images = $AssetsImagesGen();
} }
@@ -1,6 +1,8 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart'; import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import '../../../common/extension/extension.dart';
class DateRangePickerBottomSheet { class DateRangePickerBottomSheet {
static Future<DateRangePickerSelectionChangedArgs?> show({ static Future<DateRangePickerSelectionChangedArgs?> show({
required BuildContext context, required BuildContext context,
@@ -9,8 +11,8 @@ class DateRangePickerBottomSheet {
DateTime? initialEndDate, DateTime? initialEndDate,
DateTime? minDate, DateTime? minDate,
DateTime? maxDate, DateTime? maxDate,
String confirmText = 'Pilih', String? confirmText,
String cancelText = 'Batal', String? cancelText,
Color primaryColor = Colors.blue, Color primaryColor = Colors.blue,
Function(DateTime? startDate, DateTime? endDate)? onChanged, Function(DateTime? startDate, DateTime? endDate)? onChanged,
}) async { }) async {
@@ -26,8 +28,8 @@ class DateRangePickerBottomSheet {
initialEndDate: initialEndDate, initialEndDate: initialEndDate,
minDate: minDate, minDate: minDate,
maxDate: maxDate, maxDate: maxDate,
confirmText: confirmText, confirmText: confirmText ?? context.lang.select,
cancelText: cancelText, cancelText: cancelText ?? context.lang.cancel,
primaryColor: primaryColor, primaryColor: primaryColor,
onChanged: onChanged, onChanged: onChanged,
), ),
@@ -104,7 +106,7 @@ class _DateRangePickerBottomSheetState
return _formatDate(range.startDate!); return _formatDate(range.startDate!);
} }
} }
return 'Belum ada tanggal dipilih'; return context.lang.no_date_selected;
} }
String _formatDate(DateTime date) { String _formatDate(DateTime date) {
@@ -187,7 +189,7 @@ class _DateRangePickerBottomSheetState
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
'Tanggal Terpilih:', '${context.lang.selected_date}:',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_datepicker/datepicker.dart'; import 'package:syncfusion_flutter_datepicker/datepicker.dart';
import '../../../common/extension/extension.dart';
import '../../../common/theme/theme.dart'; import '../../../common/theme/theme.dart';
import '../bottom_sheet/date_range_bottom_sheet.dart'; import '../bottom_sheet/date_range_bottom_sheet.dart';
@@ -22,7 +23,7 @@ class DateRangePickerField extends StatefulWidget {
final double height; final double height;
const DateRangePickerField({ const DateRangePickerField({
Key? key, super.key,
this.label, this.label,
this.placeholder = 'Pilih rentang tanggal', this.placeholder = 'Pilih rentang tanggal',
this.startDate, this.startDate,
@@ -38,7 +39,7 @@ class DateRangePickerField extends StatefulWidget {
this.placeholderStyle, this.placeholderStyle,
this.decoration, this.decoration,
this.height = 52.0, this.height = 52.0,
}) : super(key: key); });
@override @override
State<DateRangePickerField> createState() => _DateRangePickerFieldState(); State<DateRangePickerField> createState() => _DateRangePickerFieldState();
@@ -83,7 +84,7 @@ class _DateRangePickerFieldState extends State<DateRangePickerField> {
final result = await DateRangePickerBottomSheet.show( final result = await DateRangePickerBottomSheet.show(
context: context, context: context,
title: widget.label ?? 'Pilih Rentang Tanggal', title: widget.label ?? context.lang.select_date_range,
initialStartDate: widget.startDate, initialStartDate: widget.startDate,
initialEndDate: widget.endDate, initialEndDate: widget.endDate,
minDate: widget.minDate, minDate: widget.minDate,
@@ -294,7 +295,7 @@ class _DateRangePickerFieldOutlinedState
final result = await DateRangePickerBottomSheet.show( final result = await DateRangePickerBottomSheet.show(
context: context, context: context,
title: widget.label ?? 'Pilih Rentang Tanggal', title: widget.label ?? context.lang.select_date_range,
initialStartDate: widget.startDate, initialStartDate: widget.startDate,
initialEndDate: widget.endDate, initialEndDate: widget.endDate,
minDate: widget.minDate, minDate: widget.minDate,
@@ -412,120 +413,3 @@ class _DateRangePickerFieldOutlinedState
); );
} }
} }
// Usage Example Widget
class DateRangePickerExample extends StatefulWidget {
@override
_DateRangePickerExampleState createState() => _DateRangePickerExampleState();
}
class _DateRangePickerExampleState extends State<DateRangePickerExample> {
DateTime? _startDate;
DateTime? _endDate;
DateTime? _startDate2;
DateTime? _endDate2;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Date Range Picker Example'),
backgroundColor: AppColor.primary,
foregroundColor: AppColor.white,
),
body: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Default Style',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
const SizedBox(height: 16),
DateRangePickerField(
label: 'Periode Laporan',
placeholder: 'Pilih tanggal mulai - selesai',
startDate: _startDate,
endDate: _endDate,
primaryColor: AppColor.primary,
onChanged: (start, end) {
setState(() {
_startDate = start;
_endDate = end;
});
},
),
const SizedBox(height: 32),
Text(
'Outlined Style',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: AppColor.textPrimary,
),
),
const SizedBox(height: 16),
DateRangePickerFieldOutlined(
label: 'Rentang Waktu',
placeholder: 'Pilih rentang tanggal',
startDate: _startDate2,
endDate: _endDate2,
primaryColor: AppColor.secondary,
onChanged: (start, end) {
setState(() {
_startDate2 = start;
_endDate2 = end;
});
},
),
const SizedBox(height: 24),
// Display selected dates
if (_startDate != null ||
_endDate != null ||
_startDate2 != null ||
_endDate2 != null)
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: AppColor.background,
borderRadius: BorderRadius.circular(8),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Selected Dates:',
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
),
const SizedBox(height: 8),
if (_startDate != null)
Text(
'Default: ${_startDate!} - ${_endDate ?? 'Not selected'}',
),
if (_startDate2 != null)
Text(
'Outlined: ${_startDate2!} - ${_endDate2 ?? 'Not selected'}',
),
],
),
),
],
),
),
);
}
}
@@ -0,0 +1,166 @@
import 'package:flutter/material.dart';
import '../../../common/painter/wave_painter.dart';
import '../../../common/theme/theme.dart';
class ParticleCard extends StatelessWidget {
/// Content yang ditampilkan di atas particle background
final Widget child;
/// Gradient background card. Default pakai primaryGradient
final List<Color>? gradientColors;
/// Arah gradient. Default topLeft → bottomRight
final AlignmentGeometry gradientBegin;
final AlignmentGeometry gradientEnd;
/// Border radius card. Default 16
final double borderRadius;
/// Padding konten. Default 16 semua sisi
final EdgeInsetsGeometry? padding;
/// Height card. Null = wrap content
final double? height;
/// Opacity particle & wave. Default 1.0
final double decorationOpacity;
const ParticleCard({
super.key,
required this.child,
this.gradientColors,
this.gradientBegin = Alignment.topLeft,
this.gradientEnd = Alignment.bottomRight,
this.borderRadius = 16,
this.padding,
this.height,
this.decorationOpacity = 1.0,
});
@override
Widget build(BuildContext context) {
final colors = gradientColors ?? AppColor.primaryGradient;
return ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: Container(
height: height,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
gradient: LinearGradient(
colors: colors,
begin: gradientBegin,
end: gradientEnd,
),
boxShadow: [
BoxShadow(
color: colors.first.withOpacity(0.35),
blurRadius: 16,
offset: const Offset(0, 6),
),
],
),
child: Stack(
children: [
// --- Decorative background ---
Opacity(
opacity: decorationOpacity,
child: Stack(
children: [
// Circles kanan atas
Positioned(
top: -24,
right: -24,
child: _circle(120, AppColor.white, 0.10),
),
Positioned(
top: 28,
right: 16,
child: _circle(60, AppColor.white, 0.06),
),
Positioned(
top: 70,
right: -10,
child: _circle(36, AppColor.white, 0.08),
),
// Circles kiri bawah
Positioned(
bottom: -20,
left: -20,
child: _circle(90, AppColor.white, 0.06),
),
Positioned(
bottom: 20,
left: 40,
child: _circle(40, AppColor.white, 0.04),
),
// Sparkle icons
..._sparkles(context),
// Wave pattern
Positioned.fill(
child: CustomPaint(
painter: WavePainter(
animation: 0.0,
color: AppColor.white.withOpacity(0.08),
),
),
),
// Radial gradient overlay
Container(
decoration: BoxDecoration(
gradient: RadialGradient(
center: const Alignment(0.7, -0.5),
radius: 1.4,
colors: [
Colors.white.withOpacity(0.06),
Colors.transparent,
],
),
),
),
],
),
),
// --- Content ---
Padding(
padding: padding ?? const EdgeInsets.all(16),
child: child,
),
],
),
),
);
}
Widget _circle(double size, Color color, double opacity) {
return Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color.withOpacity(opacity),
),
);
}
List<Widget> _sparkles(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return List.generate(5, (i) {
return Positioned(
left: (i * 70.0) % (width - 20),
top: 10 + (i * 18.0),
child: Icon(
Icons.auto_awesome,
size: 8 + (i % 3) * 3.0,
color: AppColor.white.withOpacity(0.18),
),
);
});
}
}

Some files were not shown because too many files have changed in this diff Show More