Add initial mobile app prototypes and staff payments feature

Introduces the first versions of client and staff mobile application prototypes, including platform-specific assets, screens, and configuration for Android, iOS, macOS, Linux, and Windows. Adds documentation, AI prompt guides, and a new staff payments feature module with repository, use cases, and presentation logic. Also includes generated localization files and supporting resources for both client and staff apps.
This commit is contained in:
Achintha Isuru
2026-01-25 17:01:18 -05:00
parent 0b043ed91e
commit 19959a2b3f
468 changed files with 71399 additions and 0 deletions

View File

@@ -0,0 +1,75 @@
You are continuing work on an existing **Flutter monorepobased mobile system** with multiple applications and a shared data/connect layer.
This prompt **replaces all missing prior thread context** and must be treated as the **single source of truth** for how you reason, plan, and execute work in this thread.
## 🧭 PROJECT OVERVIEW
* The project contains **multiple Flutter applications** (e.g. Staff app, Client app) that are being **rebuilt from scratch** using **Flutter Clean Architecture**, while **reusing UI code and flows** from POCs (prototypes).
* The goal is to rebuild the mobile apps in a **production-grade, scalable, agent-first manner**, not as POCs.
## 🧠 YOUR ROLE IN THIS THREAD
You are acting as a **Senior Flutter Architect + Execution Agent**, responsible for:
* Enforcing architectural consistency across features
* Preventing scope creep, tight coupling, and shortcut implementations
* Producing outputs that are suitable for **real engineering teams**, not demos
You **do not** invent architecture, flows, or patterns unless explicitly asked.
You **do** challenge requirements if they violate architecture or agent rules.
## 📚 MANDATORY DOCUMENTS (NON-NEGOTIABLE)
You MUST strictly follow the rules and constraints defined in **both documents below** at all times:
### 1⃣ Architecture Principles
**apps/mobile/docs/01-architecture-principles.md**
This document defines:
* Clean Architecture boundaries
* Layer responsibilities (presentation / domain / data)
* Dependency rules
* Navigation, state management, and feature isolation expectations
and others.
### 2⃣ Agent Development Rules
**apps/mobile/docs/02-agent-development-rules.md**
This document defines:
* How features are planned, split, and executed
* What an agent may or may not do
* Output formats, assumptions, and guardrails
* How prompts must be structured for future reuse
and others.
### 3⃣ Design system guidelines
**apps/mobile/docs/03-design-system-usage.md**
This document defines:
* The design system of the project and the rules on how to use the design system.
⚠️ If a request conflicts with either document, you must:
* Call out the conflict explicitly
* Propose a compliant alternative
* Never silently violate the rules
## 🔁 CURRENT STATE
* Prior thread context is **not available**
* Architecture and agent rules **do exist** and must be referenced
* Any assumptions you make must be stated clearly
## ✅ ACKNOWLEDGEMENT REQUIRED
Before proceeding with any feature work, you must:
1. Acknowledge that this context has been loaded
2. Confirm adherence to:
* `apps/mobile/docs/01-architecture-principles.md`
* `apps/mobile/docs/02-agent-development-rules.md`
* `apps/mobile/docs/03-design-system-usage.md`
3. Wait for the next instruction or feature prompt

View File

@@ -0,0 +1,34 @@
You are an expert Flutter architect and monorepo engineer.
You are working on the KROW workforce management platform.
Your responsibility is to rebuild two Flutter mobile applications (Client + Staff)
using a clean, agent-first architecture.
You must strictly follow:
- Clean Architecture
- Feature-first packaging
- Melos monorepo conventions
- Bloc for state management
- Flutter Modular for
- Modularized routes.
- Modularized Dependency Injection.
- Firebase Data Connect as the ONLY backend access layer
- No UI polish unless explicitly requested
IMPORTANT CONSTRAINTS:
- Firebase Data Connect code DOES NOT EXIST YET
- You must mock Data Connect responses using interfaces and fake implementations
- Domain entities MUST match the provided KROW domain model exactly
- No DTOs or entities inside feature packages
- Features must be independently testable
- Do not invent new entities, statuses, or workflows
You must never:
- Access Firebase directly
- Hardcode backend logic inside UI
- Mix domain logic with presentation
- Change entity definitions unless explicitly instructed
If ambiguity exists, document it instead of guessing.
Confirm understanding silently and wait for step instructions.

View File

@@ -0,0 +1,54 @@
TASK: Create the KROW Flutter monorepo skeleton using Melos.
You must:
1. Create the directory structure exactly as defined below (some of the parts are already developed)
2. Initialize Melos (some of the parts are already developed)
3. Create minimal pubspec.yaml files where required (some of the parts are already developed)
4. Do NOT add application logic
5. Do NOT generate Flutter apps yet (basic strcuture of the apps/ are developed)
Target structure:
root/
├── apps/
│ ├── client/
│ ├── staff/
│ └── design_system_viewer/
├── packages/
│ ├── core/
│ ├── design_system/
│ ├── domain/
│ ├── data_connect/
│ └── features/
│ ├─ domain/
│ │ ├─ repositories/
│ │ └─ usecases/
│ │
│ ├─ data/
│ │ ├─ datasources/
│ │ └─ repositories_impl/
│ │
│ ├─ presentation/
│ │ ├─ state/
│ │ ├─ pages/
│ │ └─ widgets/
│ │
│ └─ feature_manifest.md
├── docs/
└── dataconnect/
Rules:
- Use Flutter 3.x compatible setup
- All packages must be melos-aware
- Keep pubspec files minimal
- No dependencies unless required for structure
- No example widgets or boilerplate UI
Output:
- melos.yaml
- Folder tree
- Minimal pubspec.yaml per package/app
- Short explanation of dependency boundaries
Do NOT proceed beyond skeleton creation.

View File

@@ -0,0 +1,19 @@
TASK: Create docs/02-agent-development-rules.md
This document defines NON-NEGOTIABLE rules for AI agents.
Must include:
- File creation rules
- Naming conventions
- Where logic is allowed / forbidden
- How to mock Data Connect safely
- How to introduce new features
- How to reuse prototype code without copying architecture mistakes
- Rules for handling ambiguity (must document, not assume)
Format:
- Clear numbered rules
- Short explanations
- Explicit "DO / DO NOT" sections
This document will be enforced strictly.

View File

@@ -0,0 +1,251 @@
TASK: Create the shared domain package.
Domain Details:
## 1. Core Domain Logic
### 1.1 Domain Entities Overview
The KROW platform has **49 domain entities** organized into 8 logical groups:
```
┌────────────────────────────────────────────────────────────────────┐
│ KROW DOMAIN MODEL │
├────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ USERS & │ │ BUSINESS & │ │ EVENTS & │ │
│ │ MEMBERSHIP │ │ ORGANIZATION│ │ SHIFTS │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ User │ │ Business │ │ Event │ │
│ │ Staff │ │ BusinessSet │ │ EventShift │ │
│ │ Membership │ │ Hub │ │ Position │ │
│ │ BizMember │ │ HubDept │ │ Assignment │ │
│ │ HubMember │ │ BizContract │ │ WorkSession │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ SKILLS & │ │ FINANCIAL │ │ RATINGS & │ │
│ │ CERTS │ │ PAYROLL │ │ PENALTIES │ │
│ ├─────────────┤ ├─────────────┤ ├─────────────┤ │
│ │ Skill │ │ Invoice │ │ StaffRating │ │
│ │ SkillCat │ │ InvoiceItem │ │ PenaltyLog │ │
│ │ StaffSkill │ │ InvDecline │ │ BizStaffPref│ │
│ │ Certificate │ │ StaffPayment│ │ │ │
│ │ SkillKit │ │ │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ STAFF │ │ SUPPORT │ │
│ │ PROFILE │ │ CONFIG │ │
│ ├─────────────┤ ├─────────────┤ │
│ │ EmergencyC │ │ Addon │ │
│ │ BankAccount │ │ Tag │ │
│ │ Accessibl │ │ Media │ │
│ │ Schedule │ │ WorkingArea │ │
│ └─────────────┘ └─────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘
```
### 1.2 Key Entity Definitions
#### User & Authentication
| Entity | Description | Key Fields |
|--------|-------------|------------|
| **User** | Base auth entity (Firebase) | `id`, `email`, `phone`, `role` |
| **Staff** | Worker profile | `auth_provider_id`, `name`, `email`, `phone`, `status`, `address`, `avatar`, `live_photo` |
| **Membership** | Polymorphic org membership | `user_id`, `memberable_id`, `memberable_type`, `role` |
**Staff Status Flow:**
```
registered → pending → completed_profile → verified → [active | blocked | inactive]
```
#### Business & Organization
| Entity | Description | Key Fields |
|--------|-------------|------------|
| **Business** | Client company | `name`, `registration`, `status`, `avatar` |
| **BusinessSetting** | Payroll config | `prefix`, `overtime`, `clock_in`, `clock_out` |
| **Hub** | Branch location | `business_id`, `name`, `address`, `status` |
| **HubDepartment** | Dept within hub | `hub_id`, `name` |
#### Events & Shifts
| Entity | Description | Key Fields |
|--------|-------------|------------|
| **Event** | Job posting | `business_id`, `hub_id`, `name`, `date`, `status`, `contract_type` |
| **EventShift** | Work session | `event_id`, `name`, `address` |
| **EventShiftPosition** | Job opening | `shift_id`, `skill_id`, `count`, `rate`, `start_time`, `end_time`, `break` |
| **EventShiftPositionStaff** | Assignment | `staff_id`, `position_id`, `status`, `clock_in`, `clock_out` |
**Event Status Flow:**
```
draft → pending → assigned → confirmed → active → finished → completed → closed
↘ under_review
```
**Assignment Status Flow:**
```
assigned → confirmed → ongoing → completed
↘ decline_by_staff → [penalty logged]
↘ canceled_by_staff → [penalty logged]
↘ no_showed → [penalty logged]
```
#### Skills & Certifications
| Entity | Description | Key Fields |
|--------|-------------|------------|
| **Skill** | Job category | `category_id`, `name`, `price` |
| **StaffSkill** | Worker qualification | `staff_id`, `skill_id`, `level`, `experience`, `status` |
| **Certificate** | Required credential | `name`, `required` |
| **SkillKit** | Uniform/equipment req | `skill_id`, `name`, `is_required`, `type` |
**Skill Levels:** `beginner` | `skilled` | `professional`
#### Financial & Payroll
| Entity | Description | Key Fields |
|--------|-------------|------------|
| **Invoice** | Business bill | `event_id`, `business_id`, `status`, `total`, `work_amount`, `addons_amount` |
| **InvoiceItem** | Line item | `invoice_id`, `staff_id`, `work_hours`, `rate`, `amounts` |
| **StaffPayment** | Worker payout | `staff_id`, `assignment_id`, `amount`, `status`, `paid_at` |
**Invoice Status Flow:**
```
open → disputed → resolved → verified → paid/reconciled
↘ overdue
```
### 1.3 Core Business Workflows
#### Workflow 1: Event Lifecycle
```mermaid
sequenceDiagram
participant Client as Client App
participant API as Backend API
participant Admin as Admin
participant Staff as Worker App
Note over Client,API: 1. Event Creation
Client->>API: Create Event with Shifts & Positions
API-->>Client: Event Created (Draft)
Client->>API: Publish Event
API-->>Client: Event Published
opt 2. Staff Assignment (Optional)
Note over Admin,API: Optional Staff Assignment
Admin->>API: Assign Staff to Shift
API-->>Admin: Assignment Confirmed
API->>Staff: Notification: New Shift
end
Note over Staff,API: 3. Shift Acceptance
Staff->>API: Accept Shift
API-->>Staff: Shift Confirmed
Note over Client,Staff: 4. Day of Event
Client->>Client: Generate QR Code
Staff->>Staff: Scan QR Code
Staff->>API: Clock In
Staff->>API: Clock Out
Note over Client,API: 5. Post-Event
Client->>API: Rate Staff
API->>API: Generate Invoice
Client->>API: Approve Invoice
```
#### Workflow 2: Staff Onboarding
```
1. Registration (Firebase Phone Auth)
├── Create Staff record (status: registered)
└── Profile created with auth_provider_id
2. Profile Completion
├── Personal info (name, email, address)
├── Avatar upload
├── Emergency contacts
└── Bank account details
3. Skills Declaration
├── Add skills with level/experience
└── Status: pending → verified (admin)
4. Certification Upload
├── Upload certificates
└── Status: pending → verified (admin)
5. Equipment Confirmation
├── Confirm uniforms per skill
├── Confirm equipment per skill
└── Upload photos as proof
6. Profile Submission
├── Complete verification checklist
└── Status: completed_profile → verified
```
#### Workflow 3: Payroll Calculation
```
Work Hours = (clock_out - clock_in) - break_duration
Overtime Rules:
├── Regular Hours (1x): hours <= 8
├── Overtime Hours (1.5x): 8 < hours <= 10
└── Doubletime Hours (2x): hours > 10
Payment = (regular_hours × rate × 1.0)
+ (overtime_hours × rate × 1.5)
+ (doubletime_hours × rate × 2.0)
+ addons_amount
```
You must:
1. Create domain entities for ALL KROW entities provided
2. Group entities by logical folders
3. Use immutable models
4. Do NOT add JSON, serialization, or Firebase annotations
5. Do NOT add business logic
6. Use enums for all status flows
7. Add Doc comments for readability of the code.
Entities MUST match:
- Names
- Fields
- Status flows
Include:
- Enums for status flows
- Value objects where appropriate
- Clear folder structure
Exclude:
- DTOs
- Repositories
- Firebase logic
- Validation logic
Create packages/domain/lib/domain.dart (barrel file)
This file must export ALL entities and enums.
All other packages will import ONLY:
import 'package:domain/domain.dart';
Must follow archtiecture principles defined in:
- docs/01-architecture-principles.md
Must Follow Agent rules defined in:
- docs/02-agent-development-rules.md
Output:
- Folder structure
- Dart files
- Short explanation of grouping strategy

View File

@@ -0,0 +1,26 @@
TASK: Create the data_connect package as a mockable abstraction layer.
You must:
1. Define abstract repositories for each domain group
2. Create fake/mock implementations using in-memory data
3. Simulate async GraphQL-style behavior
4. Ensure replaceability with real generated SDK later
Rules:
- No Firebase imports
- No HTTP
- No direct entity mutation
- Return domain entities ONLY
Must follow archtiecture principles defined in:
- docs/01-architecture-principles.md
Must Follow Agent rules defined in:
- docs/02-agent-development-rules.md
Include:
- Interfaces
- Fake implementations
- Clear TODO markers for real SDK replacement
This package must compile and be dependency-safe.

View File

@@ -0,0 +1,23 @@
Task is to reafactor an existing Flutter page so that it fully complies with the design system defined in:
- apps/mobile/docs/03-design-system-usage.md
## 📍 TARGET PAGE
File to refactor the widgets in:
- apps/mobile/packages/features/staff/profile_sections/compliance/tax_forms
/lib/src/presentation/pages
- apps/mobile/packages/features/staff/profile_sections/compliance/tax_forms
/lib/src/presentation/widgets
Example page to get inspiration as this page is fully complies with the design system guide mentioned above:
apps/mobile/packages/features/staff/authentication/lib/src/presentation/pages/profile_setup_page.dart
## 🎯 GOAL
Transform the existing page implementation so that it complies with the design guideline provieded.
## 🔒 STRICT RULES (NON-NEGOTIABLE)
While following the rules outlined in the document above you should also DO NOT remove or change existing functionality of the page, add doc comments and use named parameters in functions.
Proceed with the refactor now.

View File

@@ -0,0 +1,85 @@
# FEATURE EXECUTION WORKFLOW — Modular Feature Development
## APPLICATION TARGET
`apps/mobile/apps/staff`
## EXECUTION PLAN (MANDATORY 3-STEP PROCESS)
### Step 1: Prototype Implementation
- **Goal**: First move the entire UI(pages and widgets) and logic from the prototype into the new feature package without changes. The page in the new package should be an one-one of the POC page.
- **Action**: Create the package in the folder structure under `apps/mobile/packages/features/[domain]/[feature_name]`.
- **References**: Use the specified prototypes as the primary source of truth for UI/UX, logic and business logic.
- **MANDATORY**: The **Layout** and **Wireframing** from the prototype should stay **EXACTLY** as they are. Do not re-design the UX or move elements around.
- **Note**: Pages should end with `_page.dart` instead of `_screen.dart`.
### Step 2: Architecture & Clean Code Refactor
- **Goal**: Align the prototype code with the project's long-term standards.
- **Rules**:
- Follow `apps/mobile/docs/01-architecture-principles.md` (BLoC, Domain-Driven, Repository pattern).
- Move the logic into blocs, domain and data. Use only the `apps/mobile/packages/data_connect/lib/src/mocks` to retrive / add data. This should happen via the data layer (presentation (ui -> bloc) -> domain -> data).
- Apply Clean Code: Meaningful names, one responsibility per class, small methods. Add doc comments to the files, functions for better readability.
- No magic strings inside business logic.
### Step 3: Localization & Navigation Finalization
- **Goal**: Centralize resources and decouple routing.
- **Mandatory Requirements**:
1. **Centralized Localization**:
- Extract ALL strings to `apps/mobile/packages/core_localization/lib/src/l10n/en.i18n.json` (and `es`).
- Use a unique namespace for the feature (e.g., `t.feature_name.sub_section.key`).
- Remove `slang` dependencies from the feature; re-export `core_localization` instead.
2. **Typed Navigation**:
- Create `lib/src/presentation/navigation/[feature_name]_navigator.dart`.
- Implement an extension on `IModularNavigator` for all feature-specific routes.
- Replace all `Modular.to.pushNamed('/path')` with typed methods like `Modular.to.pushFeaturePage()`.
### Step 4: Design Matching & Design System Alignment
- **Goal**: Ensure the visual identity matches the Design System perfectly while maintaining the prototype's layout.
- **Action**: Follow `apps/mobile/docs/03-design-system-usage.md` (Section 10: POC → Themed workflow).
- **Mandatory Requirements**:
- **Colors**: Replace all hex codes or raw colors with `UiColors`.
- **Typography**: Replace all manual `TextStyle` with `UiTypography`.
- **Spacing/Radius**: Replace all magic numbers with `UiConstants`.
- **Icons**: Use `UiIcons` exclusively.
- **Policy**: Maintain the prototype's layout structure while upgrading the "atoms" and "molecules" to the Design System tokens.
---
# FEATURE SCOPE — Staff shifts Screen
This feature implements the **staff shifts screen** for the **Mobile Staff application**.
---
## PROTOTYPE REFERENCES (SOURCE OF TRUTH)
* `apps/mobile/prototypes/staff_mobile_application/lib/screens/worker/payments_screen.dart`
## WHERE THE FEATURE SHOULD RESIDE
This feature should reside in the feature `apps/mobile/packages/features/staff/payments`.
## ARCHITECTURE CONSTRAINTS (NON-NEGOTIABLE)
You MUST strictly follow:
1. `apps/mobile/docs/01-architecture-principles.md`
2. `apps/mobile/docs/02-agent-development-rules.md`
3. `apps/mobile/docs/03-design-system-usage.md`
4. `MEMORY[user_global]` (Clean Code & architectural decisions)
Violations must be **explicitly reported**, never silently ignored.
---
## REFERENCE IMPLEMENTATION
Use:
```
apps/mobile/packages/features/staff/authentication
```
as the **gold standard** for:
* Feature structure
* Navigation pattern
* Localization strategy
* Design system integration

View File

@@ -0,0 +1,6 @@
for the "apps/mobile/packages/features/staff/payments" feature
- Follow apps/mobile/docs/01-architecture-principles.md (BLoC, Domain-Driven, Repository pattern).
- Move the logic into blocs, domain and data. Use only the apps/mobile/packages/data_connect/lib/src/mocks to retrive / add data. This should happen via the data layer (presentation (ui -> bloc) -> domain -> data).
- Apply Clean Code: Meaningful names, one responsibility per class, small methods. Add doc comments to the files, functions for better readability.
No magic strings inside business logic.

View File

@@ -0,0 +1,66 @@
Task is to refactor an existing Flutter package so that it fully complies with the architecture rules defined in:
* `apps/mobile/docs/01-architecture-principles.md`
## TARGET PAGE
Package to refactor:
```
apps/mobile/packages/features/staff/shifts
```
Reference feature that already follows the architecture correctly (this is the GOLD STANDARD):
```
apps/mobile/packages/features/staff/authentication
```
## GOAL
Refactor the feature so that it strictly follows **KROW Clean Architecture principles**, while preserving **all existing behavior and UI output**.
The result must be structurally correct, testable, and aligned with feature-level responsibilities.
## STRICT RULES (NON-NEGOTIABLE)
You MUST follow **all** rules defined in:
* `apps/mobile/docs/01-architecture-principles.md`
Additionally, enforce the following:
### Architecture Rules
* The pages **MUST remain inside the feature package**
* The pages **MUST NOT import other features**
* Business logic **MUST NOT exist inside the page**
* State handling **MUST be moved to a Bloc/Cubit or external widget**
* Use cases **MUST live in `domain/`**
* Repository access **MUST go through abstractions**
### Presentation Rules
* Use `StatelessWidget` for pages
* If state is required:
* Move it to a Bloc/Cubit, OR
* Extract it into a separate widget file
* Use named parameters
* Add clear doc comments where structure or intent is non-obvious
### Safety Rules
* ❌ Do NOT remove existing functionality
* ❌ Do NOT change user-facing behavior
* ❌ Do NOT introduce new dependencies
* ❌ Do NOT break modular boundaries
## EXPECTED OUTPUT
* A refactored page that:
* Fully complies with `apps/mobile/docs/01-architecture-principles.md`
* Has clean separation of concerns
* Is easy to reason about and extend
* Any required supporting files (Bloc, use case, widget extraction) created **inside the same feature**
Proceed with the refactor now.

View File

@@ -0,0 +1,88 @@
Task is to refactor the **domain and data layers** of an existing feature so that they fully comply with the architecture rules defined in:
* `apps/mobile/docs/01-architecture-principles.md`
## 📍 TARGET FEATURE
Feature to refactor:
```
apps/mobile/packages/features/staff/payments
```
Files exist in:
```
lib/src/domain/
lib/src/data/
```
## 🏆 GOLD STANDARD REFERENCE
Use the following feature as the **gold standard implementation** for structure, responsibility split, and dependency direction:
```
apps/mobile/packages/features/staff/authentication
```
Follow its patterns for:
* Repository interfaces
* Use case design
* Data layer delegation
* Interaction with `apps/mobile/packages/data_connect`
## 🎯 GOAL
Refactor the feature so that its **Domain** and **Data** layers strictly follow **KROW Clean Architecture** as defined in `apps/mobile/docs/01-architecture-principles.md`.
The feature must rely on **shared Domain entities** and must delegate all data access through `apps/mobile/packages/data_connect`.
## STRICT RULES (NON-NEGOTIABLE)
You MUST follow **all rules defined in**:
* `apps/mobile/docs/01-architecture-principles.md`
In particular, ensure that:
* Domain uses **only entities from**:
```
apps/mobile/packages/domain/lib/src/entities
```
* Feature-level domain models are removed
* Repository interfaces live in the Domain layer
* Repository implementations live in the Data layer
* Domain does NOT return concrete data objects
* Usecases in the domain layer must be extended from the `apps/mobile/packages/core/lib/src/domain/usecases/usecase.dart`.
* If there are arguments in the usecases, they must be extended from the `apps/mobile/packages/core/lib/src/domain/arguments/usecase_argument.dart`. Example usecase is given below
- `apps/mobile/packages/features/staff/authentication/lib/src/domain/usecases/verify_otp_usecase.dart`
* Data layer does NOT contain business logic and not create objects only call the `apps/mobile/packages/data_connect`.
* All data access flows through `apps/mobile/packages/data_connect`
## DOCUMENTATION
* Add clear **doc comments** to all files you modify
* Document:
* Purpose of the file
* Role of the class or interface in the architecture
## SAFETY GUARANTEES
* Do NOT change existing behavior
* Do NOT break presentation layer contracts
* Do NOT bypass `apps/mobile/packages/data_connect`
## EXPECTED OUTPUT
* Domain layer aligned with `apps/mobile/docs/01-architecture-principles.md`
* Data layer aligned with `apps/mobile/docs/01-architecture-principles.md`
* Structure and patterns consistent with:
```
apps/mobile/packages/features/staff/authentication
```
* Clean, documented, and compliant implementation
Proceed with the refactor now.

View File

@@ -0,0 +1,49 @@
package io.flutter.plugins;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
/**
* Generated file. Do not edit.
* This file is generated by the Flutter tool based on the
* plugins that support the Android platform.
*/
@Keep
public final class GeneratedPluginRegistrant {
private static final String TAG = "GeneratedPluginRegistrant";
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.appcheck.FlutterFirebaseAppCheckPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin firebase_app_check, io.flutter.plugins.firebase.appcheck.FlutterFirebaseAppCheckPlugin", e);
}
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.auth.FlutterFirebaseAuthPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin firebase_auth, io.flutter.plugins.firebase.auth.FlutterFirebaseAuthPlugin", e);
}
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin firebase_core, io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin", 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 io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin shared_preferences_android, io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin", e);
}
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.urllauncher.UrlLauncherPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin url_launcher_android, io.flutter.plugins.urllauncher.UrlLauncherPlugin", e);
}
}
}

Binary file not shown.

160
apps/mobile/apps/client/android/gradlew vendored Executable file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
apps/mobile/apps/client/android/gradlew.bat vendored Executable file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,32 @@
#
# 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 --")

View File

@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#
command script import --relative-to-command-file flutter_lldb_helper.py

View File

@@ -0,0 +1,19 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GeneratedPluginRegistrant_h
#define GeneratedPluginRegistrant_h
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
NS_ASSUME_NONNULL_END
#endif /* GeneratedPluginRegistrant_h */

View File

@@ -0,0 +1,49 @@
//
// Generated file. Do not edit.
//
// clang-format off
#import "GeneratedPluginRegistrant.h"
#if __has_include(<firebase_app_check/FLTFirebaseAppCheckPlugin.h>)
#import <firebase_app_check/FLTFirebaseAppCheckPlugin.h>
#else
@import firebase_app_check;
#endif
#if __has_include(<firebase_auth/FLTFirebaseAuthPlugin.h>)
#import <firebase_auth/FLTFirebaseAuthPlugin.h>
#else
@import firebase_auth;
#endif
#if __has_include(<firebase_core/FLTFirebaseCorePlugin.h>)
#import <firebase_core/FLTFirebaseCorePlugin.h>
#else
@import firebase_core;
#endif
#if __has_include(<shared_preferences_foundation/SharedPreferencesPlugin.h>)
#import <shared_preferences_foundation/SharedPreferencesPlugin.h>
#else
@import shared_preferences_foundation;
#endif
#if __has_include(<url_launcher_ios/URLLauncherPlugin.h>)
#import <url_launcher_ios/URLLauncherPlugin.h>
#else
@import url_launcher_ios;
#endif
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[FLTFirebaseAppCheckPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAppCheckPlugin"]];
[FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]];
[FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]];
[SharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"SharedPreferencesPlugin"]];
[URLLauncherPlugin registerWithRegistrar:[registry registrarForPlugin:@"URLLauncherPlugin"]];
}
@end

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/url_launcher_linux-3.2.2/

View File

@@ -0,0 +1,11 @@
// 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/client
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

View File

@@ -0,0 +1,12 @@
#!/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/client"
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"

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_auth-6.1.4/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_core-4.4.0/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/url_launcher_windows-3.1.5/

View File

@@ -0,0 +1,19 @@
package io.flutter.plugins;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
/**
* Generated file. Do not edit.
* This file is generated by the Flutter tool based on the
* plugins that support the Android platform.
*/
@Keep
public final class GeneratedPluginRegistrant {
private static final String TAG = "GeneratedPluginRegistrant";
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
}
}

View File

@@ -0,0 +1,32 @@
#
# 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 --")

View File

@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#
command script import --relative-to-command-file flutter_lldb_helper.py

View File

@@ -0,0 +1,19 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GeneratedPluginRegistrant_h
#define GeneratedPluginRegistrant_h
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
NS_ASSUME_NONNULL_END
#endif /* GeneratedPluginRegistrant_h */

View File

@@ -0,0 +1,14 @@
//
// Generated file. Do not edit.
//
// clang-format off
#import "GeneratedPluginRegistrant.h"
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
}
@end

View File

@@ -0,0 +1,11 @@
// 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

View File

@@ -0,0 +1,12 @@
#!/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"

View File

@@ -0,0 +1,44 @@
package io.flutter.plugins;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
/**
* Generated file. Do not edit.
* This file is generated by the Flutter tool based on the
* plugins that support the Android platform.
*/
@Keep
public final class GeneratedPluginRegistrant {
private static final String TAG = "GeneratedPluginRegistrant";
public static void registerWith(@NonNull FlutterEngine flutterEngine) {
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.appcheck.FlutterFirebaseAppCheckPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin firebase_app_check, io.flutter.plugins.firebase.appcheck.FlutterFirebaseAppCheckPlugin", e);
}
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.auth.FlutterFirebaseAuthPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin firebase_auth, io.flutter.plugins.firebase.auth.FlutterFirebaseAuthPlugin", e);
}
try {
flutterEngine.getPlugins().add(new io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin firebase_core, io.flutter.plugins.firebase.core.FlutterFirebaseCorePlugin", 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 io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin());
} catch (Exception e) {
Log.e(TAG, "Error registering plugin shared_preferences_android, io.flutter.plugins.sharedpreferences.SharedPreferencesPlugin", e);
}
}
}

Binary file not shown.

160
apps/mobile/apps/staff/android/gradlew vendored Executable file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
apps/mobile/apps/staff/android/gradlew.bat vendored Executable file
View File

@@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1,32 @@
#
# 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 --")

View File

@@ -0,0 +1,5 @@
#
# Generated file, do not edit.
#
command script import --relative-to-command-file flutter_lldb_helper.py

View File

@@ -0,0 +1,19 @@
//
// Generated file. Do not edit.
//
// clang-format off
#ifndef GeneratedPluginRegistrant_h
#define GeneratedPluginRegistrant_h
#import <Flutter/Flutter.h>
NS_ASSUME_NONNULL_BEGIN
@interface GeneratedPluginRegistrant : NSObject
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry;
@end
NS_ASSUME_NONNULL_END
#endif /* GeneratedPluginRegistrant_h */

View File

@@ -0,0 +1,42 @@
//
// Generated file. Do not edit.
//
// clang-format off
#import "GeneratedPluginRegistrant.h"
#if __has_include(<firebase_app_check/FLTFirebaseAppCheckPlugin.h>)
#import <firebase_app_check/FLTFirebaseAppCheckPlugin.h>
#else
@import firebase_app_check;
#endif
#if __has_include(<firebase_auth/FLTFirebaseAuthPlugin.h>)
#import <firebase_auth/FLTFirebaseAuthPlugin.h>
#else
@import firebase_auth;
#endif
#if __has_include(<firebase_core/FLTFirebaseCorePlugin.h>)
#import <firebase_core/FLTFirebaseCorePlugin.h>
#else
@import firebase_core;
#endif
#if __has_include(<shared_preferences_foundation/SharedPreferencesPlugin.h>)
#import <shared_preferences_foundation/SharedPreferencesPlugin.h>
#else
@import shared_preferences_foundation;
#endif
@implementation GeneratedPluginRegistrant
+ (void)registerWithRegistry:(NSObject<FlutterPluginRegistry>*)registry {
[FLTFirebaseAppCheckPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAppCheckPlugin"]];
[FLTFirebaseAuthPlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseAuthPlugin"]];
[FLTFirebaseCorePlugin registerWithRegistrar:[registry registrarForPlugin:@"FLTFirebaseCorePlugin"]];
[SharedPreferencesPlugin registerWithRegistrar:[registry registrarForPlugin:@"SharedPreferencesPlugin"]];
}
@end

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_linux-2.2.1/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_linux-2.4.1/

View File

@@ -0,0 +1,11 @@
// 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

View File

@@ -0,0 +1,12 @@
#!/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"

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_auth-6.1.4/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/firebase_core-4.4.0/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/path_provider_windows-2.3.0/

View File

@@ -0,0 +1 @@
/Users/achinthaisuru/.pub-cache/hosted/pub.dev/shared_preferences_windows-2.4.1/

View File

@@ -0,0 +1,135 @@
# KROW Architecture Principles
This document is the **AUTHORITATIVE** source of truth for the KROW engineering architecture.
All agents and engineers must adhere strictly to these principles. Deviations are interpreted as errors.
## 1. High-Level Architecture
The KROW platform follows a strict **Clean Architecture** implementation within a **Melos Monorepo**.
Dependencies flow **inwards** towards the Domain.
```mermaid
graph TD
subgraph "Apps (Entry Points)"
ClientApp[apps/mobile/apps/client]
StaffApp[apps/mobile/apps/staff]
end
subgraph "Features (Presentation & Application)"
ClientFeature[apps/mobile/packages/features/client/jobs]
StaffFeature[apps/mobile/packages/features/staff/schedule]
SharedFeature[apps/mobile/packages/features/shared/auth]
end
subgraph "Interface Adapters"
DataConnect[apps/mobile/packages/data_connect]
DesignSystem[apps/mobile/packages/design_system]
end
subgraph "Core Domain"
Domain[apps/mobile/packages/domain]
Core[apps/mobile/packages/core]
end
%% Dependency Flow
ClientApp --> ClientFeature & SharedFeature
StaffApp --> StaffFeature & SharedFeature
ClientApp --> DataConnect
StaffApp --> DataConnect
ClientFeature & StaffFeature & SharedFeature --> Domain
ClientFeature & StaffFeature & SharedFeature --> DesignSystem
ClientFeature & StaffFeature & SharedFeature --> Core
DataConnect --> Domain
DataConnect --> Core
DesignSystem --> Core
Domain --> Core
%% Strict Barriers
linkStyle default stroke-width:2px,fill:none,stroke:gray
```
## 2. Repository Structure & Package Roles
### 2.1 Apps (`apps/mobile/apps/`)
- **Role**: Application entry points and Dependency Injection (DI) roots.
- **Responsibilities**:
- Initialize Flutter Modular.
- Assemble features into a navigation tree.
- Inject concrete implementations (from `data_connect`) into Feature packages.
- Configure environment-specific settings.
- **RESTRICTION**: NO business logic. NO UI widgets (except `App` and `Main`).
### 2.2 Features (`apps/mobile/packages/features/<APP_NAME>/<FEATURE_NAME>`)
- **Role**: Vertical slices of user-facing functionality.
- **Internal Structure**:
- `domain/`: Feature-specific Use Cases and Repository Interfaces.
- `data/`: Repository Implementations.
- `presentation/`:
- Pages, BLoCs, Widgets.
- For performance make the pages as `StatelessWidget` and move the state management to the BLoC or `StatefulWidget` to an external separate widget file.
- **Responsibilities**:
- **Presentation**: UI Pages, Modular Routes.
- **State Management**: BLoCs / Cubits.
- **Application Logic**: Use Cases.
- **RESTRICTION**: Features MUST NOT import other features. Communication happens via shared domain events.
### 2.3 Domain (`apps/mobile/packages/domain`)
- **Role**: The stable heart of the system. Pure Dart.
- **Responsibilities**:
- **Entities**: Immutable data models (Data Classes).
- **Failures**: Domain-specific error types.
- **RESTRICTION**: NO Flutter dependencies. NO `json_annotation`. NO package dependencies (except `equatable`).
### 2.4 Data Connect (`apps/mobile/packages/data_connect/lib/src/mocks`)
- **Role**: Interface Adapter for Backend Access (Datasource Layer).
- **Responsibilities**:
- Implement low-level Datasources or generated SDK wrappers.
- map Domain Entities to/from Firebase Data Connect generated code.
- Handle Firebase exceptions.
- For now use the mock repositories to connect to the features, not the dataconnect_generated.
### 2.5 Design System (`apps/mobile/packages/design_system`)
- **Role**: Visual language and component library.
- **Responsibilities**:
- UI components if needed. But mostly try to modify the theme file (apps/mobile/packages/design_system/lib/src/ui_theme.dart) so we can directly use the theme in the app, to use the default material widgets.
- If not possible, and if that specific widget is used in multiple features, then try to create a shared widget in the `apps/mobile/packages/design_system/widgets`.
- Theme definitions (Colors, Typography).
- Assets (Icons, Images).
- More details on how to use this package is available in the `apps/mobile/docs/03-design-system-usage.md`.
- **RESTRICTION**:
- CANNOT change colours or typography.
- Dumb widgets only. NO business logic. NO state management (Bloc).
- More details on how to use this package is available in the `apps/mobile/docs/03-design-system-usage.md`.
### 2.6 Core (`apps/mobile/packages/core`)
- **Role**: Cross-cutting concerns.
- **Responsibilities**:
- Extension methods.
- Logger configuration.
- Base classes for Use Cases or Result types (functional error handling).
## 3. Dependency Direction & Boundaries
1. **Domain Independence**: `apps/mobile/packages/domain` knows NOTHING about the outer world. It defines *what* needs to be done, not *how*.
2. **UI Agnosticism**: `apps/mobile/packages/features` depends on `apps/mobile/packages/design_system` for looks and `apps/mobile/packages/domain` for logic. It does NOT know about Firebase.
3. **Data Isolation**: `apps/mobile/packages/data_connect` depends on `apps/mobile/packages/domain` to know what interfaces to implement. It does NOT know about the UI.
## 4. Firebase Data Connect Strategy
Since Firebase Data Connect code does not yet exist, we adhere to a **Strict Mocking Strategy**:
1. **Interface First**: All data requirements are first defined as `abstract interface class IRepository` in `apps/mobile/packages/domain`.
2. **Mock Implementation**:
- Inside `apps/mobile/packages/data_connect`, create a `MockRepository` implementation.
- Use in-memory lists or hardcoded futures to simulate backend responses.
- **CRITICAL**: Do NOT put mocks in `test/` folders if they are needed to run the app in "dev" mode. Put them in `lib/src/mocks/`.
3. **Future Integration**: When Data Connect is ready, we will add `RealRepository` in `apps/mobile/packages/data_connect`.
4. **Injection**: `apps/mobile/apps/` will inject either `MockRepository` or `RealRepository` based on build flags or environment variables.
## 5. Feature Isolation
- **Zero Direct Imports**: `import 'package:feature_a/...'` is FORBIDDEN inside `package:feature_b`.
- **Navigation**: Use string-based routes or a shared route definition module in `core` (if absolutely necessary) to navigate between features.
- **Data Sharing**: Features do not share state directly. They share data via the underlying `Domain` repositories (e.g., both observe the same `User` stream from `AuthRepository`).

View File

@@ -0,0 +1,83 @@
# Agent Development Rules
These rules are **NON-NEGOTIABLE**. They are designed to prevent architectural degradation by automated agents.
## 1. File Creation & Structure
1. **Feature-First Packaging**:
* **DO**: Create new features as independent packages in `apps/mobile/packages/features/<feature_name>`.
* **DO NOT**: Add features to `apps/mobile/packages/core` or existing apps directly.
2. **Path Conventions**:
* Entities: `apps/mobile/packages/domain/lib/src/entities/<entity>.dart`
* Repositories (Interface): `apps/mobile/packages/<feature>/lib/src/domain/repositories/<name>_repository_interface.dart`
* Repositories (Impl): `apps/mobile/packages/<feature>/lib/src/data/repositories_impl/<name>_repository_impl.dart`
* Use Cases: `apps/mobile/packages/<feature>/lib/src/application/<name>_usecase.dart`
* BLoCs: `apps/mobile/packages/<feature>/lib/src/presentation/blocs/<name>_bloc.dart`
* Pages: `apps/mobile/packages/<feature>/lib/src/presentation/pages/<name>_page.dart`
3. **Barrel Files**:
* **DO**: Use `export` in `lib/<package_name>.dart` only for public APIs.
* **DO NOT**: Export internal implementation details (like mocks or helper widgets) in the main package file.
## 2. Naming Conventions
Follow Dart standards strictly.
| Type | Convention | Example |
| :--- | :--- | :--- |
| **Files** | `snake_case` | `user_profile_page.dart` |
| **Classes** | `PascalCase` | `UserProfilePage` |
| **Variables** | `camelCase` | `userProfile` |
| **Interfaces** | terminate with `Interface` | `AuthRepositoryInterface` |
| **Implementations** | terminate with `Impl` | `FirebaseDataConnectAuthRepositoryImpl` |
| **Mocks** | terminate with `Mock` | `AuthRepositoryMock` |
## 3. Logic Placement (Strict Boundaries)
* **Business Rules**: MUST reside in **Use Cases** (Domain/Feature Application layer).
* *Forbidden*: Placing business rules in BLoCs or Widgets.
* **State Logic**: MUST reside in **BLoCs**.
* *Forbidden*: `setState` in Pages (except for purely ephemeral UI animations).
* **Data Transformation**: MUST reside in **Repositories** (Data Connect layer).
* *Forbidden*: Parsing JSON in the UI or Domain.
* **Navigation Logic**: MUST reside in **Modular Routes**.
* *Forbidden*: `Navigator.push` with hardcoded widgets.
## 4. Data Connect Mocking Strategy
Since the backend does not exist, you must mock strictly:
1. **Define Interface**: Create `abstract interface class <name>RepositoryInterface` in `apps/mobile/packages/<feature>/lib/src/domain/repositories/<name>_repository_interface.dart`.
2. **Create Mock**: Create `class MockRepository implements IRepository` in `apps/mobile/packages/data_connect/lib/src/mocks/`.
3. **Fake Data**: Return hardcoded `Future`s with realistic dummy entities.
4. **Injection**: Register the `MockRepository` in the `AppModule` (in `apps/mobile/apps/client` or `apps/mobile/apps/staff`) until the real implementation exists.
**DO NOT** use `mockito` or `mocktail` for these *runtime* mocks. Use simple fake classes.
## 5. Prototype Migration Rules
You have access to `prototypes/` folders. When migrating code:
1. **Extract Assets**:
* You MAY copy icons, images, and colors. But they should be tailored to the current design system. Do not change the colours and typgorahys in the design system. They are final. And you have to use these in the UI.
* When you matching colous and typography, from the POC match it with the design system and use the colors and typography from the design system. As mentioned in the `apps/mobile/docs/03-design-system-usage.md`.
2. **Extract Layouts**: You MAY copy `build` methods for UI structure.
3. **REJECT Architecture**: You MUST **NOT** copy the `GetX`, `Provider`, or `MVC` patterns often found in prototypes. Refactor immediately to **Bloc + Clean Architecture with Flutter Modular and Melos**.
## 6. Handling Ambiguity
If a user request is vague:
1. **STOP**: Do not guess domain fields or workflows.
2. **ANALYZE**:
- For architecture related questions, refer to `apps/mobile/docs/01-architecture-principles.md` or existing code.
- For design system related questions, refer to `apps/mobile/docs/03-design-system-usage.md` or existing code.
3. **DOCUMENT**: If you must make an assumption to proceed, add a comment `// ASSUMPTION: <explanation>` and mention it in your final summary.
4. **ASK**: Prefer asking the user for clarification on business rules (e.g., "Should a 'Job' have a 'status'?").
## 7. Dependencies
* **DO NOT** add 3rd party packages without checking `apps/mobile/packages/core` first.
* **DO NOT** add `firebase_auth` or `cloud_firestore` to any Feature package. They belong in `data_connect` only.
## 8. Follow Clean Code Principles
* Add doc comments to all classes and methods you create.

View File

@@ -0,0 +1,131 @@
# 03 - Design System Usage Guide
This document defines the mandatory standards for designing and implementing user interfaces across all applications and feature packages using the shared `apps/mobile/packages/design_system`.
## 1. Introduction & Purpose
The Design System is the single source of truth for the visual identity of the project. Its purpose is to ensure UI consistency, reduce development velocity by providing reusable primitives, and eliminate "design drift" across multiple feature teams and applications.
**All UI implementation MUST consume values ONLY from the `design_system` package.**
## 2. Design System Ownership & Responsibility
- **Centralized Authority**: The `apps/mobile/packages/design_system` is the owner of all brand assets, colors, typography, and core components.
- **No Local Overrides**: Feature packages (e.g., `staff_authentication`) are consumers. They are prohibited from defining their own global styles or overriding theme values locally.
- **Extension Policy**: If a required style (color, font, or icon) is missing, the developer must first add it to the `design_system` package following existing patterns before using it in a feature.
## 3. Package Structure Overview (`apps/mobile/packages/design_system`)
The package is organized to separate tokens from implementation:
- `lib/src/ui_colors.dart`: Color tokens and semantic mappings.
- `lib/src/ui_typography.dart`: Text styles and font configurations.
- `lib/src/ui_icons.dart`: Exported icon sets.
- `lib/src/ui_constants.dart`: Spacing, radius, and elevation tokens.
- `lib/src/ui_theme.dart`: Centralized `ThemeData` factory.
- `lib/src/widgets/`: Common "Smart Widgets" and reusable UI building blocks.
## 4. Colors Usage Rules
Feature packages **MUST NOT** define custom hex codes or `Color` constants.
### Usage Protocol
- **Primary Method**:Use `UiColors` from the design system for specific brand accents.
- **Naming Matching**: If an exact color is missing, use the closest existing semantic color (e.g., use `UiColors.mutedForeground` instead of a hardcoded grey).
```dart
// ❌ ANTI-PATTERN: Hardcoded color
Container(color: Color(0xFF1A2234))
// ✅ CORRECT: Design system token
Container(color: UiColors.background)
```
## 5. Typography Usage Rules
Custom `TextStyle` definitions in feature packages are **STRICTLY PROHIBITED**.
### Usage Protocol
- Use `UiTypography` from the design system for specific brand accents.
```dart
// ❌ ANTI-PATTERN: Custom TextStyle
Text('Hello', style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold))
// ✅ CORRECT: Design system typography
Text('Hello', style: UiTypography.display1m)
```
## 6. Icons Usage Rules
Feature packages **MUST NOT** import icon libraries (like `lucide_icons`) directly. They should use the icons exposed via `UiIcons`.
- **Standardization**: Ensure the same icon is used for the same action across all features (e.g., always use `UiIcons.chevronLeft` for navigation).
- **Additions**: New icons must be added to the design system (only using the typedef _IconLib = LucideIcons or typedef _IconLib2 = FontAwesomeIcons; and nothing else) first to ensure they follow the project's stroke weight and sizing standards.
## 7. UI Constants & Layout Rules
Hardcoded padding, margins, and radius values are **PROHIBITED**.
- **Spacing**: Use `UiConstants.spacing` multiplied by tokens (e.g., `S`, `M`, `L`).
- **Border Radius**: Use `UiConstants.borderRadius`.
- **Elevation**: Use `UiConstants.elevation`.
```dart
// ✅ CORRECT: Spacing and Radius constants
Padding(
padding: EdgeInsets.all(UiConstants.spacingL),
child: Container(
borderRadius: BorderRadius.circular(UiConstants.radiusM),
),
)
```
## 8. Common Smart Widgets Guidelines
The design system provides "Smart Widgets" these are high-level UI components that encapsulate both styling and standard behavior.
- **Standard Widgets**: Prefer standard Flutter Material widgets (e.g., `ElevatedButton`) but styled via the central theme.
- **Custom Components**: Use `design_system` widgets for non-standard elements or wisgets that has similar design across various features, if provided.
- **Composition**: Prefer composing standard widgets over creating deep inheritance hierarchies in features.
## 9. Theme Configuration & Usage
Applications (`apps/mobile/apps/`) must initialize the theme once in the root `MaterialApp`.
```dart
MaterialApp.router(
theme: StaffTheme.light, // Mandatory: Consumption of centralized theme
// ...
)
```
**No application-level theme customization is allowed.**
## 10. Feature Development Workflow (POC → Themed)
To bridge the gap between rapid prototyping (POCs) and production-grade code, developers must follow this three-step workflow:
1. **Step 1: Structural Implementation**: Implement the UI logic and layout **exactly matching the POC**. Hardcoded values from the POC are acceptable in this transient state to ensure visual parity.
2. **Step 2: Logic Refactor**: Immediately refactor the code to:
- Follow the `apps/mobile/docs/01-architecture-principles.md` and `apps/mobile/docs/02-agent-development-rules.md` to refactor the code.
3. **Step 3: Theme Refactor**: Immediately refactor the code to:
- Replace hex codes with `UiColors`.
- Replace manual `TextStyle` with `UiTypography`.
- Replace hardcoded padding/radius with `UiConstants`.
- Upgrade icons to design system versions.
## 11. Anti-Patterns & Common Mistakes
- **"Magic Numbers"**: Hardcoding `EdgeInsets.all(12.0)` instead of using design system constants.
- **Local Themes**: Using `Theme(data: ...)` to override colors for a specific section of a page.
- **Hex Hunting**: Copy-pasting hex codes from Figma or POCs into feature code.
- **Package Bypassing**: Importing `package:flutter/material.dart` and ignoring `package:design_system`.
## 12. Enforcement & Review Checklist
Before any UI code is merged, it must pass this checklist:
1. [ ] No hardcoded `Color(...)` or `0xFF...` in the feature package.
2. [ ] No custom `TextStyle(...)` definitions.
3. [ ] All spacing/padding/radius uses `UiConstants`.
4. [ ] All icons are consumed from the approved design system source.
5. [ ] The feature relies on the global `ThemeData` and does not provide local overrides.
6. [ ] The layout matches the POC visual intent and element placement(wireframing and logic) while using the design system primitives.

0
apps/mobile/docs/04- Normal file
View File

View File

@@ -0,0 +1,183 @@
/// Generated file. Do not edit.
///
/// Source: packages/core_localization/lib/src/l10n
/// To regenerate, run: `dart run slang`
///
/// Locales: 2
/// Strings: 816 (408 per locale)
///
/// Built on 2026-01-25 at 02:11 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

View File

@@ -0,0 +1,183 @@
/// Generated file. Do not edit.
///
/// Source: lib/src/l10n
/// To regenerate, run: `dart run slang`
///
/// Locales: 2
/// Strings: 1004 (502 per locale)
///
/// Built on 2026-01-25 at 22:00 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

View File

@@ -0,0 +1,15 @@
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/payments_repository.dart';
class PaymentsRepositoryImpl implements PaymentsRepository {
final FinancialRepositoryMock financialRepository;
PaymentsRepositoryImpl({required this.financialRepository});
@override
Future<List<StaffPayment>> getPayments() async {
// TODO: Get actual logged in staff ID
return await financialRepository.getStaffPayments('staff_1');
}
}

View File

@@ -1,3 +1,4 @@
<<<<<<< Updated upstream
import '../entities/payment_summary.dart'; import '../entities/payment_summary.dart';
import '../entities/payment_transaction.dart'; import '../entities/payment_transaction.dart';
@@ -7,4 +8,11 @@ abstract class PaymentsRepository {
/// Fetches the list of recent payment transactions (history). /// Fetches the list of recent payment transactions (history).
Future<List<PaymentTransaction>> getPaymentHistory(String period); Future<List<PaymentTransaction>> getPaymentHistory(String period);
=======
import 'package:krow_domain/krow_domain.dart';
abstract class PaymentsRepository {
/// Fetches the list of payments.
Future<List<StaffPayment>> getPayments();
>>>>>>> Stashed changes
} }

View File

@@ -1,12 +1,27 @@
<<<<<<< Updated upstream
import '../entities/payment_transaction.dart'; import '../entities/payment_transaction.dart';
import '../repositories/payments_repository.dart'; import '../repositories/payments_repository.dart';
class GetPaymentHistoryUseCase { class GetPaymentHistoryUseCase {
=======
import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../repositories/payments_repository.dart';
class GetPaymentHistoryUseCase extends UseCase<String, List<StaffPayment>> {
>>>>>>> Stashed changes
final PaymentsRepository repository; final PaymentsRepository repository;
GetPaymentHistoryUseCase(this.repository); GetPaymentHistoryUseCase(this.repository);
<<<<<<< Updated upstream
Future<List<PaymentTransaction>> call({String period = 'week'}) async { Future<List<PaymentTransaction>> call({String period = 'week'}) async {
return await repository.getPaymentHistory(period); return await repository.getPaymentHistory(period);
=======
@override
Future<List<StaffPayment>> call(String period) async {
// TODO: Implement filtering by period
return await repository.getPayments();
>>>>>>> Stashed changes
} }
} }

View File

@@ -1,12 +1,26 @@
<<<<<<< Updated upstream
import '../entities/payment_summary.dart'; import '../entities/payment_summary.dart';
import '../repositories/payments_repository.dart'; import '../repositories/payments_repository.dart';
class GetPaymentSummaryUseCase { class GetPaymentSummaryUseCase {
=======
import 'package:krow_core/core.dart';
import 'package:krow_domain/krow_domain.dart';
import '../repositories/payments_repository.dart';
class GetPaymentSummaryUseCase extends NoInputUseCase<List<StaffPayment>> {
>>>>>>> Stashed changes
final PaymentsRepository repository; final PaymentsRepository repository;
GetPaymentSummaryUseCase(this.repository); GetPaymentSummaryUseCase(this.repository);
<<<<<<< Updated upstream
Future<PaymentSummary> call() async { Future<PaymentSummary> call() async {
return await repository.getPaymentSummary(); return await repository.getPaymentSummary();
=======
@override
Future<List<StaffPayment>> call() async {
return await repository.getPayments();
>>>>>>> Stashed changes
} }
} }

View File

@@ -1,18 +1,31 @@
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
<<<<<<< Updated upstream
import 'domain/repositories/payments_repository.dart'; import 'domain/repositories/payments_repository.dart';
import 'domain/usecases/get_payment_summary_usecase.dart'; import 'domain/usecases/get_payment_summary_usecase.dart';
import 'domain/usecases/get_payment_history_usecase.dart'; import 'domain/usecases/get_payment_history_usecase.dart';
import 'data/datasources/payments_remote_datasource.dart'; import 'data/datasources/payments_remote_datasource.dart';
import 'data/datasources/payments_mock_datasource.dart'; import 'data/datasources/payments_mock_datasource.dart';
import 'data/repositories/payments_repository_impl.dart'; import 'data/repositories/payments_repository_impl.dart';
=======
import 'package:krow_data_connect/krow_data_connect.dart';
import 'domain/repositories/payments_repository.dart';
import 'domain/usecases/get_payment_summary_usecase.dart';
import 'domain/usecases/get_payment_history_usecase.dart';
import 'data/repositories_impl/payments_repository_impl.dart';
>>>>>>> Stashed changes
import 'presentation/blocs/payments/payments_bloc.dart'; import 'presentation/blocs/payments/payments_bloc.dart';
import 'presentation/pages/payments_page.dart'; import 'presentation/pages/payments_page.dart';
class StaffPaymentsModule extends Module { class StaffPaymentsModule extends Module {
@override @override
void binds(Injector i) { void binds(Injector i) {
<<<<<<< Updated upstream
// Data Sources // Data Sources
i.add<PaymentsRemoteDataSource>(PaymentsMockDataSource.new); i.add<PaymentsRemoteDataSource>(PaymentsMockDataSource.new);
=======
// Data Connect Mocks
i.add<FinancialRepositoryMock>(FinancialRepositoryMock.new);
>>>>>>> Stashed changes
// Repositories // Repositories
i.add<PaymentsRepository>(PaymentsRepositoryImpl.new); i.add<PaymentsRepository>(PaymentsRepositoryImpl.new);

View File

@@ -1,8 +1,15 @@
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
<<<<<<< Updated upstream
import '../../../domain/entities/payment_summary.dart'; import '../../../domain/entities/payment_summary.dart';
import '../../../domain/entities/payment_transaction.dart'; import '../../../domain/entities/payment_transaction.dart';
import '../../../domain/usecases/get_payment_summary_usecase.dart'; import '../../../domain/usecases/get_payment_summary_usecase.dart';
import '../../../domain/usecases/get_payment_history_usecase.dart'; import '../../../domain/usecases/get_payment_history_usecase.dart';
=======
import 'package:krow_domain/krow_domain.dart';
import '../../../domain/usecases/get_payment_summary_usecase.dart';
import '../../../domain/usecases/get_payment_history_usecase.dart';
import '../../models/payment_stats.dart';
>>>>>>> Stashed changes
import 'payments_event.dart'; import 'payments_event.dart';
import 'payments_state.dart'; import 'payments_state.dart';
@@ -24,10 +31,19 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
) async { ) async {
emit(PaymentsLoading()); emit(PaymentsLoading());
try { try {
<<<<<<< Updated upstream
final PaymentSummary summary = await getPaymentSummary(); final PaymentSummary summary = await getPaymentSummary();
final List<PaymentTransaction> history = await getPaymentHistory(period: 'week'); final List<PaymentTransaction> history = await getPaymentHistory(period: 'week');
emit(PaymentsLoaded( emit(PaymentsLoaded(
summary: summary, summary: summary,
=======
final List<StaffPayment> allPayments = await getPaymentSummary();
final PaymentStats stats = _calculateStats(allPayments);
final List<StaffPayment> history = await getPaymentHistory('week');
emit(PaymentsLoaded(
summary: stats,
>>>>>>> Stashed changes
history: history, history: history,
activePeriod: 'week', activePeriod: 'week',
)); ));
@@ -44,10 +60,15 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
if (currentState is PaymentsLoaded) { if (currentState is PaymentsLoaded) {
if (currentState.activePeriod == event.period) return; if (currentState.activePeriod == event.period) return;
<<<<<<< Updated upstream
// Optimistic update or set loading state if expecting delay // Optimistic update or set loading state if expecting delay
// For now, we'll keep the current data and fetch new history // For now, we'll keep the current data and fetch new history
try { try {
final List<PaymentTransaction> newHistory = await getPaymentHistory(period: event.period); final List<PaymentTransaction> newHistory = await getPaymentHistory(period: event.period);
=======
try {
final List<StaffPayment> newHistory = await getPaymentHistory(event.period);
>>>>>>> Stashed changes
emit(currentState.copyWith( emit(currentState.copyWith(
history: newHistory, history: newHistory,
activePeriod: event.period, activePeriod: event.period,
@@ -57,4 +78,41 @@ class PaymentsBloc extends Bloc<PaymentsEvent, PaymentsState> {
} }
} }
} }
<<<<<<< Updated upstream
=======
PaymentStats _calculateStats(List<StaffPayment> payments) {
double total = 0;
double pending = 0;
double weekly = 0;
double monthly = 0;
final DateTime now = DateTime.now();
for (final StaffPayment p in payments) {
// Assuming all payments count towards total history
total += p.amount;
if (p.status == PaymentStatus.pending) {
pending += p.amount;
}
if (p.paidAt != null) {
if (now.difference(p.paidAt!).inDays < 7) {
weekly += p.amount;
}
if (now.month == p.paidAt!.month && now.year == p.paidAt!.year) {
monthly += p.amount;
}
}
}
return PaymentStats(
totalEarnings: total,
pendingEarnings: pending,
weeklyEarnings: weekly,
monthlyEarnings: monthly,
);
}
>>>>>>> Stashed changes
} }

View File

@@ -1,6 +1,11 @@
import 'package:equatable/equatable.dart'; import 'package:equatable/equatable.dart';
<<<<<<< Updated upstream
import '../../../domain/entities/payment_summary.dart'; import '../../../domain/entities/payment_summary.dart';
import '../../../domain/entities/payment_transaction.dart'; import '../../../domain/entities/payment_transaction.dart';
=======
import 'package:krow_domain/krow_domain.dart';
import '../../models/payment_stats.dart';
>>>>>>> Stashed changes
abstract class PaymentsState extends Equatable { abstract class PaymentsState extends Equatable {
const PaymentsState(); const PaymentsState();
@@ -14,8 +19,13 @@ class PaymentsInitial extends PaymentsState {}
class PaymentsLoading extends PaymentsState {} class PaymentsLoading extends PaymentsState {}
class PaymentsLoaded extends PaymentsState { class PaymentsLoaded extends PaymentsState {
<<<<<<< Updated upstream
final PaymentSummary summary; final PaymentSummary summary;
final List<PaymentTransaction> history; final List<PaymentTransaction> history;
=======
final PaymentStats summary;
final List<StaffPayment> history;
>>>>>>> Stashed changes
final String activePeriod; final String activePeriod;
const PaymentsLoaded({ const PaymentsLoaded({
@@ -25,8 +35,13 @@ class PaymentsLoaded extends PaymentsState {
}); });
PaymentsLoaded copyWith({ PaymentsLoaded copyWith({
<<<<<<< Updated upstream
PaymentSummary? summary, PaymentSummary? summary,
List<PaymentTransaction>? history, List<PaymentTransaction>? history,
=======
PaymentStats? summary,
List<StaffPayment>? history,
>>>>>>> Stashed changes
String? activePeriod, String? activePeriod,
}) { }) {
return PaymentsLoaded( return PaymentsLoaded(

View File

@@ -0,0 +1,23 @@
import 'package:equatable/equatable.dart';
class PaymentStats extends Equatable {
final double weeklyEarnings;
final double monthlyEarnings;
final double pendingEarnings;
final double totalEarnings;
const PaymentStats({
this.weeklyEarnings = 0.0,
this.monthlyEarnings = 0.0,
this.pendingEarnings = 0.0,
this.totalEarnings = 0.0,
});
@override
List<Object?> get props => [
weeklyEarnings,
monthlyEarnings,
pendingEarnings,
totalEarnings,
];
}

View File

@@ -3,7 +3,11 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_modular/flutter_modular.dart'; import 'package:flutter_modular/flutter_modular.dart';
import 'package:lucide_icons/lucide_icons.dart'; import 'package:lucide_icons/lucide_icons.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
<<<<<<< Updated upstream
import '../../domain/entities/payment_transaction.dart'; import '../../domain/entities/payment_transaction.dart';
=======
import 'package:krow_domain/krow_domain.dart';
>>>>>>> Stashed changes
import '../blocs/payments/payments_bloc.dart'; import '../blocs/payments/payments_bloc.dart';
import '../blocs/payments/payments_event.dart'; import '../blocs/payments/payments_event.dart';
import '../blocs/payments/payments_state.dart'; import '../blocs/payments/payments_state.dart';
@@ -177,11 +181,16 @@ class _PaymentsPageState extends State<PaymentsPage> {
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
Column( Column(
<<<<<<< Updated upstream
children: state.history.map((PaymentTransaction payment) { children: state.history.map((PaymentTransaction payment) {
=======
children: state.history.map((StaffPayment payment) {
>>>>>>> Stashed changes
return Padding( return Padding(
padding: const EdgeInsets.only(bottom: 8), padding: const EdgeInsets.only(bottom: 8),
child: PaymentHistoryItem( child: PaymentHistoryItem(
amount: payment.amount, amount: payment.amount,
<<<<<<< Updated upstream
title: payment.title, title: payment.title,
location: payment.location, location: payment.location,
address: payment.address, address: payment.address,
@@ -190,6 +199,16 @@ class _PaymentsPageState extends State<PaymentsPage> {
hours: payment.hours, hours: payment.hours,
rate: payment.rate, rate: payment.rate,
status: payment.status, status: payment.status,
=======
title: 'Assignment ${payment.assignmentId}',
location: 'Location', // TODO: Fetch from assignment
address: '',
date: payment.paidAt != null ? DateFormat('E, MMM d').format(payment.paidAt!) : 'Pending',
workedTime: '00:00 - 00:00', // TODO: Fetch from assignment
hours: 0,
rate: 0,
status: payment.status.toString().split('.').last,
>>>>>>> Stashed changes
), ),
); );
}).toList(), }).toList(),

View File

@@ -2,9 +2,16 @@ name: staff_payments
description: Staff Payments feature description: Staff Payments feature
version: 0.0.1 version: 0.0.1
publish_to: 'none' publish_to: 'none'
<<<<<<< Updated upstream
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
=======
resolution: workspace
environment:
sdk: '>=3.10.0 <4.0.0'
>>>>>>> Stashed changes
flutter: ">=3.0.0" flutter: ">=3.0.0"
dependencies: dependencies:
@@ -21,6 +28,11 @@ dependencies:
path: ../../../core_localization path: ../../../core_localization
krow_domain: krow_domain:
path: ../../../domain path: ../../../domain
<<<<<<< Updated upstream
=======
krow_core:
path: ../../../core
>>>>>>> Stashed changes
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@@ -0,0 +1,45 @@
# Miscellaneous
*.class
*.log
*.pyc
*.swp
.DS_Store
.atom/
.build/
.buildlog/
.history
.svn/
.swiftpm/
migrate_working_dir/
# IntelliJ related
*.iml
*.ipr
*.iws
.idea/
# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
# Flutter/Dart/Pub related
**/doc/api/
**/ios/Flutter/.last_build_id
.dart_tool/
.flutter-plugins-dependencies
.pub-cache/
.pub/
/build/
/coverage/
# Symbolication related
app.*.symbols
# Obfuscation related
app.*.map.json
# Android Studio will place build artifacts here
/android/app/debug
/android/app/profile
/android/app/release

View File

@@ -0,0 +1,45 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: "b45fa18946ecc2d9b4009952c636ba7e2ffbb787"
channel: "stable"
project_type: app
# Tracks metadata for the flutter migrate command
migration:
platforms:
- platform: root
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: android
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: ios
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: linux
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: macos
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: web
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
- platform: windows
create_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
base_revision: b45fa18946ecc2d9b4009952c636ba7e2ffbb787
# User provided section
# List of Local paths (relative to this file) that should be
# ignored by the migrate tool.
#
# Files that are not part of the templates will be ignored by default.
unmanaged_files:
- 'lib/main.dart'
- 'ios/Runner.xcodeproj/project.pbxproj'

View File

@@ -0,0 +1,16 @@
# client_app_mvp
A new Flutter project.
## Getting Started
This project is a starting point for a Flutter application.
A few resources to get you started if this is your first Flutter project:
- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook)
For help getting started with Flutter development, view the
[online documentation](https://docs.flutter.dev/), which offers tutorials,
samples, guidance on mobile development, and a full API reference.

View File

@@ -0,0 +1,28 @@
# This file configures the analyzer, which statically analyzes Dart code to
# check for errors, warnings, and lints.
#
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
# invoked from the command line by running `flutter analyze`.
# The following line activates a set of recommended lints for Flutter apps,
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`
# included above or to enable additional rules. A list of all available lints
# and their documentation is published at https://dart.dev/lints.
#
# Instead of disabling a lint rule for the entire project in the
# section below, it can also be suppressed for a single line of code
# or a specific dart file by using the `// ignore: name_of_lint` and
# `// ignore_for_file: name_of_lint` syntax on the line or in the file
# producing the lint.
rules:
# avoid_print: false # Uncomment to disable the `avoid_print` rule
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
# Additional information about this file can be found at
# https://dart.dev/guides/language/analysis-options

View File

@@ -0,0 +1,14 @@
gradle-wrapper.jar
/.gradle
/captures/
/gradlew
/gradlew.bat
/local.properties
GeneratedPluginRegistrant.java
.cxx/
# Remember to never publicly share your keystore.
# See https://flutter.dev/to/reference-keystore
key.properties
**/*.keystore
**/*.jks

View File

@@ -0,0 +1,45 @@
plugins {
id("com.android.application")
id("kotlin-android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
id("com.google.gms.google-services")
}
android {
namespace = "com.example.client_app_mvp"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_17.toString()
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.example.client_app_mvp"
// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
buildTypes {
release {
// TODO: Add your own signing config for the release build.
// Signing with the debug keys for now, so `flutter run --release` works.
signingConfig = signingConfigs.getByName("debug")
}
}
}
flutter {
source = "../.."
}

View File

@@ -0,0 +1,68 @@
{
"project_info": {
"project_number": "717206318340",
"project_id": "krow-apps",
"storage_bucket": "krow-apps.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:717206318340:android:b0bff06f9967d8678af451",
"android_client_info": {
"package_name": "com.example.client_app_mvp"
}
},
"oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:717206318340:android:d3eac8c3774905e08af451",
"android_client_info": {
"package_name": "com.example.staff_app_mvp"
}
},
"oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCXKJ5yME2a4FlrAzZA5LzSt97JwEwn9qE"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "717206318340-9c24vluvsda8gh0pt8gk9sd7vj2nptn2.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -0,0 +1,47 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="Krow Client App MVP"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
</application>
<!-- Required to query activities that can process text, see:
https://developer.android.com/training/package-visibility and
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
</queries>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -0,0 +1,5 @@
package com.example.client_app_mvp
import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity()

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="?android:colorBackground" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Modify this file to customize your launch splash screen -->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@android:color/white" />
<!-- You can insert your own image assets here -->
<!-- <item>
<bitmap
android:gravity="center"
android:src="@mipmap/launch_image" />
</item> -->
</layer-list>

Binary file not shown.

After

Width:  |  Height:  |  Size: 544 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is on -->
<style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Black.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Theme applied to the Android Window while the process is starting when the OS's Dark Mode setting is off -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<!-- Show a splash screen on the activity. Automatically removed when
the Flutter engine draws its first frame -->
<item name="android:windowBackground">@drawable/launch_background</item>
</style>
<!-- Theme applied to the Android Window as soon as the process has started.
This theme determines the color of the Android Window while your
Flutter UI initializes, as well as behind your Flutter UI while its
running.
This Theme is only used starting with V2 of Flutter's Android embedding. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
</style>
</resources>

View File

@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The INTERNET permission is required for development. Specifically,
the Flutter tool needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@@ -0,0 +1,24 @@
allprojects {
repositories {
google()
mavenCentral()
}
}
val newBuildDir: Directory =
rootProject.layout.buildDirectory
.dir("../../build")
.get()
rootProject.layout.buildDirectory.value(newBuildDir)
subprojects {
val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name)
project.layout.buildDirectory.value(newSubprojectBuildDir)
}
subprojects {
project.evaluationDependsOn(":app")
}
tasks.register<Delete>("clean") {
delete(rootProject.layout.buildDirectory)
}

View File

@@ -0,0 +1,2 @@
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
android.useAndroidX=true

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip

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