Merge branch 'dev' into authentication-web
This commit is contained in:
10
.gitignore
vendored
10
.gitignore
vendored
@@ -18,7 +18,6 @@ $RECYCLE.BIN/
|
||||
|
||||
# IDE & Editors
|
||||
.idea/
|
||||
.vscode/
|
||||
*.iml
|
||||
*.iws
|
||||
*.swp
|
||||
@@ -111,6 +110,9 @@ vite.config.ts.timestamp-*
|
||||
.flutter-plugins
|
||||
.flutter-plugins-dependencies
|
||||
|
||||
# Firebase Data Connect Generated SDK (regenerated via make mobile-install)
|
||||
**/dataconnect_generated/
|
||||
|
||||
# Android
|
||||
.gradle/
|
||||
**/android/app/libs/
|
||||
@@ -127,6 +129,12 @@ build/
|
||||
**/ios/Pods/
|
||||
**/ios/.symlinks/
|
||||
|
||||
# Ephemeral files (generated by Flutter for desktop platforms)
|
||||
**/linux/flutter/ephemeral/
|
||||
**/windows/flutter/ephemeral/
|
||||
**/macos/Flutter/ephemeral/
|
||||
**/ios/Flutter/ephemeral/
|
||||
|
||||
# ==============================================================================
|
||||
# FIREBASE & BACKEND
|
||||
# ==============================================================================
|
||||
|
||||
41
.vscode/launch.json
vendored
Normal file
41
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Client (Dev) - Android",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"program": "apps/mobile/apps/client/lib/main.dart",
|
||||
"args": [
|
||||
"--dart-define-from-file=${workspaceFolder}/apps/mobile/config.dev.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Client (Dev) - iOS",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"program": "apps/mobile/apps/client/lib/main.dart",
|
||||
"args": [
|
||||
"--dart-define-from-file=${workspaceFolder}/apps/mobile/config.dev.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Staff (Dev) - Android",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"program": "apps/mobile/apps/staff/lib/main.dart",
|
||||
"args": [
|
||||
"--dart-define-from-file=${workspaceFolder}/apps/mobile/config.dev.json"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Staff (Dev) - iOS",
|
||||
"request": "launch",
|
||||
"type": "dart",
|
||||
"program": "apps/mobile/apps/staff/lib/main.dart",
|
||||
"args": [
|
||||
"--dart-define-from-file=${workspaceFolder}/apps/mobile/config.dev.json"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -47,3 +47,11 @@
|
||||
- On app launch, check whether there is an active session. If a valid session exists, skip the auth flow and navigate directly to Home, loading Staff account.
|
||||
- Add an expiration time (TTL) to the session (store expiresAt / expiryTimestamp) and invalidate/clear the session when it has expired.
|
||||
- For staffs Skills = Roles? thinking in the future for the smart assigned that need to know the roles of staff to assign.
|
||||
|
||||
## App
|
||||
- Staff Application
|
||||
|
||||
### Github issue
|
||||
- https://github.com/Oloodi/krow-workforce/issues/248
|
||||
### Deveations:
|
||||
- Assumed that a worker can only have one shift per day.
|
||||
|
||||
129
CLAUDE.md
Normal file
129
CLAUDE.md
Normal file
@@ -0,0 +1,129 @@
|
||||
# CLAUDE.md - Project Context for AI Assistants
|
||||
|
||||
This file provides context for Claude Code and other AI assistants working on this codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**KROW Workforce** is a workforce management platform connecting businesses with temporary/on-demand workers. It consists of:
|
||||
- **Client App**: For businesses to create orders, manage hubs, handle billing
|
||||
- **Staff App**: For workers to manage availability, clock in/out, view earnings
|
||||
- **Web Dashboard**: Admin portal (React/Vite - WIP)
|
||||
- **Backend**: Firebase Data Connect + PostgreSQL on Cloud SQL
|
||||
|
||||
## Monorepo Structure
|
||||
|
||||
```
|
||||
/apps
|
||||
/mobile # Flutter apps (managed by Melos)
|
||||
/apps
|
||||
/client # krowwithus_client - Business app
|
||||
/staff # krowwithus_staff - Worker app
|
||||
/design_system_viewer
|
||||
/packages
|
||||
/core # Base utilities
|
||||
/domain # Business entities, repository interfaces
|
||||
/data_connect # Data layer, Firebase Data Connect SDK
|
||||
/design_system # Shared UI components
|
||||
/core_localization # i18n (Slang)
|
||||
/features
|
||||
/client/* # Client-specific features
|
||||
/staff/* # Staff-specific features
|
||||
/web-dashboard # React web app (WIP)
|
||||
/backend
|
||||
/dataconnect # GraphQL schemas, Firebase Data Connect config
|
||||
/cloud-functions # Serverless functions (placeholder)
|
||||
/internal
|
||||
/launchpad # Internal DevOps portal
|
||||
/api-harness # API testing tool
|
||||
/makefiles # Modular Make targets
|
||||
/docs # Project documentation
|
||||
```
|
||||
|
||||
## Key Commands
|
||||
|
||||
### Mobile Development
|
||||
```bash
|
||||
# Install dependencies
|
||||
make mobile-install
|
||||
|
||||
# Run client app (specify your device ID)
|
||||
make mobile-client-dev-android DEVICE=<device_id>
|
||||
|
||||
# Run staff app
|
||||
make mobile-staff-dev-android DEVICE=<device_id>
|
||||
|
||||
# Find your device ID
|
||||
flutter devices
|
||||
|
||||
# Build APK
|
||||
make mobile-client-build PLATFORM=apk
|
||||
make mobile-staff-build PLATFORM=apk
|
||||
|
||||
# Code generation (localization + build_runner)
|
||||
cd apps/mobile && melos run gen:all
|
||||
```
|
||||
|
||||
### Web Development
|
||||
```bash
|
||||
make install # Install web dependencies
|
||||
make dev # Run web dev server
|
||||
```
|
||||
|
||||
### Data Connect
|
||||
```bash
|
||||
make dataconnect-sync # Deploy schemas, migrate, regenerate SDK
|
||||
```
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
- **State Management**: BLoC pattern (flutter_bloc)
|
||||
- **Navigation**: Flutter Modular
|
||||
- **Architecture**: Clean Architecture (domain/data/presentation layers)
|
||||
- **Feature Organization**: Each feature is a separate package
|
||||
- **Value Objects**: Equatable for entity equality
|
||||
|
||||
## Code Conventions
|
||||
|
||||
- Features go in `/apps/mobile/packages/features/{client|staff}/`
|
||||
- Shared code goes in `/apps/mobile/packages/{core|domain|data_connect}/`
|
||||
- UI components go in `/apps/mobile/packages/design_system/`
|
||||
- GraphQL schemas go in `/backend/dataconnect/schema/`
|
||||
- Documentation language: **English**
|
||||
|
||||
## Important Files
|
||||
|
||||
- `apps/mobile/melos.yaml` - Melos workspace config
|
||||
- `makefiles/mobile.mk` - Mobile Make targets
|
||||
- `backend/dataconnect/dataconnect.yaml` - Data Connect config
|
||||
- `firebase.json` - Firebase hosting/emulator config
|
||||
- `BLOCKERS.md` - Known blockers and deviations
|
||||
|
||||
## Branch Protection
|
||||
|
||||
- `main` and `dev` branches are protected
|
||||
- Always create feature branches: `feature/`, `fix/`, `chore/`
|
||||
- PRs required for merging
|
||||
|
||||
## Testing Mobile Apps
|
||||
|
||||
1. Connect your Android device or start emulator
|
||||
2. Run `flutter devices` to get device ID
|
||||
3. Run `make mobile-client-dev-android DEVICE=<your_device_id>`
|
||||
|
||||
## Common Issues
|
||||
|
||||
### "No devices found with name 'android'"
|
||||
The Makefile defaults to device ID `android`. Override with your actual device:
|
||||
```bash
|
||||
make mobile-client-dev-android DEVICE=3fb285a7
|
||||
```
|
||||
|
||||
### Dependency resolution issues
|
||||
```bash
|
||||
cd apps/mobile && melos clean && melos bootstrap
|
||||
```
|
||||
|
||||
### Code generation out of sync
|
||||
```bash
|
||||
cd apps/mobile && melos run gen:all
|
||||
```
|
||||
138
GEMINI.md
Normal file
138
GEMINI.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# GEMINI.md - Project Context for AI Assistants
|
||||
|
||||
This file provides context for Gemini and other AI assistants working on this codebase.
|
||||
|
||||
## Project Overview
|
||||
|
||||
**KROW Workforce** is a workforce management platform connecting businesses with temporary/on-demand workers. It consists of:
|
||||
- **Client App**: For businesses to create orders, manage hubs, handle billing
|
||||
- **Staff App**: For workers to manage availability, clock in/out, view earnings
|
||||
- **Web Dashboard**: Admin portal (React/Vite - WIP)
|
||||
- **Backend**: Firebase Data Connect + PostgreSQL on Cloud SQL
|
||||
|
||||
## Monorepo Structure
|
||||
|
||||
```
|
||||
/apps
|
||||
/mobile # Flutter apps (managed by Melos)
|
||||
/apps
|
||||
/client # krowwithus_client - Business app
|
||||
/staff # krowwithus_staff - Worker app
|
||||
/design_system_viewer
|
||||
/packages
|
||||
/core # Base utilities
|
||||
/domain # Business entities, repository interfaces
|
||||
/data_connect # Data layer, Firebase Data Connect SDK
|
||||
/design_system # Shared UI components
|
||||
/core_localization # i18n (Slang)
|
||||
/features
|
||||
/client/* # Client-specific features
|
||||
/staff/* # Staff-specific features
|
||||
/web-dashboard # React web app (WIP)
|
||||
/backend
|
||||
/dataconnect # GraphQL schemas, Firebase Data Connect config
|
||||
/cloud-functions # Serverless functions (placeholder)
|
||||
/internal
|
||||
/launchpad # Internal DevOps portal
|
||||
/api-harness # API testing tool
|
||||
/makefiles # Modular Make targets
|
||||
/docs # Project documentation
|
||||
/bugs # Bug reports and screenshots
|
||||
```
|
||||
|
||||
## Key Commands
|
||||
|
||||
### Mobile Development
|
||||
```bash
|
||||
# Install dependencies
|
||||
make mobile-install
|
||||
|
||||
# Run client app (specify your device ID)
|
||||
make mobile-client-dev-android DEVICE=<device_id>
|
||||
|
||||
# Run staff app
|
||||
make mobile-staff-dev-android DEVICE=<device_id>
|
||||
|
||||
# Find your device ID
|
||||
flutter devices
|
||||
|
||||
# Build APK
|
||||
make mobile-client-build PLATFORM=apk
|
||||
make mobile-staff-build PLATFORM=apk
|
||||
|
||||
# Code generation (localization + build_runner)
|
||||
cd apps/mobile && melos run gen:all
|
||||
```
|
||||
|
||||
### Web Development
|
||||
```bash
|
||||
make install # Install web dependencies
|
||||
make dev # Run web dev server
|
||||
```
|
||||
|
||||
### Data Connect
|
||||
```bash
|
||||
make dataconnect-sync # Deploy schemas, migrate, regenerate SDK
|
||||
```
|
||||
|
||||
## Architecture Patterns
|
||||
|
||||
- **State Management**: BLoC pattern (flutter_bloc)
|
||||
- **Navigation**: Flutter Modular
|
||||
- **Architecture**: Clean Architecture (domain/data/presentation layers)
|
||||
- **Feature Organization**: Each feature is a separate package
|
||||
- **Value Objects**: Equatable for entity equality
|
||||
|
||||
## Code Conventions
|
||||
|
||||
- Features go in `/apps/mobile/packages/features/{client|staff}/`
|
||||
- Shared code goes in `/apps/mobile/packages/{core|domain|data_connect}/`
|
||||
- UI components go in `/apps/mobile/packages/design_system/`
|
||||
- GraphQL schemas go in `/backend/dataconnect/schema/`
|
||||
- Documentation language: **English**
|
||||
|
||||
## Important Files
|
||||
|
||||
- `apps/mobile/melos.yaml` - Melos workspace config
|
||||
- `makefiles/mobile.mk` - Mobile Make targets
|
||||
- `backend/dataconnect/dataconnect.yaml` - Data Connect config
|
||||
- `firebase.json` - Firebase hosting/emulator config
|
||||
- `BLOCKERS.md` - Known blockers and deviations
|
||||
- `bugs/BUG-REPORT-*.md` - Bug reports with analysis
|
||||
|
||||
## Branch Protection
|
||||
|
||||
- `main` and `dev` branches are protected
|
||||
- Always create feature branches: `feature/`, `fix/`, `chore/`
|
||||
- PRs required for merging
|
||||
|
||||
## Testing Mobile Apps
|
||||
|
||||
1. Connect your Android device or start emulator
|
||||
2. Run `flutter devices` to get device ID
|
||||
3. Run `make mobile-client-dev-android DEVICE=<your_device_id>`
|
||||
|
||||
## Common Issues
|
||||
|
||||
### "No devices found with name 'android'"
|
||||
The Makefile defaults to device ID `android`. Override with your actual device:
|
||||
```bash
|
||||
make mobile-client-dev-android DEVICE=3fb285a7
|
||||
```
|
||||
|
||||
### Dependency resolution issues
|
||||
```bash
|
||||
cd apps/mobile && melos clean && melos bootstrap
|
||||
```
|
||||
|
||||
### Code generation out of sync
|
||||
```bash
|
||||
cd apps/mobile && melos run gen:all
|
||||
```
|
||||
|
||||
## Known Technical Debt
|
||||
|
||||
See `bugs/BUG-REPORT-*.md` for detailed analysis of:
|
||||
- Authentication/User sync issues
|
||||
- Error handling architecture (needs AppException pattern)
|
||||
- BLoC state management patterns (copyWith null handling)
|
||||
74
Makefile
74
Makefile
@@ -17,9 +17,9 @@ include makefiles/tools.mk
|
||||
.PHONY: help
|
||||
|
||||
help:
|
||||
@echo "--------------------------------------------------"
|
||||
@echo " KROW Workforce - Available Makefile Commands"
|
||||
@echo "--------------------------------------------------"
|
||||
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
@echo " 🚀 KROW Workforce - Available Makefile Commands"
|
||||
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
@echo ""
|
||||
@echo " --- WEB APP DEVELOPMENT ---"
|
||||
@echo " make web-install - Installs web frontend dependencies."
|
||||
@@ -29,31 +29,53 @@ help:
|
||||
@echo " make web-lint - Runs linter for web frontend."
|
||||
@echo " make web-preview - Previews the web frontend build."
|
||||
@echo " make launchpad-dev - Starts the local launchpad server (Firebase Hosting emulator)."
|
||||
@echo " 📦 WEB FRONTEND (internal/api-harness)"
|
||||
@echo " ────────────────────────────────────────────────────────────────────"
|
||||
@echo " make install Install web frontend dependencies"
|
||||
@echo " make dev Start local web frontend dev server"
|
||||
@echo " make build Build web frontend for production"
|
||||
@echo " make deploy-app [ENV=dev] Build and deploy web app (dev/staging/prod)"
|
||||
@echo ""
|
||||
@echo " --- MOBILE APP DEVELOPMENT ---"
|
||||
@echo " make mobile-install - Bootstrap the mobile workspace (Melos)."
|
||||
@echo " make mobile-info - List custom mobile development commands."
|
||||
@echo " make mobile-client-dev-android - Run client app in dev mode (Android)."
|
||||
@echo " make mobile-client-build PLATFORM=apk - Build client app for specified platform."
|
||||
@echo " make mobile-staff-dev-android - Run staff app in dev mode (Android)."
|
||||
@echo " make mobile-staff-build PLATFORM=apk - Build staff app for specified platform."
|
||||
@echo " 🏠 LAUNCHPAD (internal/launchpad)"
|
||||
@echo " ────────────────────────────────────────────────────────────────────"
|
||||
@echo " make launchpad-dev Start launchpad dev server (Firebase Hosting)"
|
||||
@echo " make deploy-launchpad-hosting Deploy launchpad to Firebase Hosting"
|
||||
@echo ""
|
||||
@echo " --- DEPLOYMENT ---"
|
||||
@echo " make deploy-launchpad-hosting - Deploys internal launchpad to Firebase Hosting."
|
||||
@echo " make deploy-app [ENV=staging] - Builds and deploys the main web app (default: dev)."
|
||||
@echo " 📱 MOBILE APPS (apps/mobile)"
|
||||
@echo " ────────────────────────────────────────────────────────────────────"
|
||||
@echo " make mobile-install Bootstrap mobile workspace + SDK"
|
||||
@echo " make mobile-info List mobile development commands"
|
||||
@echo " make mobile-client-dev-android [DEVICE=android] Run client app (Android)"
|
||||
@echo " make mobile-client-build PLATFORM=apk Build client app (apk/ipa/etc)"
|
||||
@echo " make mobile-staff-dev-android [DEVICE=android] Run staff app (Android)"
|
||||
@echo " make mobile-staff-build PLATFORM=apk Build staff app (apk/ipa/etc)"
|
||||
@echo " make mobile-hot-reload Hot reload running Flutter app"
|
||||
@echo " make mobile-hot-restart Hot restart running Flutter app"
|
||||
@echo ""
|
||||
@echo " --- DEVELOPMENT TOOLS ---"
|
||||
@echo " make install-melos - Installs Melos globally if not already present."
|
||||
@echo " make install-git-hooks - Installs git pre-push hook to protect main/dev branches."
|
||||
@echo " make sync-prototypes - Builds and copies prototypes from adjacent 'client-krow-poc' repo."
|
||||
@echo " 🗄️ DATA CONNECT & BACKEND (backend/dataconnect)"
|
||||
@echo " ────────────────────────────────────────────────────────────────────"
|
||||
@echo " make dataconnect-init Initialize Firebase Data Connect"
|
||||
@echo " make dataconnect-deploy Deploy Data Connect schemas to Cloud SQL"
|
||||
@echo " make dataconnect-sql-migrate Apply pending SQL migrations"
|
||||
@echo " make dataconnect-generate-sdk Regenerate Data Connect client SDK"
|
||||
@echo " make dataconnect-sync Full sync: deploy + migrate + generate SDK"
|
||||
@echo " make dataconnect-seed Seed database with test data"
|
||||
@echo " make dataconnect-clean Delete all data from Data Connect"
|
||||
@echo " make dataconnect-test Test Data Connect deployment (dry-run)"
|
||||
@echo " make dataconnect-enable-apis Enable required GCP APIs"
|
||||
@echo " make dataconnect-bootstrap-db ONE-TIME: Full Cloud SQL + Data Connect setup"
|
||||
@echo ""
|
||||
@echo " --- DATA CONNECT MANAGEMENT ---"
|
||||
@echo " make dataconnect-init - Initializes Firebase Data Connect."
|
||||
@echo " make dataconnect-deploy - Deploys Data Connect schemas."
|
||||
@echo " make dataconnect-sql-migrate - Applies SQL migrations."
|
||||
@echo " make dataconnect-generate-sdk - Regenerates the Data Connect SDK."
|
||||
@echo " make dataconnect-sync - Runs migrate + deploy + generate-sdk."
|
||||
@echo " make dataconnect-bootstrap-db - ONE-TIME: Full Cloud SQL + Data Connect setup."
|
||||
@echo " 🛠️ DEVELOPMENT TOOLS"
|
||||
@echo " ────────────────────────────────────────────────────────────────────"
|
||||
@echo " make install-melos Install Melos globally (for mobile dev)"
|
||||
@echo " make install-git-hooks Install git pre-push hook (protect main/dev)"
|
||||
@echo " make sync-prototypes Sync prototypes from client-krow-poc repo"
|
||||
@echo ""
|
||||
@echo " make help - Shows this help message."
|
||||
@echo "--------------------------------------------------"
|
||||
@echo " ℹ️ HELP"
|
||||
@echo " ────────────────────────────────────────────────────────────────────"
|
||||
@echo " make help Show this help message"
|
||||
@echo ""
|
||||
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
@echo " 💡 Tip: Run 'make mobile-install' first for mobile development"
|
||||
@echo " 💡 Tip: Use 'make dataconnect-sync' after schema changes"
|
||||
@echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
||||
18
apps/mobile/NEXT_SPRINT_TASKS.md
Normal file
18
apps/mobile/NEXT_SPRINT_TASKS.md
Normal file
@@ -0,0 +1,18 @@
|
||||
## Recommended tasks for the next sprint
|
||||
|
||||
|
||||
* In the mobile applications, since the structure is now finalized (at least for the existing features), we need to **strictly follow best practices while coding**:
|
||||
|
||||
* Break down large widgets into **smaller, reusable widgets**
|
||||
* Add **doc comments** where necessary to improve readability and maintainability
|
||||
* **Remove overly complicated or unnecessary logic** introduced by AI and simplify where possible
|
||||
* **Adhere to the design system** and remove all **hard-coded colors and typography**, using shared tokens instead
|
||||
|
||||
* Improvement points
|
||||
- apps/mobile/packages/features/client/client_coverage/lib/src/data/repositories_impl/coverage_repository_impl.dart
|
||||
- Fix the location field in CoverageShiftRole to use the correct fallback logic.
|
||||
- line 125 remove redundant location values.
|
||||
- Need to clarify the difference b/w `case dc.ApplicationStatus.ACCEPTED` and `case dc.ApplicationStatus.CONFIRMED`.
|
||||
- Update the dataconnect docs.
|
||||
- Track `lat` and `lng` in the staff preferred work locations (for now we are only storing the name).
|
||||
- Remove "Up Next (x)" counter from orders list in client app as it is confusing, becase the tab already has a badge showing the number of the upcoming orders.
|
||||
@@ -27,32 +27,43 @@ The project is organized into modular packages to ensure separation of concerns
|
||||
Ensure you have the Flutter SDK installed and configured.
|
||||
|
||||
### 2. Initial Setup
|
||||
Run the following command from the **project root** to install Melos, bootstrap all packages, and generate localization files:
|
||||
Run the following command from the **project root** to install Melos, bootstrap all packages, generate localization files, and generate the Firebase Data Connect SDK:
|
||||
|
||||
```bash
|
||||
# Using Makefile
|
||||
# Using Makefile (Recommended)
|
||||
make mobile-install
|
||||
# Using Melos
|
||||
melos bootstrap
|
||||
```
|
||||
|
||||
This command will:
|
||||
- Install Melos if not already installed
|
||||
- Generate the Firebase Data Connect SDK from schema files
|
||||
- Bootstrap all packages (install dependencies)
|
||||
- Generate localization files
|
||||
|
||||
**Note:** The Firebase Data Connect SDK files (`dataconnect_generated/`) are auto-generated and not committed to the repository. They will be regenerated automatically when you run `make mobile-install` or any mobile development commands.
|
||||
|
||||
### 3. Running the Apps
|
||||
You can run the applications using Melos scripts or through the `Makefile`:
|
||||
|
||||
First, find your device ID:
|
||||
```bash
|
||||
flutter devices
|
||||
```
|
||||
|
||||
#### Client App
|
||||
```bash
|
||||
# Using Melos
|
||||
melos run start:client -d android # or ios
|
||||
# Using Makefile
|
||||
make mobile-client-dev-android
|
||||
melos run start:client -- -d <device_id>
|
||||
# Using Makefile (DEVICE defaults to 'android' if not specified)
|
||||
make mobile-client-dev-android DEVICE=<device_id>
|
||||
```
|
||||
|
||||
#### Staff App
|
||||
```bash
|
||||
# Using Melos
|
||||
melos run start:staff -d android # or ios
|
||||
# Using Makefile
|
||||
make mobile-staff-dev-android
|
||||
melos run start:staff -- -d <device_id>
|
||||
# Using Makefile (DEVICE defaults to 'android' if not specified)
|
||||
make mobile-staff-dev-android DEVICE=<device_id>
|
||||
```
|
||||
|
||||
## 🛠 Useful Commands
|
||||
|
||||
@@ -7,7 +7,7 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.krow_client"
|
||||
namespace = "com.krowwithus.client"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
|
||||
@@ -5,42 +5,6 @@
|
||||
"storage_bucket": "krow-workforce-dev.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:87d41566f8dda41d7757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.example.krow_workforce"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:edcddb83ea4bbb517757db",
|
||||
@@ -67,10 +31,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -103,10 +67,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -121,6 +85,14 @@
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.krowwithus.client",
|
||||
"certificate_hash": "c3efbe1642239c599c16ad04c7fac340902fe280"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
@@ -139,10 +111,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -151,12 +123,20 @@
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:d26bde4ee337b0b17757db",
|
||||
"mobilesdk_app_id": "1:933560802882:android:1ae05d85c865f77c7757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.krowwithus.krow_workforce.dev"
|
||||
"package_name": "com.krowwithus.staff"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-ikdfv3o5f47g36qqgvfq55o4m19n7gk4.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.krowwithus.staff",
|
||||
"certificate_hash": "ac917ae8470ab29f1107c773c6017ff5ea5d102d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
@@ -175,10 +155,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.krow_client
|
||||
package com.krowwithus.client
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
|
||||
1
apps/mobile/apps/client/firebase.json
Normal file
1
apps/mobile/apps/client/firebase.json
Normal file
@@ -0,0 +1 @@
|
||||
{"flutter":{"platforms":{"android":{"default":{"projectId":"krow-workforce-dev","appId":"1:933560802882:android:da13569105659ead7757db","fileOutput":"android/app/google-services.json"}},"ios":{"default":{"projectId":"krow-workforce-dev","appId":"1:933560802882:ios:d2b6d743608e2a527757db","uploadDebugSymbols":false,"fileOutput":"ios/Runner/GoogleService-Info.plist"}},"dart":{"lib/firebase_options.dart":{"projectId":"krow-workforce-dev","configurations":{"android":"1:933560802882:android:da13569105659ead7757db","ios":"1:933560802882:ios:d2b6d743608e2a527757db","web":"1:933560802882:web:173a841992885bb27757db"}}}}}}
|
||||
@@ -1,32 +0,0 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
import lldb
|
||||
|
||||
def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
|
||||
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
|
||||
base = frame.register["x0"].GetValueAsAddress()
|
||||
page_len = frame.register["x1"].GetValueAsUnsigned()
|
||||
|
||||
# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
|
||||
# first page to see if handled it correctly. This makes diagnosing
|
||||
# misconfiguration (e.g. missing breakpoint) easier.
|
||||
data = bytearray(page_len)
|
||||
data[0:8] = b'IHELPED!'
|
||||
|
||||
error = lldb.SBError()
|
||||
frame.GetThread().GetProcess().WriteMemory(base, data, error)
|
||||
if not error.Success():
|
||||
print(f'Failed to write into {base}[+{page_len}]', error)
|
||||
return
|
||||
|
||||
def __lldb_init_module(debugger: lldb.SBDebugger, _):
|
||||
target = debugger.GetDummyTarget()
|
||||
# Caveat: must use BreakpointCreateByRegEx here and not
|
||||
# BreakpointCreateByName. For some reasons callback function does not
|
||||
# get carried over from dummy target for the later.
|
||||
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
|
||||
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
|
||||
bp.SetAutoContinue(True)
|
||||
print("-- LLDB integration loaded --")
|
||||
@@ -1,5 +0,0 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
command script import --relative-to-command-file flutter_lldb_helper.py
|
||||
@@ -14,6 +14,7 @@
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
E8C1A28BFABAEE32FB779C9A /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 221E00B70DE845BE3D50D0A0 /* GoogleService-Info.plist */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
@@ -42,6 +43,7 @@
|
||||
/* Begin PBXFileReference section */
|
||||
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>"; };
|
||||
221E00B70DE845BE3D50D0A0 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; 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; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
@@ -94,6 +96,7 @@
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
221E00B70DE845BE3D50D0A0 /* GoogleService-Info.plist */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -216,6 +219,7 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
E8C1A28BFABAEE32FB779C9A /* GoogleService-Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
36
apps/mobile/apps/client/ios/Runner/GoogleService-Info.plist
Normal file
36
apps/mobile/apps/client/ios/Runner/GoogleService-Info.plist
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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>CLIENT_ID</key>
|
||||
<string>933560802882-jqpv1l3gjmi3m87b2gu1iq4lg46lkdfg.apps.googleusercontent.com</string>
|
||||
<key>REVERSED_CLIENT_ID</key>
|
||||
<string>com.googleusercontent.apps.933560802882-jqpv1l3gjmi3m87b2gu1iq4lg46lkdfg</string>
|
||||
<key>ANDROID_CLIENT_ID</key>
|
||||
<string>933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com</string>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyDyEXkzZAWpXXe4dAesYaZflt5BEtMn9tA</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>933560802882</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>com.krowwithus.client</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>krow-workforce-dev</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>krow-workforce-dev.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:933560802882:ios:d2b6d743608e2a527757db</string>
|
||||
</dict>
|
||||
</plist>
|
||||
78
apps/mobile/apps/client/lib/firebase_options.dart
Normal file
78
apps/mobile/apps/client/lib/firebase_options.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
return web;
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions web = FirebaseOptions(
|
||||
apiKey: 'AIzaSyBqRtZPMGU-Sz5x5UnRrunKu5NSWYyPRn8',
|
||||
appId: '1:933560802882:web:173a841992885bb27757db',
|
||||
messagingSenderId: '933560802882',
|
||||
projectId: 'krow-workforce-dev',
|
||||
authDomain: 'krow-workforce-dev.firebaseapp.com',
|
||||
storageBucket: 'krow-workforce-dev.firebasestorage.app',
|
||||
measurementId: 'G-9S7WEQTDKX',
|
||||
);
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4',
|
||||
appId: '1:933560802882:android:da13569105659ead7757db',
|
||||
messagingSenderId: '933560802882',
|
||||
projectId: 'krow-workforce-dev',
|
||||
storageBucket: 'krow-workforce-dev.firebasestorage.app',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDyEXkzZAWpXXe4dAesYaZflt5BEtMn9tA',
|
||||
appId: '1:933560802882:ios:d2b6d743608e2a527757db',
|
||||
messagingSenderId: '933560802882',
|
||||
projectId: 'krow-workforce-dev',
|
||||
storageBucket: 'krow-workforce-dev.firebasestorage.app',
|
||||
androidClientId: '933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com',
|
||||
iosClientId: '933560802882-jqpv1l3gjmi3m87b2gu1iq4lg46lkdfg.apps.googleusercontent.com',
|
||||
iosBundleId: 'com.krowwithus.client',
|
||||
);
|
||||
|
||||
}
|
||||
@@ -12,10 +12,15 @@ import 'package:client_hubs/client_hubs.dart' as client_hubs;
|
||||
import 'package:client_create_order/client_create_order.dart'
|
||||
as client_create_order;
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
import 'firebase_options.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
await Firebase.initializeApp(
|
||||
options: kIsWeb ? DefaultFirebaseOptions.currentPlatform : null,
|
||||
);
|
||||
runApp(ModularApp(module: AppModule(), child: const AppWidget()));
|
||||
}
|
||||
|
||||
@@ -54,10 +59,12 @@ class AppWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<core_localization.LocaleBloc>(
|
||||
return WebMobileFrame(
|
||||
appName: 'KROW Client\nApplication',
|
||||
logo: Image.asset('assets/logo.png'),
|
||||
child: BlocProvider<core_localization.LocaleBloc>(
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<core_localization.LocaleBloc>()
|
||||
..add(const core_localization.LoadLocale()),
|
||||
Modular.get<core_localization.LocaleBloc>(),
|
||||
child:
|
||||
BlocBuilder<
|
||||
core_localization.LocaleBloc,
|
||||
@@ -83,6 +90,7 @@ class AppWidget extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
|
||||
set(BINARY_NAME "krow_client")
|
||||
# The unique GTK application identifier for this application. See:
|
||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||
set(APPLICATION_ID "com.example.krow_client")
|
||||
set(APPLICATION_ID "com.krowwithus.client")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2/
|
||||
@@ -1,13 +0,0 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=/Users/josesalazar/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/josesalazar/Documents/DEV/krow-workforce/apps/mobile/apps/client
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_TARGET=/Users/josesalazar/Documents/DEV/krow-workforce/apps/mobile/apps/client/lib/main.dart
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=1.0.0
|
||||
FLUTTER_BUILD_NUMBER=1
|
||||
DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzguNw==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049M2I2MmVmYzJhMw==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049NzhmYzMwMTJlNA==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My4xMC43
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=/Users/josesalazar/Documents/DEV/krow-workforce/apps/mobile/.dart_tool/package_config.json
|
||||
@@ -1,14 +0,0 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/josesalazar/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/josesalazar/Documents/DEV/krow-workforce/apps/mobile/apps/client"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_TARGET=/Users/josesalazar/Documents/DEV/krow-workforce/apps/mobile/apps/client/lib/main.dart"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=1.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=1"
|
||||
export "DART_DEFINES=RkxVVFRFUl9WRVJTSU9OPTMuMzguNw==,RkxVVFRFUl9DSEFOTkVMPXN0YWJsZQ==,RkxVVFRFUl9HSVRfVVJMPWh0dHBzOi8vZ2l0aHViLmNvbS9mbHV0dGVyL2ZsdXR0ZXIuZ2l0,RkxVVFRFUl9GUkFNRVdPUktfUkVWSVNJT049M2I2MmVmYzJhMw==,RkxVVFRFUl9FTkdJTkVfUkVWSVNJT049NzhmYzMwMTJlNA==,RkxVVFRFUl9EQVJUX1ZFUlNJT049My4xMC43"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=/Users/josesalazar/Documents/DEV/krow-workforce/apps/mobile/.dart_tool/package_config.json"
|
||||
@@ -1,11 +1,11 @@
|
||||
name: krowwithus_client
|
||||
description: "Krow Client Application"
|
||||
publish_to: "none"
|
||||
version: 0.0.1-M+301
|
||||
version: 0.0.1-M3+5
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.7
|
||||
sdk: '>=3.10.0 <4.0.0'
|
||||
|
||||
dependencies:
|
||||
flutter:
|
||||
@@ -32,6 +32,8 @@ dependencies:
|
||||
path: ../../packages/features/client/hubs
|
||||
client_create_order:
|
||||
path: ../../packages/features/client/create_order
|
||||
krow_core:
|
||||
path: ../../packages/core
|
||||
|
||||
cupertino_icons: ^1.0.8
|
||||
flutter_modular: ^6.3.2
|
||||
|
||||
@@ -33,6 +33,29 @@
|
||||
<link rel="manifest" href="manifest.json">
|
||||
</head>
|
||||
<body>
|
||||
<script type="module">
|
||||
// Import the functions you need from the SDKs you need
|
||||
import { initializeApp } from "https://www.gstatic.com/firebasejs/12.8.0/firebase-app.js";
|
||||
import { getAnalytics } from "https://www.gstatic.com/firebasejs/12.8.0/firebase-analytics.js";
|
||||
// TODO: Add SDKs for Firebase products that you want to use
|
||||
// https://firebase.google.com/docs/web/setup#available-libraries
|
||||
|
||||
// Your web app's Firebase configuration
|
||||
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyBqRtZPMGU-Sz5x5UnRrunKu5NSWYyPRn8",
|
||||
authDomain: "krow-workforce-dev.firebaseapp.com",
|
||||
projectId: "krow-workforce-dev",
|
||||
storageBucket: "krow-workforce-dev.firebasestorage.app",
|
||||
messagingSenderId: "933560802882",
|
||||
appId: "1:933560802882:web:173a841992885bb27757db",
|
||||
measurementId: "G-9S7WEQTDKX"
|
||||
};
|
||||
|
||||
// Initialize Firebase
|
||||
const app = initializeApp(firebaseConfig);
|
||||
const analytics = getAnalytics(app);
|
||||
</script>
|
||||
<script src="flutter_bootstrap.js" async></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_auth-6.1.4/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_core-4.4.0/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5/
|
||||
@@ -1,32 +0,0 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
import lldb
|
||||
|
||||
def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
|
||||
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
|
||||
base = frame.register["x0"].GetValueAsAddress()
|
||||
page_len = frame.register["x1"].GetValueAsUnsigned()
|
||||
|
||||
# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
|
||||
# first page to see if handled it correctly. This makes diagnosing
|
||||
# misconfiguration (e.g. missing breakpoint) easier.
|
||||
data = bytearray(page_len)
|
||||
data[0:8] = b'IHELPED!'
|
||||
|
||||
error = lldb.SBError()
|
||||
frame.GetThread().GetProcess().WriteMemory(base, data, error)
|
||||
if not error.Success():
|
||||
print(f'Failed to write into {base}[+{page_len}]', error)
|
||||
return
|
||||
|
||||
def __lldb_init_module(debugger: lldb.SBDebugger, _):
|
||||
target = debugger.GetDummyTarget()
|
||||
# Caveat: must use BreakpointCreateByRegEx here and not
|
||||
# BreakpointCreateByName. For some reasons callback function does not
|
||||
# get carried over from dummy target for the later.
|
||||
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
|
||||
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
|
||||
bp.SetAutoContinue(True)
|
||||
print("-- LLDB integration loaded --")
|
||||
@@ -1,5 +0,0 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
command script import --relative-to-command-file flutter_lldb_helper.py
|
||||
@@ -1,11 +0,0 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=/Users/achinthaisuru/Documents/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/achinthaisuru/Documents/Github/krow-workforce/apps/mobile/apps/design_system_viewer
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=1.0.0
|
||||
FLUTTER_BUILD_NUMBER=1
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=.dart_tool/package_config.json
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/achinthaisuru/Documents/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/achinthaisuru/Documents/Github/krow-workforce/apps/mobile/apps/design_system_viewer"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=1.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=1"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=.dart_tool/package_config.json"
|
||||
@@ -16,11 +16,11 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
|
||||
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
|
||||
# In Windows, build-name is used as the major, minor, and patch parts
|
||||
# of the product and file versions while build-number is used as the build suffix.
|
||||
version: 1.0.0+1
|
||||
version: 0.0.1
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.7
|
||||
sdk: '>=3.10.0 <4.0.0'
|
||||
|
||||
# Dependencies specify other packages that your package needs in order to work.
|
||||
# To automatically upgrade your package dependencies to the latest versions
|
||||
|
||||
@@ -7,7 +7,7 @@ plugins {
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "com.example.krow_staff"
|
||||
namespace = "com.krowwithus.staff"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
|
||||
@@ -5,42 +5,6 @@
|
||||
"storage_bucket": "krow-workforce-dev.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:87d41566f8dda41d7757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.example.krow_workforce"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:edcddb83ea4bbb517757db",
|
||||
@@ -67,10 +31,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -103,10 +67,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -122,41 +86,13 @@
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"client_id": "933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.krowwithus.client",
|
||||
"certificate_hash": "c3efbe1642239c599c16ad04c7fac340902fe280"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:d26bde4ee337b0b17757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.krowwithus.krow_workforce.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
@@ -175,10 +111,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -193,6 +129,14 @@
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-ikdfv3o5f47g36qqgvfq55o4m19n7gk4.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.krowwithus.staff",
|
||||
"certificate_hash": "ac917ae8470ab29f1107c773c6017ff5ea5d102d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
@@ -211,10 +155,10 @@
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_id": "933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
"bundle_id": "com.krowwithus.staff"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
162
apps/mobile/apps/staff/android/app/google-services.json_back
Normal file
162
apps/mobile/apps/staff/android/app/google-services.json_back
Normal file
@@ -0,0 +1,162 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "933560802882",
|
||||
"project_id": "krow-workforce-dev",
|
||||
"storage_bucket": "krow-workforce-dev.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:edcddb83ea4bbb517757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.krow.app.business.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:d49b8c0f4d19e95e7757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.krow.app.staff.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:da13569105659ead7757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.krowwithus.client"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:933560802882:android:1ae05d85c865f77c7757db",
|
||||
"android_client_info": {
|
||||
"package_name": "com.krowwithus.staff"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-ikdfv3o5f47g36qqgvfq55o4m19n7gk4.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "com.krowwithus.staff",
|
||||
"certificate_hash": "ac917ae8470ab29f1107c773c6017ff5ea5d102d"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "933560802882-grp98a1v7amflnnup68vh01tj06eaem1.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
},
|
||||
{
|
||||
"client_id": "933560802882-dppsapp5i3lsfrlm1mhob2s21peofg1t.apps.googleusercontent.com",
|
||||
"client_type": 2,
|
||||
"ios_info": {
|
||||
"bundle_id": "com.krow.app.staff.dev"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
@@ -30,11 +30,21 @@ public final class GeneratedPluginRegistrant {
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error registering plugin firebase_core, io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin", e);
|
||||
}
|
||||
try {
|
||||
flutterEngine.getPlugins().add(new com.baseflow.geolocator.GeolocatorPlugin());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error registering plugin geolocator_android, com.baseflow.geolocator.GeolocatorPlugin", e);
|
||||
}
|
||||
try {
|
||||
flutterEngine.getPlugins().add(new io.flutter.plugins.pathprovider.PathProviderPlugin());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error registering plugin path_provider_android, io.flutter.plugins.pathprovider.PathProviderPlugin", e);
|
||||
}
|
||||
try {
|
||||
flutterEngine.getPlugins().add(new com.baseflow.permissionhandler.PermissionHandlerPlugin());
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error registering plugin permission_handler_android, com.baseflow.permissionhandler.PermissionHandlerPlugin", e);
|
||||
}
|
||||
try {
|
||||
flutterEngine.getPlugins().add(new io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin());
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package com.example.krow_staff
|
||||
package com.krowwithus.staff
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
import lldb
|
||||
|
||||
def handle_new_rx_page(frame: lldb.SBFrame, bp_loc, extra_args, intern_dict):
|
||||
"""Intercept NOTIFY_DEBUGGER_ABOUT_RX_PAGES and touch the pages."""
|
||||
base = frame.register["x0"].GetValueAsAddress()
|
||||
page_len = frame.register["x1"].GetValueAsUnsigned()
|
||||
|
||||
# Note: NOTIFY_DEBUGGER_ABOUT_RX_PAGES will check contents of the
|
||||
# first page to see if handled it correctly. This makes diagnosing
|
||||
# misconfiguration (e.g. missing breakpoint) easier.
|
||||
data = bytearray(page_len)
|
||||
data[0:8] = b'IHELPED!'
|
||||
|
||||
error = lldb.SBError()
|
||||
frame.GetThread().GetProcess().WriteMemory(base, data, error)
|
||||
if not error.Success():
|
||||
print(f'Failed to write into {base}[+{page_len}]', error)
|
||||
return
|
||||
|
||||
def __lldb_init_module(debugger: lldb.SBDebugger, _):
|
||||
target = debugger.GetDummyTarget()
|
||||
# Caveat: must use BreakpointCreateByRegEx here and not
|
||||
# BreakpointCreateByName. For some reasons callback function does not
|
||||
# get carried over from dummy target for the later.
|
||||
bp = target.BreakpointCreateByRegex("^NOTIFY_DEBUGGER_ABOUT_RX_PAGES$")
|
||||
bp.SetScriptCallbackFunction('{}.handle_new_rx_page'.format(__name__))
|
||||
bp.SetAutoContinue(True)
|
||||
print("-- LLDB integration loaded --")
|
||||
@@ -1,5 +0,0 @@
|
||||
#
|
||||
# Generated file, do not edit.
|
||||
#
|
||||
|
||||
command script import --relative-to-command-file flutter_lldb_helper.py
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
1E967D034ADA3A16EF82CB3E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 9F0B07DEC91B141354438F79 /* GoogleService-Info.plist */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
@@ -55,6 +56,7 @@
|
||||
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>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
9F0B07DEC91B141354438F79 /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -94,6 +96,7 @@
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
9F0B07DEC91B141354438F79 /* GoogleService-Info.plist */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
@@ -216,6 +219,7 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
1E967D034ADA3A16EF82CB3E /* GoogleService-Info.plist in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -24,6 +24,18 @@
|
||||
@import firebase_core;
|
||||
#endif
|
||||
|
||||
#if __has_include(<geolocator_apple/GeolocatorPlugin.h>)
|
||||
#import <geolocator_apple/GeolocatorPlugin.h>
|
||||
#else
|
||||
@import geolocator_apple;
|
||||
#endif
|
||||
|
||||
#if __has_include(<permission_handler_apple/PermissionHandlerPlugin.h>)
|
||||
#import <permission_handler_apple/PermissionHandlerPlugin.h>
|
||||
#else
|
||||
@import permission_handler_apple;
|
||||
#endif
|
||||
|
||||
#if __has_include(<shared_preferences_foundation/SharedPreferencesPlugin.h>)
|
||||
#import <shared_preferences_foundation/SharedPreferencesPlugin.h>
|
||||
#else
|
||||
@@ -36,6 +48,8 @@
|
||||
[FLTFirebaseAppCheckPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAppCheckPlugin"]];
|
||||
[FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]];
|
||||
[FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]];
|
||||
[GeolocatorPlugin registerWithRegistrar:[registry registrarForPlugin:@"GeolocatorPlugin"]];
|
||||
[PermissionHandlerPlugin registerWithRegistrar:[registry registrarForPlugin:@"PermissionHandlerPlugin"]];
|
||||
[SharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"SharedPreferencesPlugin"]];
|
||||
}
|
||||
|
||||
|
||||
36
apps/mobile/apps/staff/ios/Runner/GoogleService-Info.plist
Normal file
36
apps/mobile/apps/staff/ios/Runner/GoogleService-Info.plist
Normal file
@@ -0,0 +1,36 @@
|
||||
<?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>CLIENT_ID</key>
|
||||
<string>933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com</string>
|
||||
<key>REVERSED_CLIENT_ID</key>
|
||||
<string>com.googleusercontent.apps.933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh</string>
|
||||
<key>ANDROID_CLIENT_ID</key>
|
||||
<string>933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com</string>
|
||||
<key>API_KEY</key>
|
||||
<string>AIzaSyDyEXkzZAWpXXe4dAesYaZflt5BEtMn9tA</string>
|
||||
<key>GCM_SENDER_ID</key>
|
||||
<string>933560802882</string>
|
||||
<key>PLIST_VERSION</key>
|
||||
<string>1</string>
|
||||
<key>BUNDLE_ID</key>
|
||||
<string>com.krowwithus.staff</string>
|
||||
<key>PROJECT_ID</key>
|
||||
<string>krow-workforce-dev</string>
|
||||
<key>STORAGE_BUCKET</key>
|
||||
<string>krow-workforce-dev.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:933560802882:ios:fa584205b356de937757db</string>
|
||||
</dict>
|
||||
</plist>
|
||||
78
apps/mobile/apps/staff/lib/firebase_options.dart
Normal file
78
apps/mobile/apps/staff/lib/firebase_options.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
// File generated by FlutterFire CLI.
|
||||
|
||||
import 'package:firebase_core/firebase_core.dart' show FirebaseOptions;
|
||||
import 'package:flutter/foundation.dart'
|
||||
show defaultTargetPlatform, kIsWeb, TargetPlatform;
|
||||
|
||||
/// Default [FirebaseOptions] for use with your Firebase apps.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// import 'firebase_options.dart';
|
||||
/// // ...
|
||||
/// await Firebase.initializeApp(
|
||||
/// options: DefaultFirebaseOptions.currentPlatform,
|
||||
/// );
|
||||
/// ```
|
||||
class DefaultFirebaseOptions {
|
||||
static FirebaseOptions get currentPlatform {
|
||||
if (kIsWeb) {
|
||||
return web;
|
||||
}
|
||||
switch (defaultTargetPlatform) {
|
||||
case TargetPlatform.android:
|
||||
return android;
|
||||
case TargetPlatform.iOS:
|
||||
return ios;
|
||||
case TargetPlatform.macOS:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for macos - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.windows:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for windows - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
case TargetPlatform.linux:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions have not been configured for linux - '
|
||||
'you can reconfigure this by running the FlutterFire CLI again.',
|
||||
);
|
||||
default:
|
||||
throw UnsupportedError(
|
||||
'DefaultFirebaseOptions are not supported for this platform.',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static const FirebaseOptions web = FirebaseOptions(
|
||||
apiKey: 'AIzaSyBqRtZPMGU-Sz5x5UnRrunKu5NSWYyPRn8',
|
||||
appId: '1:933560802882:web:173a841992885bb27757db',
|
||||
messagingSenderId: '933560802882',
|
||||
projectId: 'krow-workforce-dev',
|
||||
authDomain: 'krow-workforce-dev.firebaseapp.com',
|
||||
storageBucket: 'krow-workforce-dev.firebasestorage.app',
|
||||
measurementId: 'G-9S7WEQTDKX',
|
||||
);
|
||||
|
||||
static const FirebaseOptions android = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDBYhflhK6DThKnS7RM-9raKdvyKzLUjY4',
|
||||
appId: '1:933560802882:android:1ae05d85c865f77c7757db',
|
||||
messagingSenderId: '933560802882',
|
||||
projectId: 'krow-workforce-dev',
|
||||
storageBucket: 'krow-workforce-dev.firebasestorage.app',
|
||||
);
|
||||
|
||||
static const FirebaseOptions ios = FirebaseOptions(
|
||||
apiKey: 'AIzaSyDyEXkzZAWpXXe4dAesYaZflt5BEtMn9tA',
|
||||
appId: '1:933560802882:ios:fa584205b356de937757db',
|
||||
messagingSenderId: '933560802882',
|
||||
projectId: 'krow-workforce-dev',
|
||||
storageBucket: 'krow-workforce-dev.firebasestorage.app',
|
||||
androidClientId: '933560802882-fbqg2icq24bmci3f84evjrbth5huh87f.apps.googleusercontent.com',
|
||||
iosClientId: '933560802882-29olj9ku64jbe9h7flinha6hbi8qrluh.apps.googleusercontent.com',
|
||||
iosBundleId: 'com.krowwithus.staff',
|
||||
);
|
||||
|
||||
}
|
||||
@@ -1,17 +1,21 @@
|
||||
import 'package:core_localization/core_localization.dart' as core_localization;
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_localizations/flutter_localizations.dart';
|
||||
import 'package:flutter_modular/flutter_modular.dart';
|
||||
import 'package:krowwithus_staff/firebase_options.dart';
|
||||
import 'package:staff_authentication/staff_authentication.dart'
|
||||
as staff_authentication;
|
||||
import 'package:staff_main/staff_main.dart' as staff_main;
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:krow_core/core.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
await Firebase.initializeApp(
|
||||
options: DefaultFirebaseOptions.currentPlatform,
|
||||
);
|
||||
runApp(ModularApp(module: AppModule(), child: const AppWidget()));
|
||||
}
|
||||
|
||||
@@ -34,16 +38,19 @@ class AppWidget extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider<core_localization.LocaleBloc>(
|
||||
return WebMobileFrame(
|
||||
appName: 'KROW Staff\nApplication',
|
||||
logo: Image.asset('assets/logo.png'),
|
||||
child: BlocProvider<core_localization.LocaleBloc>(
|
||||
create: (BuildContext context) =>
|
||||
Modular.get<core_localization.LocaleBloc>()
|
||||
..add(const core_localization.LoadLocale()),
|
||||
Modular.get<core_localization.LocaleBloc>(),
|
||||
child:
|
||||
BlocBuilder<
|
||||
core_localization.LocaleBloc,
|
||||
core_localization.LocaleState
|
||||
>(
|
||||
builder: (BuildContext context, core_localization.LocaleState state) {
|
||||
builder:
|
||||
(BuildContext context, core_localization.LocaleState state) {
|
||||
return core_localization.TranslationProvider(
|
||||
child: MaterialApp.router(
|
||||
title: "KROW Staff",
|
||||
@@ -51,14 +58,17 @@ class AppWidget extends StatelessWidget {
|
||||
routerConfig: Modular.routerConfig,
|
||||
locale: state.locale,
|
||||
supportedLocales: state.supportedLocales,
|
||||
localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
|
||||
localizationsDelegates:
|
||||
const <LocalizationsDelegate<dynamic>>[
|
||||
GlobalMaterialLocalizations.delegate,
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
GlobalCupertinoLocalizations.delegate,
|
||||
],
|
||||
));
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ project(runner LANGUAGES CXX)
|
||||
set(BINARY_NAME "krow_staff")
|
||||
# The unique GTK application identifier for this application. See:
|
||||
# https://wiki.gnome.org/HowDoI/ChooseApplicationID
|
||||
set(APPLICATION_ID "com.example.krow_staff")
|
||||
set(APPLICATION_ID "com.krowwithus.staff")
|
||||
|
||||
# Explicitly opt in to modern CMake behaviors to avoid warnings with recent
|
||||
# versions of CMake.
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/
|
||||
@@ -8,11 +8,13 @@ import Foundation
|
||||
import firebase_app_check
|
||||
import firebase_auth
|
||||
import firebase_core
|
||||
import geolocator_apple
|
||||
import shared_preferences_foundation
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FLTFirebaseAppCheckPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAppCheckPlugin"))
|
||||
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
|
||||
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
|
||||
GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
// This is a generated file; do not edit or check into version control.
|
||||
FLUTTER_ROOT=/Users/achinthaisuru/Documents/flutter
|
||||
FLUTTER_APPLICATION_PATH=/Users/achinthaisuru/Documents/Github/krow-workforce/apps/mobile/apps/staff
|
||||
COCOAPODS_PARALLEL_CODE_SIGN=true
|
||||
FLUTTER_BUILD_DIR=build
|
||||
FLUTTER_BUILD_NAME=1.0.0
|
||||
FLUTTER_BUILD_NUMBER=1
|
||||
DART_OBFUSCATION=false
|
||||
TRACK_WIDGET_CREATION=true
|
||||
TREE_SHAKE_ICONS=false
|
||||
PACKAGE_CONFIG=.dart_tool/package_config.json
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/bin/sh
|
||||
# This is a generated file; do not edit or check into version control.
|
||||
export "FLUTTER_ROOT=/Users/achinthaisuru/Documents/flutter"
|
||||
export "FLUTTER_APPLICATION_PATH=/Users/achinthaisuru/Documents/Github/krow-workforce/apps/mobile/apps/staff"
|
||||
export "COCOAPODS_PARALLEL_CODE_SIGN=true"
|
||||
export "FLUTTER_BUILD_DIR=build"
|
||||
export "FLUTTER_BUILD_NAME=1.0.0"
|
||||
export "FLUTTER_BUILD_NUMBER=1"
|
||||
export "DART_OBFUSCATION=false"
|
||||
export "TRACK_WIDGET_CREATION=true"
|
||||
export "TREE_SHAKE_ICONS=false"
|
||||
export "PACKAGE_CONFIG=.dart_tool/package_config.json"
|
||||
@@ -1,21 +1,143 @@
|
||||
PODS:
|
||||
- AppCheckCore (11.2.0):
|
||||
- GoogleUtilities/Environment (~> 8.0)
|
||||
- GoogleUtilities/UserDefaults (~> 8.0)
|
||||
- PromisesObjC (~> 2.4)
|
||||
- Firebase/AppCheck (12.8.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAppCheck (~> 12.8.0)
|
||||
- Firebase/Auth (12.8.0):
|
||||
- Firebase/CoreOnly
|
||||
- FirebaseAuth (~> 12.8.0)
|
||||
- Firebase/CoreOnly (12.8.0):
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- firebase_app_check (0.4.1-4):
|
||||
- Firebase/AppCheck (~> 12.8.0)
|
||||
- Firebase/CoreOnly (~> 12.8.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_auth (6.1.4):
|
||||
- Firebase/Auth (~> 12.8.0)
|
||||
- Firebase/CoreOnly (~> 12.8.0)
|
||||
- firebase_core
|
||||
- FlutterMacOS
|
||||
- firebase_core (4.4.0):
|
||||
- Firebase/CoreOnly (~> 12.8.0)
|
||||
- FlutterMacOS
|
||||
- FirebaseAppCheck (12.8.0):
|
||||
- AppCheckCore (~> 11.0)
|
||||
- FirebaseAppCheckInterop (~> 12.8.0)
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/UserDefaults (~> 8.1)
|
||||
- FirebaseAppCheckInterop (12.8.0)
|
||||
- FirebaseAuth (12.8.0):
|
||||
- FirebaseAppCheckInterop (~> 12.8.0)
|
||||
- FirebaseAuthInterop (~> 12.8.0)
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- FirebaseCoreExtension (~> 12.8.0)
|
||||
- GoogleUtilities/AppDelegateSwizzler (~> 8.1)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GTMSessionFetcher/Core (< 6.0, >= 3.4)
|
||||
- RecaptchaInterop (~> 101.0)
|
||||
- FirebaseAuthInterop (12.8.0)
|
||||
- FirebaseCore (12.8.0):
|
||||
- FirebaseCoreInternal (~> 12.8.0)
|
||||
- GoogleUtilities/Environment (~> 8.1)
|
||||
- GoogleUtilities/Logger (~> 8.1)
|
||||
- FirebaseCoreExtension (12.8.0):
|
||||
- FirebaseCore (~> 12.8.0)
|
||||
- FirebaseCoreInternal (12.8.0):
|
||||
- "GoogleUtilities/NSData+zlib (~> 8.1)"
|
||||
- FlutterMacOS (1.0.0)
|
||||
- geolocator_apple (1.2.0):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
- GoogleUtilities/AppDelegateSwizzler (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Network
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Environment (8.1.0):
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Logger (8.1.0):
|
||||
- GoogleUtilities/Environment
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Network (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- "GoogleUtilities/NSData+zlib"
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Reachability
|
||||
- "GoogleUtilities/NSData+zlib (8.1.0)":
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/Privacy (8.1.0)
|
||||
- GoogleUtilities/Reachability (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GoogleUtilities/UserDefaults (8.1.0):
|
||||
- GoogleUtilities/Logger
|
||||
- GoogleUtilities/Privacy
|
||||
- GTMSessionFetcher/Core (5.0.0)
|
||||
- PromisesObjC (2.4.0)
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
- Flutter
|
||||
- FlutterMacOS
|
||||
|
||||
DEPENDENCIES:
|
||||
- firebase_app_check (from `Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos`)
|
||||
- firebase_auth (from `Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos`)
|
||||
- firebase_core (from `Flutter/ephemeral/.symlinks/plugins/firebase_core/macos`)
|
||||
- FlutterMacOS (from `Flutter/ephemeral`)
|
||||
- geolocator_apple (from `Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin`)
|
||||
- shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`)
|
||||
|
||||
SPEC REPOS:
|
||||
trunk:
|
||||
- AppCheckCore
|
||||
- Firebase
|
||||
- FirebaseAppCheck
|
||||
- FirebaseAppCheckInterop
|
||||
- FirebaseAuth
|
||||
- FirebaseAuthInterop
|
||||
- FirebaseCore
|
||||
- FirebaseCoreExtension
|
||||
- FirebaseCoreInternal
|
||||
- GoogleUtilities
|
||||
- GTMSessionFetcher
|
||||
- PromisesObjC
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
firebase_app_check:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/firebase_app_check/macos
|
||||
firebase_auth:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/firebase_auth/macos
|
||||
firebase_core:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/firebase_core/macos
|
||||
FlutterMacOS:
|
||||
:path: Flutter/ephemeral
|
||||
geolocator_apple:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/geolocator_apple/darwin
|
||||
shared_preferences_foundation:
|
||||
:path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
AppCheckCore: cc8fd0a3a230ddd401f326489c99990b013f0c4f
|
||||
Firebase: 9a58fdbc9d8655ed7b79a19cf9690bb007d3d46d
|
||||
firebase_app_check: daf97f2d7044e28b68d23bc90e16751acee09732
|
||||
firebase_auth: 2c2438e41f061c03bd67dcb045dfd7bc843b5f52
|
||||
firebase_core: b1697fb64ff2b9ca16baaa821205f8b0c058e5d2
|
||||
FirebaseAppCheck: 11da425929a45c677d537adfff3520ccd57c1690
|
||||
FirebaseAppCheckInterop: ba3dc604a89815379e61ec2365101608d365cf7d
|
||||
FirebaseAuth: 4c289b1a43f5955283244a55cf6bd616de344be5
|
||||
FirebaseAuthInterop: 95363fe96493cb4f106656666a0768b420cba090
|
||||
FirebaseCore: 0dbad74bda10b8fb9ca34ad8f375fb9dd3ebef7c
|
||||
FirebaseCoreExtension: 6605938d51f765d8b18bfcafd2085276a252bee2
|
||||
FirebaseCoreInternal: fe5fa466aeb314787093a7dce9f0beeaad5a2a21
|
||||
FlutterMacOS: d0db08ddef1a9af05a5ec4b724367152bb0500b1
|
||||
geolocator_apple: ab36aa0e8b7d7a2d7639b3b4e48308394e8cef5e
|
||||
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
|
||||
GTMSessionFetcher: 02d6e866e90bc236f48a703a041dfe43e6221a29
|
||||
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
|
||||
shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
|
||||
|
||||
PODFILE CHECKSUM: 54d867c82ac51cbd61b565781b9fada492027009
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
name: krowwithus_staff
|
||||
description: "Krow Staff Application"
|
||||
publish_to: 'none'
|
||||
version: 0.0.1+M301
|
||||
version: 0.0.1-M3+3
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.7
|
||||
sdk: '>=3.10.0 <4.0.0'
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_localizations:
|
||||
sdk: flutter
|
||||
cupertino_icons: ^1.0.8
|
||||
flutter_modular: ^6.3.0
|
||||
|
||||
# Architecture Packages
|
||||
design_system:
|
||||
path: ../../packages/design_system
|
||||
@@ -23,6 +20,18 @@ dependencies:
|
||||
# Feature Packages
|
||||
staff_authentication:
|
||||
path: ../../packages/features/staff/authentication
|
||||
staff_availability:
|
||||
path: ../../packages/features/staff/availability
|
||||
staff_clock_in:
|
||||
path: ../../packages/features/staff/clock_in
|
||||
staff_main:
|
||||
path: ../../packages/features/staff/staff_main
|
||||
krow_core:
|
||||
path: ../../packages/core
|
||||
cupertino_icons: ^1.0.8
|
||||
flutter_modular: ^6.3.0
|
||||
firebase_core: ^4.4.0
|
||||
flutter_bloc: ^8.1.6
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@@ -34,5 +34,28 @@
|
||||
</head>
|
||||
<body>
|
||||
<script src="flutter_bootstrap.js" async></script>
|
||||
<script type="module">
|
||||
// Import the functions you need from the SDKs you need
|
||||
import { initializeApp } from "https://www.gstatic.com/firebasejs/12.8.0/firebase-app.js";
|
||||
import { getAnalytics } from "https://www.gstatic.com/firebasejs/12.8.0/firebase-analytics.js";
|
||||
// TODO: Add SDKs for Firebase products that you want to use
|
||||
// https://firebase.google.com/docs/web/setup#available-libraries
|
||||
|
||||
// Your web app's Firebase configuration
|
||||
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
|
||||
const firebaseConfig = {
|
||||
apiKey: "AIzaSyBqRtZPMGU-Sz5x5UnRrunKu5NSWYyPRn8",
|
||||
authDomain: "krow-workforce-dev.firebaseapp.com",
|
||||
projectId: "krow-workforce-dev",
|
||||
storageBucket: "krow-workforce-dev.firebasestorage.app",
|
||||
messagingSenderId: "933560802882",
|
||||
appId: "1:933560802882:web:4508ef1ee6d4e6907757db",
|
||||
measurementId: "G-DTDL7YRRM6"
|
||||
};
|
||||
|
||||
// Initialize Firebase
|
||||
const app = initializeApp(firebaseConfig);
|
||||
const analytics = getAnalytics(app);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_auth-6.1.4/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_core-4.4.0/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/
|
||||
@@ -1 +0,0 @@
|
||||
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/
|
||||
@@ -8,10 +8,16 @@
|
||||
|
||||
#include <firebase_auth/firebase_auth_plugin_c_api.h>
|
||||
#include <firebase_core/firebase_core_plugin_c_api.h>
|
||||
#include <geolocator_windows/geolocator_windows.h>
|
||||
#include <permission_handler_windows/permission_handler_windows_plugin.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FirebaseAuthPluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FirebaseAuthPluginCApi"));
|
||||
FirebaseCorePluginCApiRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FirebaseCorePluginCApi"));
|
||||
GeolocatorWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("GeolocatorWindows"));
|
||||
PermissionHandlerWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin"));
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
firebase_auth
|
||||
firebase_core
|
||||
geolocator_windows
|
||||
permission_handler_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
3
apps/mobile/config.dev.json
Normal file
3
apps/mobile/config.dev.json
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"GOOGLE_PLACES_API_KEY": "AIzaSyAS9yTf4q51_CNSZ7mbmeS9V3l_LZR80lU"
|
||||
}
|
||||
@@ -2,3 +2,5 @@ library core;
|
||||
|
||||
export 'src/domain/arguments/usecase_argument.dart';
|
||||
export 'src/domain/usecases/usecase.dart';
|
||||
export 'src/utils/date_time_utils.dart';
|
||||
export 'src/presentation/widgets/web_mobile_frame.dart';
|
||||
|
||||
@@ -0,0 +1,263 @@
|
||||
import 'package:design_system/design_system.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// A wrapper widget that renders the application inside an iPhone-like frame
|
||||
/// specifically for Flutter Web. On other platforms, it simply returns the child.
|
||||
class WebMobileFrame extends StatelessWidget {
|
||||
const WebMobileFrame({
|
||||
super.key,
|
||||
required this.child,
|
||||
required this.logo,
|
||||
required this.appName,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
final Widget logo;
|
||||
final String appName;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!kIsWeb) return child;
|
||||
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: ThemeData.dark(),
|
||||
home: _WebFrameContent(logo: logo, appName: appName, child: child),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _WebFrameContent extends StatefulWidget {
|
||||
const _WebFrameContent({
|
||||
required this.child,
|
||||
required this.logo,
|
||||
required this.appName,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
final Widget logo;
|
||||
final String appName;
|
||||
|
||||
@override
|
||||
State<_WebFrameContent> createState() => _WebFrameContentState();
|
||||
}
|
||||
|
||||
class _WebFrameContentState extends State<_WebFrameContent> {
|
||||
// ignore: unused_field
|
||||
Offset _cursorPosition = Offset.zero;
|
||||
// ignore: unused_field
|
||||
bool _isHovering = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// iPhone 14 Pro Max-ish dimensions (scaled for frame look)
|
||||
const double frameWidth = 390 * 1.2;
|
||||
const double frameHeight = 844 * 1.3;
|
||||
const double borderRadius = 54.0;
|
||||
const double borderThickness = 12.0;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: UiColors.foreground,
|
||||
body: MouseRegion(
|
||||
cursor: SystemMouseCursors.none,
|
||||
onHover: (PointerHoverEvent event) {
|
||||
setState(() {
|
||||
_cursorPosition = event.position;
|
||||
_isHovering = true;
|
||||
});
|
||||
},
|
||||
onExit: (_) => setState(() => _isHovering = false),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
// Logo and Title on the left (Web only)
|
||||
Positioned(
|
||||
left: 60,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
child: Center(
|
||||
child: Opacity(
|
||||
opacity: 0.5,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
SizedBox(width: 140, child: widget.logo),
|
||||
const SizedBox(height: 12),
|
||||
Text(
|
||||
widget.appName,
|
||||
textAlign: TextAlign.left,
|
||||
style: UiTypography.display1b.copyWith(
|
||||
color: UiColors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Container(
|
||||
height: 2,
|
||||
width: 40,
|
||||
color: UiColors.white.withOpacity(0.3),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// Frame and Content
|
||||
Center(
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
// Scale down if screen is too small
|
||||
final double scaleX = constraints.maxWidth / (frameWidth - 150);
|
||||
final double scaleY = constraints.maxHeight / (frameHeight - 220);
|
||||
final double scale = (scaleX < 1 || scaleY < 1)
|
||||
? (scaleX < scaleY ? scaleX : scaleY)
|
||||
: 1.0;
|
||||
|
||||
return Transform.scale(
|
||||
scale: scale,
|
||||
child: Container(
|
||||
width: frameWidth,
|
||||
height: frameHeight,
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.black,
|
||||
borderRadius: BorderRadius.circular(borderRadius),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.black.withOpacity(0.6),
|
||||
blurRadius: 40,
|
||||
spreadRadius: 10,
|
||||
),
|
||||
],
|
||||
border: Border.all(
|
||||
color: const Color(0xFF2C2C2C),
|
||||
width: borderThickness,
|
||||
),
|
||||
),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
borderRadius - borderThickness,
|
||||
),
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
// The actual app + status bar
|
||||
Column(
|
||||
children: <Widget>[
|
||||
// Mock iOS Status Bar
|
||||
Container(
|
||||
height: 48,
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
),
|
||||
decoration: const BoxDecoration(
|
||||
color: UiColors.background,
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
color: UiColors.border,
|
||||
width: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
// Time side
|
||||
SizedBox(
|
||||
width: 80,
|
||||
child: Text(
|
||||
'9:41 PM',
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: UiColors.black,
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 14,
|
||||
letterSpacing: -0.2,
|
||||
),
|
||||
),
|
||||
),
|
||||
// Status Icons side
|
||||
SizedBox(
|
||||
width: 80,
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.end,
|
||||
spacing: 12,
|
||||
children: <Widget>[
|
||||
Icon(
|
||||
Icons.signal_cellular_alt,
|
||||
size: 14,
|
||||
color: UiColors.black,
|
||||
),
|
||||
Icon(
|
||||
Icons.wifi,
|
||||
size: 14,
|
||||
color: UiColors.black,
|
||||
),
|
||||
Icon(
|
||||
Icons.battery_full,
|
||||
size: 14,
|
||||
color: UiColors.black,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// The main app content
|
||||
Expanded(child: widget.child),
|
||||
],
|
||||
),
|
||||
|
||||
// Dynamic Island / Notch Mockup
|
||||
Align(
|
||||
alignment: Alignment.topCenter,
|
||||
child: Container(
|
||||
width: 120,
|
||||
height: 35,
|
||||
margin: const EdgeInsets.only(top: 10),
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.black,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (_isHovering)
|
||||
Positioned(
|
||||
left: _cursorPosition.dx - 15,
|
||||
top: _cursorPosition.dy - 15,
|
||||
child: IgnorePointer(
|
||||
child: Container(
|
||||
width: 30,
|
||||
height: 30,
|
||||
decoration: BoxDecoration(
|
||||
color: UiColors.mutedForeground.withOpacity(0.3),
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: UiColors.white.withOpacity(0.7), width: 2),
|
||||
boxShadow: <BoxShadow>[
|
||||
BoxShadow(
|
||||
color: UiColors.black.withOpacity(0.2),
|
||||
blurRadius: 4,
|
||||
spreadRadius: 1,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
class DateTimeUtils {
|
||||
/// Converts a [DateTime] (assumed UTC if not specified) to the device's local time.
|
||||
static DateTime toDeviceTime(DateTime date) {
|
||||
return date.toLocal();
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,5 @@ environment:
|
||||
dependencies:
|
||||
flutter:
|
||||
sdk: flutter
|
||||
design_system:
|
||||
path: ../design_system
|
||||
|
||||
@@ -8,3 +8,4 @@ export 'src/domain/usecases/set_locale_use_case.dart';
|
||||
export 'src/data/repositories_impl/locale_repository_impl.dart';
|
||||
export 'src/data/datasources/locale_local_data_source.dart';
|
||||
export 'src/localization_module.dart';
|
||||
export 'src/utils/error_translator.dart';
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../domain/usecases/get_default_locale_use_case.dart';
|
||||
import '../domain/usecases/get_locale_use_case.dart';
|
||||
import '../domain/usecases/get_supported_locales_use_case.dart';
|
||||
import '../domain/usecases/set_locale_use_case.dart';
|
||||
import '../l10n/strings.g.dart';
|
||||
import 'locale_event.dart';
|
||||
@@ -11,23 +13,39 @@ import 'locale_state.dart';
|
||||
/// It coordinates the flow between user language requests and persistent storage
|
||||
/// using [SetLocaleUseCase] and [GetLocaleUseCase].
|
||||
class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
|
||||
final GetLocaleUseCase getLocaleUseCase;
|
||||
final SetLocaleUseCase setLocaleUseCase;
|
||||
|
||||
/// Creates a [LocaleBloc] with the required use cases.
|
||||
LocaleBloc({required this.getLocaleUseCase, required this.setLocaleUseCase})
|
||||
: super(LocaleState.initial()) {
|
||||
LocaleBloc({
|
||||
required this.getLocaleUseCase,
|
||||
required this.setLocaleUseCase,
|
||||
required this.getSupportedLocalesUseCase,
|
||||
required this.getDefaultLocaleUseCase,
|
||||
}) : super(LocaleState.initial()) {
|
||||
on<ChangeLocale>(_onChangeLocale);
|
||||
on<LoadLocale>(_onLoadLocale);
|
||||
|
||||
/// Initial event
|
||||
add(const LoadLocale());
|
||||
}
|
||||
|
||||
/// Use case for retrieving the saved locale.
|
||||
final GetLocaleUseCase getLocaleUseCase;
|
||||
|
||||
/// Use case for saving the selected locale.
|
||||
final SetLocaleUseCase setLocaleUseCase;
|
||||
|
||||
/// Use case for retrieving supported locales.
|
||||
final GetSupportedLocalesUseCase getSupportedLocalesUseCase;
|
||||
|
||||
/// Use case for retrieving the default locale.
|
||||
final GetDefaultLocaleUseCase getDefaultLocaleUseCase;
|
||||
|
||||
/// Handles the [ChangeLocale] event by saving it via the use case and emitting new state.
|
||||
Future<void> _onChangeLocale(
|
||||
ChangeLocale event,
|
||||
Emitter<LocaleState> emit,
|
||||
) async {
|
||||
// 1. Update slang settings
|
||||
LocaleSettings.setLocaleRaw(event.locale.languageCode);
|
||||
await LocaleSettings.setLocaleRaw(event.locale.languageCode);
|
||||
|
||||
// 2. Persist using Use Case
|
||||
await setLocaleUseCase(event.locale);
|
||||
@@ -46,11 +64,14 @@ class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
|
||||
LoadLocale event,
|
||||
Emitter<LocaleState> emit,
|
||||
) async {
|
||||
final Locale? savedLocale = await getLocaleUseCase();
|
||||
final Locale locale = const Locale('es');
|
||||
final Locale savedLocale = await getLocaleUseCase();
|
||||
final List<Locale> supportedLocales = getSupportedLocalesUseCase();
|
||||
|
||||
LocaleSettings.setLocaleRaw(locale.languageCode);
|
||||
await LocaleSettings.setLocaleRaw(savedLocale.languageCode);
|
||||
|
||||
emit(LocaleState(locale: locale, supportedLocales: state.supportedLocales));
|
||||
emit(LocaleState(
|
||||
locale: savedLocale,
|
||||
supportedLocales: supportedLocales,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../l10n/strings.g.dart';
|
||||
|
||||
/// Represents the current state of the application's localization.
|
||||
class LocaleState {
|
||||
/// The current active locale.
|
||||
final Locale locale;
|
||||
|
||||
/// The list of supported locales for the application.
|
||||
final List<Locale> supportedLocales;
|
||||
|
||||
/// Creates a [LocaleState] with the specified [locale].
|
||||
const LocaleState({required this.locale, required this.supportedLocales});
|
||||
|
||||
/// The initial state of the application, defaulting to English.
|
||||
factory LocaleState.initial() => LocaleState(
|
||||
locale: const Locale('es'),
|
||||
locale: AppLocaleUtils.findDeviceLocale().flutterLocale,
|
||||
supportedLocales: AppLocaleUtils.supportedLocales,
|
||||
);
|
||||
|
||||
/// The current active locale.
|
||||
final Locale locale;
|
||||
|
||||
/// The list of supported locales for the application.
|
||||
final List<Locale> supportedLocales;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'dart:ui';
|
||||
import 'package:core_localization/src/l10n/strings.g.dart';
|
||||
|
||||
import '../../domain/repositories/locale_repository_interface.dart';
|
||||
import '../datasources/locale_local_data_source.dart';
|
||||
|
||||
@@ -7,22 +9,36 @@ import '../datasources/locale_local_data_source.dart';
|
||||
/// This class handles the mapping between domain [Locale] objects and the raw
|
||||
/// strings handled by the [LocaleLocalDataSource].
|
||||
class LocaleRepositoryImpl implements LocaleRepositoryInterface {
|
||||
final LocaleLocalDataSource _localDataSource;
|
||||
/// Creates a [LocaleRepositoryImpl] with the provided [localDataSource].
|
||||
LocaleRepositoryImpl({required this.localDataSource});
|
||||
|
||||
/// Creates a [LocaleRepositoryImpl] with the provided [_localDataSource].
|
||||
LocaleRepositoryImpl(this._localDataSource);
|
||||
final LocaleLocalDataSource localDataSource;
|
||||
|
||||
@override
|
||||
Future<void> saveLocale(Locale locale) {
|
||||
return _localDataSource.saveLanguageCode(locale.languageCode);
|
||||
return localDataSource.saveLanguageCode(locale.languageCode);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Locale?> getSavedLocale() async {
|
||||
final String? languageCode = await _localDataSource.getLanguageCode();
|
||||
Future<Locale> getSavedLocale() async {
|
||||
return getDefaultLocale();
|
||||
|
||||
/// TODO: FEATURE_NOT_IMPLEMENTED: Implement saved locale retrieval later
|
||||
final String? languageCode = await localDataSource.getLanguageCode();
|
||||
if (languageCode != null) {
|
||||
return Locale(languageCode);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
Locale getDefaultLocale() {
|
||||
final Locale deviceLocale = AppLocaleUtils.findDeviceLocale().flutterLocale;
|
||||
if (getSupportedLocales().contains(deviceLocale)) {
|
||||
return deviceLocale;
|
||||
}
|
||||
return const Locale('en');
|
||||
}
|
||||
|
||||
@override
|
||||
List<Locale> getSupportedLocales() => AppLocaleUtils.supportedLocales;
|
||||
}
|
||||
|
||||
@@ -13,5 +13,11 @@ abstract interface class LocaleRepositoryInterface {
|
||||
/// Retrieves the saved [locale] from persistent storage.
|
||||
///
|
||||
/// Returns `null` if no locale has been previously saved.
|
||||
Future<Locale?> getSavedLocale();
|
||||
Future<Locale> getSavedLocale();
|
||||
|
||||
/// Retrieves the default [Locale] for the application.
|
||||
Locale getDefaultLocale();
|
||||
|
||||
/// Retrieves the list of supported [Locale]s.
|
||||
List<Locale> getSupportedLocales();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'dart:ui';
|
||||
import '../repositories/locale_repository_interface.dart';
|
||||
|
||||
/// Use case to retrieve the default locale.
|
||||
class GetDefaultLocaleUseCase {
|
||||
final LocaleRepositoryInterface _repository;
|
||||
|
||||
/// Creates a [GetDefaultLocaleUseCase] with the required [LocaleRepositoryInterface].
|
||||
GetDefaultLocaleUseCase(this._repository);
|
||||
|
||||
/// Retrieves the default locale.
|
||||
Locale call() {
|
||||
return _repository.getDefaultLocale();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ class GetLocaleUseCase extends NoInputUseCase<Locale?> {
|
||||
GetLocaleUseCase(this._repository);
|
||||
|
||||
@override
|
||||
Future<Locale?> call() {
|
||||
Future<Locale> call() {
|
||||
return _repository.getSavedLocale();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import 'dart:ui';
|
||||
import '../repositories/locale_repository_interface.dart';
|
||||
|
||||
/// Use case to retrieve the list of supported locales.
|
||||
class GetSupportedLocalesUseCase {
|
||||
final LocaleRepositoryInterface _repository;
|
||||
|
||||
/// Creates a [GetSupportedLocalesUseCase] with the required [LocaleRepositoryInterface].
|
||||
GetSupportedLocalesUseCase(this._repository);
|
||||
|
||||
/// Retrieves the supported locales.
|
||||
List<Locale> call() {
|
||||
return _repository.getSupportedLocales();
|
||||
}
|
||||
}
|
||||
@@ -517,6 +517,8 @@
|
||||
"secure_subtitle": "Your account details are encrypted and safe.",
|
||||
"primary": "Primary",
|
||||
"add_new_account": "Add New Account",
|
||||
"bank_name": "Bank Name",
|
||||
"bank_hint": "Enter bank name",
|
||||
"routing_number": "Routing Number",
|
||||
"routing_hint": "Enter routing number",
|
||||
"account_number": "Account Number",
|
||||
@@ -526,7 +528,8 @@
|
||||
"savings": "Savings",
|
||||
"cancel": "Cancel",
|
||||
"save": "Save",
|
||||
"account_ending": "Ending in $last4"
|
||||
"account_ending": "Ending in $last4",
|
||||
"account_added_success": "Bank account added successfully!"
|
||||
},
|
||||
"logout": {
|
||||
"button": "Sign Out"
|
||||
@@ -725,6 +728,60 @@
|
||||
"paid": "Paid",
|
||||
"pending": "Pending"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"auth": {
|
||||
"invalid_credentials": "The email or password you entered is incorrect.",
|
||||
"account_exists": "An account with this email already exists. Try signing in instead.",
|
||||
"session_expired": "Your session has expired. Please sign in again.",
|
||||
"user_not_found": "We couldn't find your account. Please check your email and try again.",
|
||||
"unauthorized_app": "This account is not authorized for this app.",
|
||||
"weak_password": "Please choose a stronger password with at least 8 characters.",
|
||||
"sign_up_failed": "We couldn't create your account. Please try again.",
|
||||
"sign_in_failed": "We couldn't sign you in. Please try again.",
|
||||
"not_authenticated": "Please sign in to continue.",
|
||||
"password_mismatch": "This email is already registered. Please use the correct password or tap 'Forgot Password' to reset it.",
|
||||
"google_only_account": "This email is registered via Google. Please use 'Forgot Password' to set a password, then try signing up again with the same information."
|
||||
},
|
||||
"hub": {
|
||||
"has_orders": "This hub has active orders and cannot be deleted.",
|
||||
"not_found": "The hub you're looking for doesn't exist.",
|
||||
"creation_failed": "We couldn't create the hub. Please try again."
|
||||
},
|
||||
"order": {
|
||||
"missing_hub": "Please select a location for your order.",
|
||||
"missing_vendor": "Please select a vendor for your order.",
|
||||
"creation_failed": "We couldn't create your order. Please try again.",
|
||||
"shift_creation_failed": "We couldn't schedule the shift. Please try again.",
|
||||
"missing_business": "Your business profile couldn't be loaded. Please sign in again."
|
||||
},
|
||||
"profile": {
|
||||
"staff_not_found": "Your profile couldn't be loaded. Please sign in again.",
|
||||
"business_not_found": "Your business profile couldn't be loaded. Please sign in again.",
|
||||
"update_failed": "We couldn't update your profile. Please try again."
|
||||
},
|
||||
"shift": {
|
||||
"no_open_roles": "There are no open positions available for this shift.",
|
||||
"application_not_found": "Your application couldn't be found.",
|
||||
"no_active_shift": "You don't have an active shift to clock out from."
|
||||
},
|
||||
"generic": {
|
||||
"unknown": "Something went wrong. Please try again.",
|
||||
"no_connection": "No internet connection. Please check your network and try again."
|
||||
}
|
||||
},
|
||||
"success": {
|
||||
"hub": {
|
||||
"created": "Hub created successfully!",
|
||||
"deleted": "Hub deleted successfully!",
|
||||
"nfc_assigned": "NFC tag assigned successfully!"
|
||||
},
|
||||
"order": {
|
||||
"created": "Order created successfully!"
|
||||
},
|
||||
"profile": {
|
||||
"updated": "Profile updated successfully!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -515,6 +515,8 @@
|
||||
"secure_title": "Seguro y Cifrado",
|
||||
"secure_subtitle": "Su información bancaria está cifrada y almacenada de forma segura. Nunca compartimos sus detalles.",
|
||||
"add_new_account": "Agregar Nueva Cuenta",
|
||||
"bank_name": "Nombre del Banco",
|
||||
"bank_hint": "Ingrese nombre del banco",
|
||||
"routing_number": "Número de Ruta",
|
||||
"routing_hint": "9 dígitos",
|
||||
"account_number": "Número de Cuenta",
|
||||
@@ -525,7 +527,8 @@
|
||||
"cancel": "Cancelar",
|
||||
"save": "Guardar",
|
||||
"primary": "Principal",
|
||||
"account_ending": "Termina en $last4"
|
||||
"account_ending": "Termina en $last4",
|
||||
"account_added_success": "¡Cuenta bancaria agregada exitosamente!"
|
||||
},
|
||||
"logout": {
|
||||
"button": "Cerrar Sesión"
|
||||
@@ -724,5 +727,59 @@
|
||||
"paid": "Pagado",
|
||||
"pending": "Pendiente"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"auth": {
|
||||
"invalid_credentials": "El correo electrónico o la contraseña que ingresaste es incorrecta.",
|
||||
"account_exists": "Ya existe una cuenta con este correo electrónico. Intenta iniciar sesión.",
|
||||
"session_expired": "Tu sesión ha expirado. Por favor, inicia sesión de nuevo.",
|
||||
"user_not_found": "No pudimos encontrar tu cuenta. Por favor, verifica tu correo electrónico e intenta de nuevo.",
|
||||
"unauthorized_app": "Esta cuenta no está autorizada para esta aplicación.",
|
||||
"weak_password": "Por favor, elige una contraseña más segura con al menos 8 caracteres.",
|
||||
"sign_up_failed": "No pudimos crear tu cuenta. Por favor, intenta de nuevo.",
|
||||
"sign_in_failed": "No pudimos iniciar sesión. Por favor, intenta de nuevo.",
|
||||
"not_authenticated": "Por favor, inicia sesión para continuar.",
|
||||
"password_mismatch": "Este correo ya está registrado. Por favor, usa la contraseña correcta o toca 'Olvidé mi contraseña' para restablecerla.",
|
||||
"google_only_account": "Este correo está registrado con Google. Por favor, usa 'Olvidé mi contraseña' para establecer una contraseña, luego intenta registrarte de nuevo con la misma información."
|
||||
},
|
||||
"hub": {
|
||||
"has_orders": "Este hub tiene órdenes activas y no puede ser eliminado.",
|
||||
"not_found": "El hub que buscas no existe.",
|
||||
"creation_failed": "No pudimos crear el hub. Por favor, intenta de nuevo."
|
||||
},
|
||||
"order": {
|
||||
"missing_hub": "Por favor, selecciona una ubicación para tu orden.",
|
||||
"missing_vendor": "Por favor, selecciona un proveedor para tu orden.",
|
||||
"creation_failed": "No pudimos crear tu orden. Por favor, intenta de nuevo.",
|
||||
"shift_creation_failed": "No pudimos programar el turno. Por favor, intenta de nuevo.",
|
||||
"missing_business": "No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo."
|
||||
},
|
||||
"profile": {
|
||||
"staff_not_found": "No se pudo cargar tu perfil. Por favor, inicia sesión de nuevo.",
|
||||
"business_not_found": "No se pudo cargar tu perfil de empresa. Por favor, inicia sesión de nuevo.",
|
||||
"update_failed": "No pudimos actualizar tu perfil. Por favor, intenta de nuevo."
|
||||
},
|
||||
"shift": {
|
||||
"no_open_roles": "No hay posiciones abiertas disponibles para este turno.",
|
||||
"application_not_found": "No se pudo encontrar tu solicitud.",
|
||||
"no_active_shift": "No tienes un turno activo para registrar salida."
|
||||
},
|
||||
"generic": {
|
||||
"unknown": "Algo salió mal. Por favor, intenta de nuevo.",
|
||||
"no_connection": "Sin conexión a internet. Por favor, verifica tu red e intenta de nuevo."
|
||||
}
|
||||
},
|
||||
"success": {
|
||||
"hub": {
|
||||
"created": "¡Hub creado exitosamente!",
|
||||
"deleted": "¡Hub eliminado exitosamente!",
|
||||
"nfc_assigned": "¡Etiqueta NFC asignada exitosamente!"
|
||||
},
|
||||
"order": {
|
||||
"created": "¡Orden creada exitosamente!"
|
||||
},
|
||||
"profile": {
|
||||
"updated": "¡Perfil actualizado exitosamente!"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,183 +0,0 @@
|
||||
/// Generated file. Do not edit.
|
||||
///
|
||||
/// Source: lib/src/l10n
|
||||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 2
|
||||
/// Strings: 1038 (519 per locale)
|
||||
///
|
||||
/// Built on 2026-01-27 at 19:37 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
// dart format off
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:slang/generated.dart';
|
||||
import 'package:slang_flutter/slang_flutter.dart';
|
||||
export 'package:slang_flutter/slang_flutter.dart';
|
||||
|
||||
import 'strings_es.g.dart' deferred as l_es;
|
||||
part 'strings_en.g.dart';
|
||||
|
||||
/// Supported locales.
|
||||
///
|
||||
/// Usage:
|
||||
/// - LocaleSettings.setLocale(AppLocale.en) // set locale
|
||||
/// - Locale locale = AppLocale.en.flutterLocale // get flutter locale from enum
|
||||
/// - if (LocaleSettings.currentLocale == AppLocale.en) // locale check
|
||||
enum AppLocale with BaseAppLocale<AppLocale, Translations> {
|
||||
en(languageCode: 'en'),
|
||||
es(languageCode: 'es');
|
||||
|
||||
const AppLocale({
|
||||
required this.languageCode,
|
||||
this.scriptCode, // ignore: unused_element, unused_element_parameter
|
||||
this.countryCode, // ignore: unused_element, unused_element_parameter
|
||||
});
|
||||
|
||||
@override final String languageCode;
|
||||
@override final String? scriptCode;
|
||||
@override final String? countryCode;
|
||||
|
||||
@override
|
||||
Future<Translations> build({
|
||||
Map<String, Node>? overrides,
|
||||
PluralResolver? cardinalResolver,
|
||||
PluralResolver? ordinalResolver,
|
||||
}) async {
|
||||
switch (this) {
|
||||
case AppLocale.en:
|
||||
return TranslationsEn(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
case AppLocale.es:
|
||||
await l_es.loadLibrary();
|
||||
return l_es.TranslationsEs(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Translations buildSync({
|
||||
Map<String, Node>? overrides,
|
||||
PluralResolver? cardinalResolver,
|
||||
PluralResolver? ordinalResolver,
|
||||
}) {
|
||||
switch (this) {
|
||||
case AppLocale.en:
|
||||
return TranslationsEn(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
case AppLocale.es:
|
||||
return l_es.TranslationsEs(
|
||||
overrides: overrides,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets current instance managed by [LocaleSettings].
|
||||
Translations get translations => LocaleSettings.instance.getTranslations(this);
|
||||
}
|
||||
|
||||
/// Method A: Simple
|
||||
///
|
||||
/// No rebuild after locale change.
|
||||
/// Translation happens during initialization of the widget (call of t).
|
||||
/// Configurable via 'translate_var'.
|
||||
///
|
||||
/// Usage:
|
||||
/// String a = t.someKey.anotherKey;
|
||||
/// String b = t['someKey.anotherKey']; // Only for edge cases!
|
||||
Translations get t => LocaleSettings.instance.currentTranslations;
|
||||
|
||||
/// Method B: Advanced
|
||||
///
|
||||
/// All widgets using this method will trigger a rebuild when locale changes.
|
||||
/// Use this if you have e.g. a settings page where the user can select the locale during runtime.
|
||||
///
|
||||
/// Step 1:
|
||||
/// wrap your App with
|
||||
/// TranslationProvider(
|
||||
/// child: MyApp()
|
||||
/// );
|
||||
///
|
||||
/// Step 2:
|
||||
/// final t = Translations.of(context); // Get t variable.
|
||||
/// String a = t.someKey.anotherKey; // Use t variable.
|
||||
/// String b = t['someKey.anotherKey']; // Only for edge cases!
|
||||
class TranslationProvider extends BaseTranslationProvider<AppLocale, Translations> {
|
||||
TranslationProvider({required super.child}) : super(settings: LocaleSettings.instance);
|
||||
|
||||
static InheritedLocaleData<AppLocale, Translations> of(BuildContext context) => InheritedLocaleData.of<AppLocale, Translations>(context);
|
||||
}
|
||||
|
||||
/// Method B shorthand via [BuildContext] extension method.
|
||||
/// Configurable via 'translate_var'.
|
||||
///
|
||||
/// Usage (e.g. in a widget's build method):
|
||||
/// context.t.someKey.anotherKey
|
||||
extension BuildContextTranslationsExtension on BuildContext {
|
||||
Translations get t => TranslationProvider.of(this).translations;
|
||||
}
|
||||
|
||||
/// Manages all translation instances and the current locale
|
||||
class LocaleSettings extends BaseFlutterLocaleSettings<AppLocale, Translations> {
|
||||
LocaleSettings._() : super(
|
||||
utils: AppLocaleUtils.instance,
|
||||
lazy: true,
|
||||
);
|
||||
|
||||
static final instance = LocaleSettings._();
|
||||
|
||||
// static aliases (checkout base methods for documentation)
|
||||
static AppLocale get currentLocale => instance.currentLocale;
|
||||
static Stream<AppLocale> getLocaleStream() => instance.getLocaleStream();
|
||||
static Future<AppLocale> setLocale(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocale(locale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static Future<AppLocale> setLocaleRaw(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRaw(rawLocale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static Future<AppLocale> useDeviceLocale() => instance.useDeviceLocale();
|
||||
static Future<void> setPluralResolver({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolver(
|
||||
language: language,
|
||||
locale: locale,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
|
||||
// synchronous versions
|
||||
static AppLocale setLocaleSync(AppLocale locale, {bool? listenToDeviceLocale = false}) => instance.setLocaleSync(locale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static AppLocale setLocaleRawSync(String rawLocale, {bool? listenToDeviceLocale = false}) => instance.setLocaleRawSync(rawLocale, listenToDeviceLocale: listenToDeviceLocale);
|
||||
static AppLocale useDeviceLocaleSync() => instance.useDeviceLocaleSync();
|
||||
static void setPluralResolverSync({String? language, AppLocale? locale, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver}) => instance.setPluralResolverSync(
|
||||
language: language,
|
||||
locale: locale,
|
||||
cardinalResolver: cardinalResolver,
|
||||
ordinalResolver: ordinalResolver,
|
||||
);
|
||||
}
|
||||
|
||||
/// Provides utility functions without any side effects.
|
||||
class AppLocaleUtils extends BaseAppLocaleUtils<AppLocale, Translations> {
|
||||
AppLocaleUtils._() : super(
|
||||
baseLocale: AppLocale.en,
|
||||
locales: AppLocale.values,
|
||||
);
|
||||
|
||||
static final instance = AppLocaleUtils._();
|
||||
|
||||
// static aliases (checkout base methods for documentation)
|
||||
static AppLocale parse(String rawLocale) => instance.parse(rawLocale);
|
||||
static AppLocale parseLocaleParts({required String languageCode, String? scriptCode, String? countryCode}) => instance.parseLocaleParts(languageCode: languageCode, scriptCode: scriptCode, countryCode: countryCode);
|
||||
static AppLocale findDeviceLocale() => instance.findDeviceLocale();
|
||||
static List<Locale> get supportedLocales => instance.supportedLocales;
|
||||
static List<String> get supportedLocalesRaw => instance.supportedLocalesRaw;
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,9 @@ import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'data/datasources/locale_local_data_source.dart';
|
||||
import 'data/repositories_impl/locale_repository_impl.dart';
|
||||
import 'domain/repositories/locale_repository_interface.dart';
|
||||
import 'domain/usecases/get_default_locale_use_case.dart';
|
||||
import 'domain/usecases/get_locale_use_case.dart';
|
||||
import 'domain/usecases/get_supported_locales_use_case.dart';
|
||||
import 'domain/usecases/set_locale_use_case.dart';
|
||||
import 'bloc/locale_bloc.dart';
|
||||
|
||||
@@ -18,28 +20,36 @@ class LocalizationModule extends Module {
|
||||
i.addInstance<SharedPreferencesAsync>(SharedPreferencesAsync());
|
||||
|
||||
// Data Sources
|
||||
i.addSingleton<LocaleLocalDataSource>(
|
||||
i.addLazySingleton<LocaleLocalDataSource>(
|
||||
() => LocaleLocalDataSourceImpl(i.get<SharedPreferencesAsync>()),
|
||||
);
|
||||
|
||||
// Repositories
|
||||
i.addSingleton<LocaleRepositoryInterface>(
|
||||
() => LocaleRepositoryImpl(i.get<LocaleLocalDataSource>()),
|
||||
i.addLazySingleton<LocaleRepositoryInterface>(
|
||||
() => LocaleRepositoryImpl(localDataSource: i.get<LocaleLocalDataSource>()),
|
||||
);
|
||||
|
||||
// Use Cases
|
||||
i.addSingleton<GetLocaleUseCase>(
|
||||
i.addLazySingleton<GetLocaleUseCase>(
|
||||
() => GetLocaleUseCase(i.get<LocaleRepositoryInterface>()),
|
||||
);
|
||||
i.addSingleton<SetLocaleUseCase>(
|
||||
i.addLazySingleton<SetLocaleUseCase>(
|
||||
() => SetLocaleUseCase(i.get<LocaleRepositoryInterface>()),
|
||||
);
|
||||
i.addLazySingleton<GetSupportedLocalesUseCase>(
|
||||
() => GetSupportedLocalesUseCase(i.get<LocaleRepositoryInterface>()),
|
||||
);
|
||||
i.addLazySingleton<GetDefaultLocaleUseCase>(
|
||||
() => GetDefaultLocaleUseCase(i.get<LocaleRepositoryInterface>()),
|
||||
);
|
||||
|
||||
// BLoCs
|
||||
i.addSingleton<LocaleBloc>(
|
||||
i.add<LocaleBloc>(
|
||||
() => LocaleBloc(
|
||||
getLocaleUseCase: i.get<GetLocaleUseCase>(),
|
||||
setLocaleUseCase: i.get<SetLocaleUseCase>(),
|
||||
getSupportedLocalesUseCase: i.get<GetSupportedLocalesUseCase>(),
|
||||
getDefaultLocaleUseCase: i.get<GetDefaultLocaleUseCase>(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
import '../l10n/strings.g.dart';
|
||||
|
||||
/// Translates error message keys to localized strings.
|
||||
///
|
||||
/// This utility function takes a dot-notation key like 'errors.auth.account_exists'
|
||||
/// and returns the corresponding localized string from the translation system.
|
||||
///
|
||||
/// If the key is not found or doesn't match the expected format, the original
|
||||
/// key is returned as a fallback.
|
||||
///
|
||||
/// Example:
|
||||
/// ```dart
|
||||
/// final message = translateErrorKey('errors.auth.account_exists');
|
||||
/// // Returns: "An account with this email already exists. Try signing in instead."
|
||||
/// ```
|
||||
String translateErrorKey(String key) {
|
||||
final List<String> parts = key.split('.');
|
||||
|
||||
// Expected format: errors.{category}.{error_type}
|
||||
if (parts.length != 3 || parts[0] != 'errors') {
|
||||
return key;
|
||||
}
|
||||
|
||||
final String category = parts[1];
|
||||
final String errorType = parts[2];
|
||||
|
||||
switch (category) {
|
||||
case 'auth':
|
||||
return _translateAuthError(errorType);
|
||||
case 'hub':
|
||||
return _translateHubError(errorType);
|
||||
case 'order':
|
||||
return _translateOrderError(errorType);
|
||||
case 'profile':
|
||||
return _translateProfileError(errorType);
|
||||
case 'shift':
|
||||
return _translateShiftError(errorType);
|
||||
case 'generic':
|
||||
return _translateGenericError(errorType);
|
||||
default:
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
String _translateAuthError(String errorType) {
|
||||
switch (errorType) {
|
||||
case 'invalid_credentials':
|
||||
return t.errors.auth.invalid_credentials;
|
||||
case 'account_exists':
|
||||
return t.errors.auth.account_exists;
|
||||
case 'session_expired':
|
||||
return t.errors.auth.session_expired;
|
||||
case 'user_not_found':
|
||||
return t.errors.auth.user_not_found;
|
||||
case 'unauthorized_app':
|
||||
return t.errors.auth.unauthorized_app;
|
||||
case 'weak_password':
|
||||
return t.errors.auth.weak_password;
|
||||
case 'sign_up_failed':
|
||||
return t.errors.auth.sign_up_failed;
|
||||
case 'sign_in_failed':
|
||||
return t.errors.auth.sign_in_failed;
|
||||
case 'not_authenticated':
|
||||
return t.errors.auth.not_authenticated;
|
||||
case 'password_mismatch':
|
||||
return t.errors.auth.password_mismatch;
|
||||
case 'google_only_account':
|
||||
return t.errors.auth.google_only_account;
|
||||
default:
|
||||
return t.errors.generic.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
String _translateHubError(String errorType) {
|
||||
switch (errorType) {
|
||||
case 'has_orders':
|
||||
return t.errors.hub.has_orders;
|
||||
case 'not_found':
|
||||
return t.errors.hub.not_found;
|
||||
case 'creation_failed':
|
||||
return t.errors.hub.creation_failed;
|
||||
default:
|
||||
return t.errors.generic.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
String _translateOrderError(String errorType) {
|
||||
switch (errorType) {
|
||||
case 'missing_hub':
|
||||
return t.errors.order.missing_hub;
|
||||
case 'missing_vendor':
|
||||
return t.errors.order.missing_vendor;
|
||||
case 'creation_failed':
|
||||
return t.errors.order.creation_failed;
|
||||
case 'shift_creation_failed':
|
||||
return t.errors.order.shift_creation_failed;
|
||||
case 'missing_business':
|
||||
return t.errors.order.missing_business;
|
||||
default:
|
||||
return t.errors.generic.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
String _translateProfileError(String errorType) {
|
||||
switch (errorType) {
|
||||
case 'staff_not_found':
|
||||
return t.errors.profile.staff_not_found;
|
||||
case 'business_not_found':
|
||||
return t.errors.profile.business_not_found;
|
||||
case 'update_failed':
|
||||
return t.errors.profile.update_failed;
|
||||
default:
|
||||
return t.errors.generic.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
String _translateShiftError(String errorType) {
|
||||
switch (errorType) {
|
||||
case 'no_open_roles':
|
||||
return t.errors.shift.no_open_roles;
|
||||
case 'application_not_found':
|
||||
return t.errors.shift.application_not_found;
|
||||
case 'no_active_shift':
|
||||
return t.errors.shift.no_active_shift;
|
||||
default:
|
||||
return t.errors.generic.unknown;
|
||||
}
|
||||
}
|
||||
|
||||
String _translateGenericError(String errorType) {
|
||||
switch (errorType) {
|
||||
case 'unknown':
|
||||
return t.errors.generic.unknown;
|
||||
case 'no_connection':
|
||||
return t.errors.generic.no_connection;
|
||||
default:
|
||||
return t.errors.generic.unknown;
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,12 @@ import 'package:krow_domain/krow_domain.dart' as domain;
|
||||
class StaffSession {
|
||||
final domain.User user;
|
||||
final domain.Staff? staff;
|
||||
final String? ownerId;
|
||||
|
||||
const StaffSession({
|
||||
required this.user,
|
||||
this.staff,
|
||||
this.ownerId,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -14,3 +14,4 @@ dependencies:
|
||||
krow_domain:
|
||||
path: ../domain
|
||||
flutter_modular: ^6.3.0
|
||||
firebase_data_connect: ^0.2.2+2
|
||||
|
||||
@@ -37,4 +37,7 @@ class UiConstants {
|
||||
static const double space12 = 48.0;
|
||||
static const double space14 = 56.0;
|
||||
static const double space16 = 64.0;
|
||||
static const double space20 = 80.0;
|
||||
static const double space24 = 96.0;
|
||||
static const double space32 = 128.0;
|
||||
}
|
||||
|
||||
@@ -63,6 +63,9 @@ class UiIcons {
|
||||
/// Checkmark icon
|
||||
static const IconData check = _IconLib.check;
|
||||
|
||||
/// Checkmark circle icon
|
||||
static const IconData checkCircle = _IconLib.checkCircle;
|
||||
|
||||
/// X/Cancel icon
|
||||
static const IconData close = _IconLib.x;
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'ui_colors.dart';
|
||||
import 'ui_typography.dart';
|
||||
import 'ui_constants.dart';
|
||||
import 'ui_typography.dart';
|
||||
|
||||
/// The main entry point for the Staff Design System theme.
|
||||
/// Assembles colors, typography, and constants into a comprehensive Material 3 theme.
|
||||
|
||||
@@ -50,7 +50,7 @@ class UiButton extends StatelessWidget {
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
this.size = UiButtonSize.large,
|
||||
this.fullWidth = false,
|
||||
}) : assert(
|
||||
text != null || child != null,
|
||||
@@ -67,7 +67,7 @@ class UiButton extends StatelessWidget {
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
this.size = UiButtonSize.large,
|
||||
this.fullWidth = false,
|
||||
}) : buttonBuilder = _elevatedButtonBuilder,
|
||||
assert(
|
||||
@@ -85,7 +85,7 @@ class UiButton extends StatelessWidget {
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
this.size = UiButtonSize.large,
|
||||
this.fullWidth = false,
|
||||
}) : buttonBuilder = _outlinedButtonBuilder,
|
||||
assert(
|
||||
@@ -103,7 +103,7 @@ class UiButton extends StatelessWidget {
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
this.size = UiButtonSize.large,
|
||||
this.fullWidth = false,
|
||||
}) : buttonBuilder = _textButtonBuilder,
|
||||
assert(
|
||||
@@ -121,7 +121,7 @@ class UiButton extends StatelessWidget {
|
||||
this.trailingIcon,
|
||||
this.style,
|
||||
this.iconSize = 20,
|
||||
this.size = UiButtonSize.medium,
|
||||
this.size = UiButtonSize.large,
|
||||
this.fullWidth = false,
|
||||
}) : buttonBuilder = _textButtonBuilder,
|
||||
assert(
|
||||
@@ -132,10 +132,14 @@ class UiButton extends StatelessWidget {
|
||||
@override
|
||||
/// Builds the button UI.
|
||||
Widget build(BuildContext context) {
|
||||
final ButtonStyle? mergedStyle = style != null
|
||||
? _getSizeStyle().merge(style)
|
||||
: _getSizeStyle();
|
||||
|
||||
final Widget button = buttonBuilder(
|
||||
context,
|
||||
onPressed,
|
||||
style,
|
||||
mergedStyle,
|
||||
_buildButtonContent(),
|
||||
);
|
||||
|
||||
@@ -146,6 +150,65 @@ class UiButton extends StatelessWidget {
|
||||
return button;
|
||||
}
|
||||
|
||||
/// Gets the style based on the button size.
|
||||
ButtonStyle _getSizeStyle() {
|
||||
switch (size) {
|
||||
case UiButtonSize.extraSmall:
|
||||
return ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space2,
|
||||
vertical: UiConstants.space1,
|
||||
),
|
||||
),
|
||||
minimumSize: WidgetStateProperty.all(const Size(0, 28)),
|
||||
maximumSize: WidgetStateProperty.all(const Size(double.infinity, 28)),
|
||||
textStyle: WidgetStateProperty.all(
|
||||
const TextStyle(fontSize: 12, fontWeight: FontWeight.w500),
|
||||
),
|
||||
);
|
||||
case UiButtonSize.small:
|
||||
return ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space3,
|
||||
vertical: UiConstants.space2,
|
||||
),
|
||||
),
|
||||
minimumSize: WidgetStateProperty.all(const Size(0, 36)),
|
||||
maximumSize: WidgetStateProperty.all(const Size(double.infinity, 36)),
|
||||
textStyle: WidgetStateProperty.all(
|
||||
const TextStyle(fontSize: 13, fontWeight: FontWeight.w500),
|
||||
),
|
||||
);
|
||||
case UiButtonSize.medium:
|
||||
return ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space4,
|
||||
vertical: UiConstants.space3,
|
||||
),
|
||||
),
|
||||
minimumSize: WidgetStateProperty.all(const Size(0, 44)),
|
||||
maximumSize: WidgetStateProperty.all(const Size(double.infinity, 44)),
|
||||
);
|
||||
case UiButtonSize.large:
|
||||
return ButtonStyle(
|
||||
padding: WidgetStateProperty.all(
|
||||
const EdgeInsets.symmetric(
|
||||
horizontal: UiConstants.space6,
|
||||
vertical: UiConstants.space4,
|
||||
),
|
||||
),
|
||||
minimumSize: WidgetStateProperty.all(const Size(0, 52)),
|
||||
maximumSize: WidgetStateProperty.all(const Size(double.infinity, 52)),
|
||||
textStyle: WidgetStateProperty.all(
|
||||
const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds the button content with optional leading and trailing icons.
|
||||
Widget _buildButtonContent() {
|
||||
if (child != null) {
|
||||
@@ -229,6 +292,9 @@ class UiButton extends StatelessWidget {
|
||||
|
||||
/// Defines the size of a [UiButton].
|
||||
enum UiButtonSize {
|
||||
/// Extra small button (very compact)
|
||||
extraSmall,
|
||||
|
||||
/// Small button (compact)
|
||||
small,
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ homepage:
|
||||
resolution: workspace
|
||||
|
||||
environment:
|
||||
sdk: ^3.10.7
|
||||
sdk: '>=3.10.0 <4.0.0'
|
||||
flutter: ">=1.17.0"
|
||||
|
||||
dependencies:
|
||||
|
||||
@@ -29,6 +29,7 @@ export 'src/entities/events/work_session.dart';
|
||||
|
||||
// Shifts
|
||||
export 'src/entities/shifts/shift.dart';
|
||||
export 'src/adapters/shifts/shift_adapter.dart';
|
||||
|
||||
// Orders & Requests
|
||||
export 'src/entities/orders/order_type.dart';
|
||||
@@ -45,9 +46,11 @@ export 'src/entities/skills/skill_kit.dart';
|
||||
|
||||
// Financial & Payroll
|
||||
export 'src/entities/financial/invoice.dart';
|
||||
export 'src/entities/financial/time_card.dart';
|
||||
export 'src/entities/financial/invoice_item.dart';
|
||||
export 'src/entities/financial/invoice_decline.dart';
|
||||
export 'src/entities/financial/staff_payment.dart';
|
||||
export 'src/entities/financial/payment_summary.dart';
|
||||
|
||||
// Profile
|
||||
export 'src/entities/profile/staff_document.dart';
|
||||
@@ -78,12 +81,24 @@ export 'src/entities/home/home_dashboard_data.dart';
|
||||
export 'src/entities/home/reorder_item.dart';
|
||||
|
||||
// Availability
|
||||
export 'src/adapters/availability/availability_adapter.dart';
|
||||
export 'src/entities/clock_in/attendance_status.dart';
|
||||
export 'src/adapters/clock_in/clock_in_adapter.dart';
|
||||
export 'src/entities/availability/availability_slot.dart';
|
||||
export 'src/entities/availability/day_availability.dart';
|
||||
|
||||
// Coverage
|
||||
export 'src/entities/coverage_domain/coverage_shift.dart';
|
||||
export 'src/entities/coverage_domain/coverage_worker.dart';
|
||||
export 'src/entities/coverage_domain/coverage_stats.dart';
|
||||
|
||||
// Adapters
|
||||
export 'src/adapters/profile/emergency_contact_adapter.dart';
|
||||
export 'src/adapters/profile/experience_adapter.dart';
|
||||
export 'src/entities/profile/experience_skill.dart';
|
||||
export 'src/adapters/profile/bank_account_adapter.dart';
|
||||
export 'src/adapters/profile/tax_form_adapter.dart';
|
||||
export 'src/adapters/financial/payment_adapter.dart';
|
||||
|
||||
// Exceptions
|
||||
export 'src/exceptions/app_exception.dart';
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import '../../entities/availability/availability_slot.dart';
|
||||
|
||||
/// Adapter for [AvailabilitySlot] domain entity.
|
||||
class AvailabilityAdapter {
|
||||
static const Map<String, Map<String, String>> _slotDefinitions = {
|
||||
'MORNING': {
|
||||
'id': 'morning',
|
||||
'label': 'Morning',
|
||||
'timeRange': '4:00 AM - 12:00 PM',
|
||||
},
|
||||
'AFTERNOON': {
|
||||
'id': 'afternoon',
|
||||
'label': 'Afternoon',
|
||||
'timeRange': '12:00 PM - 6:00 PM',
|
||||
},
|
||||
'EVENING': {
|
||||
'id': 'evening',
|
||||
'label': 'Evening',
|
||||
'timeRange': '6:00 PM - 12:00 AM',
|
||||
},
|
||||
};
|
||||
|
||||
/// Converts a backend slot name (e.g. 'MORNING') to a Domain [AvailabilitySlot].
|
||||
static AvailabilitySlot fromPrimitive(String slotName, {bool isAvailable = false}) {
|
||||
final def = _slotDefinitions[slotName.toUpperCase()] ?? _slotDefinitions['MORNING']!;
|
||||
return AvailabilitySlot(
|
||||
id: def['id']!,
|
||||
label: def['label']!,
|
||||
timeRange: def['timeRange']!,
|
||||
isAvailable: isAvailable,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import '../../entities/shifts/shift.dart';
|
||||
import '../../entities/clock_in/attendance_status.dart';
|
||||
|
||||
/// Adapter for Clock In related data.
|
||||
class ClockInAdapter {
|
||||
|
||||
/// Converts primitive attendance data to [AttendanceStatus].
|
||||
static AttendanceStatus toAttendanceStatus({
|
||||
required String status,
|
||||
DateTime? checkInTime,
|
||||
DateTime? checkOutTime,
|
||||
String? activeShiftId,
|
||||
String? activeApplicationId,
|
||||
}) {
|
||||
final bool isCheckedIn = status == 'CHECKED_IN' || status == 'LATE'; // Assuming LATE is also checked in?
|
||||
|
||||
// Statuses that imply active attendance: CHECKED_IN, LATE.
|
||||
// Statuses that imply completed: CHECKED_OUT.
|
||||
|
||||
return AttendanceStatus(
|
||||
isCheckedIn: isCheckedIn,
|
||||
checkInTime: checkInTime,
|
||||
checkOutTime: checkOutTime,
|
||||
activeShiftId: activeShiftId,
|
||||
activeApplicationId: activeApplicationId,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import '../../entities/financial/staff_payment.dart';
|
||||
|
||||
/// Adapter for Payment related data.
|
||||
class PaymentAdapter {
|
||||
|
||||
/// Converts string status to [PaymentStatus].
|
||||
static PaymentStatus toPaymentStatus(String status) {
|
||||
switch (status) {
|
||||
case 'PAID':
|
||||
return PaymentStatus.paid;
|
||||
case 'PENDING':
|
||||
return PaymentStatus.pending;
|
||||
case 'FAILED':
|
||||
return PaymentStatus.failed;
|
||||
default:
|
||||
return PaymentStatus.unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import '../../entities/financial/time_card.dart';
|
||||
|
||||
/// Adapter for [TimeCard] to map data layer values to domain entity.
|
||||
class TimeCardAdapter {
|
||||
/// Maps primitive values to [TimeCard].
|
||||
static TimeCard fromPrimitives({
|
||||
required String id,
|
||||
required String shiftTitle,
|
||||
required String clientName,
|
||||
required DateTime date,
|
||||
required String startTime,
|
||||
required String endTime,
|
||||
required double totalHours,
|
||||
required double hourlyRate,
|
||||
required double totalPay,
|
||||
required String status,
|
||||
String? location,
|
||||
}) {
|
||||
return TimeCard(
|
||||
id: id,
|
||||
shiftTitle: shiftTitle,
|
||||
clientName: clientName,
|
||||
date: date,
|
||||
startTime: startTime,
|
||||
endTime: endTime,
|
||||
totalHours: totalHours,
|
||||
hourlyRate: hourlyRate,
|
||||
totalPay: totalPay,
|
||||
status: _stringToStatus(status),
|
||||
location: location,
|
||||
);
|
||||
}
|
||||
|
||||
static TimeCardStatus _stringToStatus(String status) {
|
||||
switch (status.toUpperCase()) {
|
||||
case 'CHECKED_OUT':
|
||||
case 'COMPLETED':
|
||||
return TimeCardStatus.approved; // Assuming completed = approved for now
|
||||
case 'PAID':
|
||||
return TimeCardStatus.paid; // If this status exists
|
||||
case 'DISPUTED':
|
||||
return TimeCardStatus.disputed;
|
||||
case 'CHECKED_IN':
|
||||
case 'ACCEPTED':
|
||||
case 'CONFIRMED':
|
||||
default:
|
||||
return TimeCardStatus.pending;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,18 +15,36 @@ class TaxFormAdapter {
|
||||
DateTime? createdAt,
|
||||
DateTime? updatedAt,
|
||||
}) {
|
||||
return TaxForm(
|
||||
final TaxFormType formType = _stringToType(type);
|
||||
final TaxFormStatus formStatus = _stringToStatus(status);
|
||||
final Map<String, dynamic> formDetails =
|
||||
formData is Map ? Map<String, dynamic>.from(formData as Map) : <String, dynamic>{};
|
||||
|
||||
if (formType == TaxFormType.i9) {
|
||||
return I9TaxForm(
|
||||
id: id,
|
||||
type: _stringToType(type),
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
description: description,
|
||||
status: _stringToStatus(status),
|
||||
status: formStatus,
|
||||
staffId: staffId,
|
||||
formData: formData is Map ? Map<String, dynamic>.from(formData) : null,
|
||||
formData: formDetails,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
);
|
||||
} else {
|
||||
return W4TaxForm(
|
||||
id: id,
|
||||
title: title,
|
||||
subtitle: subtitle,
|
||||
description: description,
|
||||
status: formStatus,
|
||||
staffId: staffId,
|
||||
formData: formDetails,
|
||||
createdAt: createdAt,
|
||||
updatedAt: updatedAt,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static TaxFormType _stringToType(String? value) {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../entities/shifts/shift.dart';
|
||||
|
||||
/// Adapter for Shift related data.
|
||||
class ShiftAdapter {
|
||||
/// Maps application data to a Shift entity.
|
||||
///
|
||||
/// This method handles the common mapping logic used across different
|
||||
/// repositories when converting application data from Data Connect to
|
||||
/// domain Shift entities.
|
||||
static Shift fromApplicationData({
|
||||
required String shiftId,
|
||||
required String roleId,
|
||||
required String roleName,
|
||||
required String businessName,
|
||||
String? companyLogoUrl,
|
||||
required double costPerHour,
|
||||
String? shiftLocation,
|
||||
required String teamHubName,
|
||||
DateTime? shiftDate,
|
||||
DateTime? startTime,
|
||||
DateTime? endTime,
|
||||
DateTime? createdAt,
|
||||
required String status,
|
||||
String? description,
|
||||
int? durationDays,
|
||||
required int count,
|
||||
int? assigned,
|
||||
String? eventName,
|
||||
bool hasApplied = false,
|
||||
}) {
|
||||
final String orderName = (eventName ?? '').trim().isNotEmpty
|
||||
? eventName!
|
||||
: businessName;
|
||||
final String title = '$roleName - $orderName';
|
||||
|
||||
return Shift(
|
||||
id: shiftId,
|
||||
roleId: roleId,
|
||||
title: title,
|
||||
clientName: businessName,
|
||||
logoUrl: companyLogoUrl,
|
||||
hourlyRate: costPerHour,
|
||||
location: shiftLocation ?? '',
|
||||
locationAddress: teamHubName,
|
||||
date: shiftDate?.toIso8601String() ?? '',
|
||||
startTime: startTime != null ? DateFormat('HH:mm').format(startTime) : '',
|
||||
endTime: endTime != null ? DateFormat('HH:mm').format(endTime) : '',
|
||||
createdDate: createdAt?.toIso8601String() ?? '',
|
||||
status: status,
|
||||
description: description,
|
||||
durationDays: durationDays,
|
||||
requiredSlots: count,
|
||||
filledSlots: assigned ?? 0,
|
||||
hasApplied: hasApplied,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Simple entity to hold attendance state
|
||||
class AttendanceStatus extends Equatable {
|
||||
final bool isCheckedIn;
|
||||
final DateTime? checkInTime;
|
||||
final DateTime? checkOutTime;
|
||||
final String? activeShiftId;
|
||||
final String? activeApplicationId;
|
||||
|
||||
const AttendanceStatus({
|
||||
this.isCheckedIn = false,
|
||||
this.checkInTime,
|
||||
this.checkOutTime,
|
||||
this.activeShiftId,
|
||||
this.activeApplicationId,
|
||||
});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [
|
||||
isCheckedIn,
|
||||
checkInTime,
|
||||
checkOutTime,
|
||||
activeShiftId,
|
||||
activeApplicationId,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'coverage_worker.dart';
|
||||
|
||||
/// Domain entity representing a shift in the coverage view.
|
||||
///
|
||||
/// This is a feature-specific domain entity that encapsulates shift information
|
||||
/// including scheduling details and assigned workers.
|
||||
class CoverageShift extends Equatable {
|
||||
/// Creates a [CoverageShift].
|
||||
const CoverageShift({
|
||||
required this.id,
|
||||
required this.title,
|
||||
required this.location,
|
||||
required this.startTime,
|
||||
required this.workersNeeded,
|
||||
required this.date,
|
||||
required this.workers,
|
||||
});
|
||||
|
||||
/// The unique identifier for the shift.
|
||||
final String id;
|
||||
|
||||
/// The title or role of the shift.
|
||||
final String title;
|
||||
|
||||
/// The location where the shift takes place.
|
||||
final String location;
|
||||
|
||||
/// The start time of the shift (e.g., "16:00").
|
||||
final String startTime;
|
||||
|
||||
/// The number of workers needed for this shift.
|
||||
final int workersNeeded;
|
||||
|
||||
/// The date of the shift.
|
||||
final DateTime date;
|
||||
|
||||
/// The list of workers assigned to this shift.
|
||||
final List<CoverageWorker> workers;
|
||||
|
||||
/// Calculates the coverage percentage for this shift.
|
||||
int get coveragePercent {
|
||||
if (workersNeeded == 0) return 0;
|
||||
return ((workers.length / workersNeeded) * 100).round();
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[
|
||||
id,
|
||||
title,
|
||||
location,
|
||||
startTime,
|
||||
workersNeeded,
|
||||
date,
|
||||
workers,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
/// Domain entity representing coverage statistics.
|
||||
///
|
||||
/// Aggregates coverage metrics for a specific date.
|
||||
class CoverageStats extends Equatable {
|
||||
/// Creates a [CoverageStats].
|
||||
const CoverageStats({
|
||||
required this.totalNeeded,
|
||||
required this.totalConfirmed,
|
||||
required this.checkedIn,
|
||||
required this.enRoute,
|
||||
required this.late,
|
||||
});
|
||||
|
||||
/// The total number of workers needed.
|
||||
final int totalNeeded;
|
||||
|
||||
/// The total number of confirmed workers.
|
||||
final int totalConfirmed;
|
||||
|
||||
/// The number of workers who have checked in.
|
||||
final int checkedIn;
|
||||
|
||||
/// The number of workers en route.
|
||||
final int enRoute;
|
||||
|
||||
/// The number of late workers.
|
||||
final int late;
|
||||
|
||||
/// Calculates the overall coverage percentage.
|
||||
int get coveragePercent {
|
||||
if (totalNeeded == 0) return 0;
|
||||
return ((totalConfirmed / totalNeeded) * 100).round();
|
||||
}
|
||||
|
||||
@override
|
||||
List<Object?> get props => <Object?>[
|
||||
totalNeeded,
|
||||
totalConfirmed,
|
||||
checkedIn,
|
||||
enRoute,
|
||||
late,
|
||||
];
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user