Initial commit: Grounded Flutter frontend
A to-do app that doesn't believe you — an enforcement layer rather than a
neutral ledger.
Architecture ported from Autoreceptives/Frontend/Receptive: stacked MVVM with
the mandatory 4-file screen pattern, one ParentViewModel owning the loading /
network / error overlays and the handleError decision tree, one AppDataManager
gateway, dio comms carrying the three identity headers, secure storage with
random-suffixed keys, and a single-chokepoint Navigator. Package root and Dart
package name are both Grounded; org is nya.
The enforcement engine, one unit per formula in utils/:
- DebtEngine w(class) x severity(d) x decay(t), sublinear severity so old
misses cannot swamp the score; abandonment 2x with 30-day
decay immunity; late complete retains 30%
- StandingEngine Good -> Warned -> Grounded -> Lockdown, derived not set;
Grounded replaces home with the overdue queue
- CapacityEngine blocks over-scheduling against p50 of historically completed
minutes, with a learned per-category estimation multiplier
- IntegrityEngine session integrity, weekly volume, plyometric contact ceiling
and enforced recovery gaps
- ExcuseAnalyser on-device excuse clustering plus the confrontation copy
- GuardrailEngine distress detection and rationed amnesty
- ToneEngine all enforcement copy, so the tone cap lives in one place
CommitmentEvent is append-only and is the source of truth rather than the
status field, which is what makes honest history and excuse analysis possible.
Goals contain commitments via parentId, and a task can be run from a
full-screen runner that derives elapsed time from wall-clock so screen-off
cannot lose time. Backgrounding pauses the clock and is counted. The runner is
mirrored into an ongoing notification, with alarm-class full-screen intents
reserved for non-negotiables.
Design language, fonts, icon and native splash are in place; Mason bricks are
retargeted to this project and verified end-to-end.
flutter analyze lib/ reports no errors.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mfu2gQLSFN21YRBcU2NrTt
10
frontend/.env.example
Normal file
@@ -0,0 +1,10 @@
|
||||
# Copy to `.env` before running. The real file is gitignored.
|
||||
#
|
||||
# GROUNDED_LOCAL_PATH is the host only — CommsDirections appends the service
|
||||
# port and context path (Prospect 40003, Training 40004, Discipline 40005).
|
||||
|
||||
GROUNDED_LOCAL_PATH="http://192.168.0.100"
|
||||
|
||||
GROUNDED_PRODUCTION_PATH="https://app.grounded.com"
|
||||
|
||||
LOCALISED_APP_VERSION="1.0.0"
|
||||
45
frontend/.gitignore
vendored
Normal 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
|
||||
39
frontend/.metadata
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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: "ee80f08bbf97172ec030b8751ceab557177a34a6"
|
||||
channel: "stable"
|
||||
|
||||
project_type: app
|
||||
|
||||
# Tracks metadata for the flutter migrate command
|
||||
migration:
|
||||
platforms:
|
||||
- platform: root
|
||||
create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
- platform: android
|
||||
create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
- platform: ios
|
||||
create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
- platform: web
|
||||
create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
- platform: windows
|
||||
create_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
base_revision: ee80f08bbf97172ec030b8751ceab557177a34a6
|
||||
|
||||
# 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'
|
||||
179
frontend/CLAUDE.md
Normal file
@@ -0,0 +1,179 @@
|
||||
# Grounded — Flutter Frontend
|
||||
|
||||
*A to-do app that doesn't believe you.*
|
||||
|
||||
Architecture ported from `Documents/Autoreceptives/Frontend/Receptive`. Same
|
||||
structure, conventions and infrastructure; the business logic is the debt and
|
||||
enforcement engine.
|
||||
|
||||
---
|
||||
|
||||
## 1. Stack
|
||||
|
||||
Flutter (Dart `^3.6.2`), **stacked** MVVM, **dio**, **flutter_secure_storage**,
|
||||
**flutter_dotenv**, **fl_chart**, **flutter_local_notifications**.
|
||||
Package name and `lib/` root are both `Grounded`, so imports read
|
||||
`package:Grounded/Grounded/...`. Org is `nya` (`nya.grounded`).
|
||||
|
||||
Codegen is via **Mason** — screens, endpoints and storage fields are generated,
|
||||
never hand-scaffolded.
|
||||
|
||||
---
|
||||
|
||||
## 2. Layout (`lib/Grounded/`)
|
||||
|
||||
```
|
||||
about/external/data/ responses & domain models (+ pages/ for pagination)
|
||||
about/external/initial/ request bodies
|
||||
about/internal/application/ enums and app-internal models
|
||||
about/internal/file/ FileStorage
|
||||
comms/ CommsDirections · ConnectComms · Comms
|
||||
informatics/ DataManager · AppDataManager
|
||||
memory/ ConnectInternalMemory · InternalMemory
|
||||
configs/ Navigator · Env · NotificationServiceConfig
|
||||
designs/ Component · Shell · Responsive · buttons/ input/ text/
|
||||
see/<feature>/ screens, 4 files each
|
||||
utils/ Colors · CommonUtils · engines · validators
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. The 4-file screen pattern (mandatory)
|
||||
|
||||
| File | Role |
|
||||
|---|---|
|
||||
| `Foo.dart` | `StatefulWidget` shell — creates `FooState` only. |
|
||||
| `FooState.dart` | All UI + local state; implements `ConnectFoo`. |
|
||||
| `ViewFoo.dart` | `extends ParentViewModel` — business logic, calls `DataManager`, pushes results back through `ConnectFoo`. |
|
||||
| `ConnectFoo.dart` | Abstract callbacks so the ViewModel never touches widgets. |
|
||||
|
||||
`ViewModelBuilder<ViewFoo>.reactive` wires them. `onViewModelReady` assigns
|
||||
`_model` and calls one named `_initiate()`. **No logic in `builder:` before the
|
||||
`return`.**
|
||||
|
||||
Generate with: `mason make mvvc_template --project Grounded --screen Foo`
|
||||
|
||||
---
|
||||
|
||||
## 4. ParentViewModel
|
||||
|
||||
Constructs the single `AppDataManager` and owns everything cross-cutting:
|
||||
`showLoading` / `closeLoading`, `hasNetwork(retry)`, `showError`,
|
||||
`showApplicationNotification`, and `handleError` — whose decision tree routes
|
||||
`401 → sessionExpired()` and error code `5000.901 → updateMe()`.
|
||||
|
||||
Guard every network call:
|
||||
|
||||
```dart
|
||||
void loadThing(ThingRequest request) async {
|
||||
if (!await hasNetwork(() => loadThing(request))) return;
|
||||
showLoading('Loading…');
|
||||
try {
|
||||
final response = await getDataManager().getThing(request);
|
||||
closeLoading();
|
||||
connection.onThingLoaded(Thing.fromJson(response.data));
|
||||
} catch (e) {
|
||||
handleError(e, () => loadThing(request), () => dismissError(), 'Retry');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Domain — the enforcement engine
|
||||
|
||||
Three primitives: **Commitment** (what you said you'd do), **Debt** (weighted,
|
||||
decaying score), **Standing** (`Good → Warned → Grounded → Lockdown`).
|
||||
|
||||
**Goals** contain commitments via `Commitment.parentId` — "Workout" holds
|
||||
"Monday shoulders". Goals never carry debt; the tasks inside them do.
|
||||
|
||||
Engines in `utils/`, each mapping 1:1 to the spec's formulas:
|
||||
|
||||
| Engine | Owns |
|
||||
|---|---|
|
||||
| `DebtEngine` | `w(class) × severity(d) × decay(t)`; abandonment 2×, no decay 30d; late complete retains 30% |
|
||||
| `StandingEngine` | tier derivation; what each tier permits |
|
||||
| `CapacityEngine` | blocks over-scheduling against p50 of historical completed minutes × 0.85 |
|
||||
| `IntegrityEngine` | session integrity, weekly volume, plyo contact ceiling, recovery gate |
|
||||
| `ExcuseAnalyser` | on-device excuse clustering + the confrontation copy |
|
||||
| `GuardrailEngine` | distress detection, amnesty tokens |
|
||||
| `ToneEngine` | **all** enforcement copy — the one place the tone cap is enforced |
|
||||
|
||||
Thresholds live in `Thresholds.dart`. Never inline a limit.
|
||||
|
||||
`CommitmentEvent` is append-only and is the source of truth — **not** the
|
||||
status field. That's what makes honest history and excuse analysis possible.
|
||||
|
||||
---
|
||||
|
||||
## 6. Design language
|
||||
|
||||
See `design.md`. In short: black chrome → white sheet with a 28 radius →
|
||||
oversized **Light** display title → tiny grey all-caps labels above values.
|
||||
|
||||
- Every screen is built from `Sheet` (`designs/Shell.dart`).
|
||||
- Display titles are `TextType.Light`. Bold is for labels and metrics only.
|
||||
- Never raw `Text`/`TextStyle` — use `text()` from `designs/text/Text.dart`.
|
||||
- Never inline hex — use `utils/Colors.dart`.
|
||||
- Standing owns a colour used consistently everywhere (chrome, chip, meter).
|
||||
- One primary button per screen; everything else outlined or text.
|
||||
|
||||
Font: **General Sans** (Fontshare, FFL — see `fonts/LICENSE-GeneralSans.txt`),
|
||||
wrapped as `TextType.{Bold,Medium,Regular,Light}`.
|
||||
|
||||
---
|
||||
|
||||
## 7. Live task runner
|
||||
|
||||
`see/live/` is the full-screen runner: a task being run takes over the screen.
|
||||
Elapsed time is derived from **wall-clock**, not counted by the ticker, so a
|
||||
screen-off period cannot lose time. Backgrounding pauses the clock and
|
||||
increments `backgroundedCount` — that's what makes Timer proof mean anything.
|
||||
|
||||
`LocalNotificationEngine` mirrors it into an ongoing notification and fires
|
||||
alarm-class **full-screen intents** for non-negotiables. Android manifest
|
||||
carries `USE_FULL_SCREEN_INTENT`, `SCHEDULE_EXACT_ALARM`, and the activity is
|
||||
`showWhenLocked` + `turnScreenOn`.
|
||||
|
||||
---
|
||||
|
||||
## 8. Hard conventions
|
||||
|
||||
1. Named event handlers only — `onPressed: _onSave`, never `() => _save()`.
|
||||
2. `selectField` loads on tap; never pre-load picker options.
|
||||
3. List parsing via `utils/ObjectConvertors.dart` — never inline `.map(...fromJson)`.
|
||||
4. Pagination: `HistoryRequest { PageAndSort }`; responses are `*Page`; `last == true` stops loading.
|
||||
5. Reload-on-return: child `Navigator.pop(context, true)`, parent refreshes on the result.
|
||||
6. New endpoint → `mason make api_endpoint` (injects into all four HTTP files).
|
||||
7. New secure field → `mason make internal_memory`.
|
||||
8. One class per file, named after the class.
|
||||
|
||||
---
|
||||
|
||||
## 9. Environment
|
||||
|
||||
`.env` is a bundled asset, loaded in `main()` before `runApp`:
|
||||
|
||||
```
|
||||
GROUNDED_PRODUCTION_PATH · GROUNDED_LOCAL_PATH · LOCALISED_APP_VERSION
|
||||
```
|
||||
|
||||
`isProd` in `CommsDirections.dart` flips local↔production. Requests carry the
|
||||
three identity headers: `what`, `whom`, `version`.
|
||||
|
||||
---
|
||||
|
||||
## 10. Commands
|
||||
|
||||
```bash
|
||||
flutter pub get
|
||||
flutter analyze lib/ # bricks/ are excluded — templates aren't valid Dart
|
||||
flutter run
|
||||
|
||||
mason get
|
||||
mason make mvvc_template --project Grounded --screen MyScreen
|
||||
|
||||
dart run flutter_launcher_icons
|
||||
dart run flutter_native_splash:create
|
||||
```
|
||||
17
frontend/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# grounded
|
||||
|
||||
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:
|
||||
|
||||
- [Learn Flutter](https://docs.flutter.dev/get-started/learn-flutter)
|
||||
- [Write your first Flutter app](https://docs.flutter.dev/get-started/codelab)
|
||||
- [Flutter learning resources](https://docs.flutter.dev/reference/learning-resources)
|
||||
|
||||
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.
|
||||
24
frontend/analysis_options.yaml
Normal file
@@ -0,0 +1,24 @@
|
||||
include: package:flutter_lints/flutter.yaml
|
||||
|
||||
analyzer:
|
||||
exclude:
|
||||
# Mason templates are not valid Dart until they are rendered.
|
||||
- bricks/**
|
||||
- build/**
|
||||
|
||||
errors:
|
||||
# The project deliberately uses PascalCase file names and a PascalCase
|
||||
# package root, matching the house architecture. These are conventions,
|
||||
# not defects.
|
||||
file_names: ignore
|
||||
camel_case_types: ignore
|
||||
constant_identifier_names: ignore
|
||||
non_constant_identifier_names: ignore
|
||||
library_prefixes: ignore
|
||||
|
||||
linter:
|
||||
rules:
|
||||
use_super_parameters: false
|
||||
prefer_const_constructors: false
|
||||
prefer_const_literals_to_create_immutables: false
|
||||
library_private_types_in_public_api: false
|
||||
14
frontend/android/.gitignore
vendored
Normal 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
|
||||
45
frontend/android/app/build.gradle.kts
Normal file
@@ -0,0 +1,45 @@
|
||||
plugins {
|
||||
id("com.android.application")
|
||||
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
|
||||
id("dev.flutter.flutter-gradle-plugin")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "nya.grounded"
|
||||
compileSdk = flutter.compileSdkVersion
|
||||
ndkVersion = flutter.ndkVersion
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility = JavaVersion.VERSION_17
|
||||
targetCompatibility = JavaVersion.VERSION_17
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
||||
applicationId = "nya.grounded"
|
||||
// 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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlin {
|
||||
compilerOptions {
|
||||
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
|
||||
}
|
||||
}
|
||||
|
||||
flutter {
|
||||
source = "../.."
|
||||
}
|
||||
7
frontend/android/app/src/debug/AndroidManifest.xml
Normal 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>
|
||||
69
frontend/android/app/src/main/AndroidManifest.xml
Normal file
@@ -0,0 +1,69 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||
|
||||
<!-- The ongoing "task in progress" notification and its live timer. -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
|
||||
<!-- Non-negotiables surface over the lock screen rather than as a banner
|
||||
that can be swiped past. -->
|
||||
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"/>
|
||||
|
||||
<!-- A due window has to close on time, not whenever the OS gets round to
|
||||
it, so the reminders are scheduled as exact alarms. -->
|
||||
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/>
|
||||
<uses-permission android:name="android.permission.USE_EXACT_ALARM"/>
|
||||
|
||||
<!-- Reminders survive a reboot. -->
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
<application
|
||||
android:label="Grounded"
|
||||
android:name="${applicationName}"
|
||||
android:icon="@mipmap/ic_launcher">
|
||||
<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"
|
||||
android:showWhenLocked="true"
|
||||
android:turnScreenOn="true">
|
||||
<!-- 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>
|
||||
</manifest>
|
||||
@@ -0,0 +1,5 @@
|
||||
package nya.grounded
|
||||
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
|
||||
class MainActivity : FlutterActivity()
|
||||
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
BIN
frontend/android/app/src/main/res/drawable-hdpi/splash.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
BIN
frontend/android/app/src/main/res/drawable-mdpi/splash.png
Normal file
|
After Width: | Height: | Size: 7.3 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 30 KiB |
BIN
frontend/android/app/src/main/res/drawable-v21/background.png
Normal file
|
After Width: | Height: | Size: 69 B |
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
BIN
frontend/android/app/src/main/res/drawable-xhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 22 KiB |
|
After Width: | Height: | Size: 7.6 KiB |
BIN
frontend/android/app/src/main/res/drawable-xxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 11 KiB |
BIN
frontend/android/app/src/main/res/drawable-xxxhdpi/splash.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
frontend/android/app/src/main/res/drawable/background.png
Normal file
|
After Width: | Height: | Size: 69 B |
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item>
|
||||
<bitmap android:gravity="fill" android:src="@drawable/background"/>
|
||||
</item>
|
||||
<item>
|
||||
<bitmap android:gravity="center" android:src="@drawable/splash"/>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground>
|
||||
<inset
|
||||
android:drawable="@drawable/ic_launcher_foreground"
|
||||
android:inset="16%" />
|
||||
</foreground>
|
||||
</adaptive-icon>
|
||||
BIN
frontend/android/app/src/main/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
frontend/android/app/src/main/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
frontend/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
frontend/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
frontend/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
@@ -0,0 +1,22 @@
|
||||
<?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">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowSplashScreenBackground">#141414</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">#141414</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>
|
||||
22
frontend/android/app/src/main/res/values-night/styles.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</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>
|
||||
22
frontend/android/app/src/main/res/values-v31/styles.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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">
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
|
||||
<item name="android:windowSplashScreenBackground">#141414</item>
|
||||
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
|
||||
<item name="android:windowSplashScreenIconBackgroundColor">#141414</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>
|
||||
4
frontend/android/app/src/main/res/values/colors.xml
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="ic_launcher_background">#141414</color>
|
||||
</resources>
|
||||
22
frontend/android/app/src/main/res/values/styles.xml
Normal file
@@ -0,0 +1,22 @@
|
||||
<?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>
|
||||
<item name="android:forceDarkAllowed">false</item>
|
||||
<item name="android:windowFullscreen">false</item>
|
||||
<item name="android:windowDrawsSystemBarBackgrounds">false</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</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>
|
||||
7
frontend/android/app/src/profile/AndroidManifest.xml
Normal 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>
|
||||
24
frontend/android/build.gradle.kts
Normal 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)
|
||||
}
|
||||
6
frontend/android/gradle.properties
Normal file
@@ -0,0 +1,6 @@
|
||||
org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError
|
||||
android.useAndroidX=true
|
||||
# This newDsl flag was added by the Flutter template
|
||||
android.newDsl=false
|
||||
# This builtInKotlin flag was added by the Flutter template
|
||||
android.builtInKotlin=false
|
||||
5
frontend/android/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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-9.1.0-all.zip
|
||||
26
frontend/android/settings.gradle.kts
Normal file
@@ -0,0 +1,26 @@
|
||||
pluginManagement {
|
||||
val flutterSdkPath =
|
||||
run {
|
||||
val properties = java.util.Properties()
|
||||
file("local.properties").inputStream().use { properties.load(it) }
|
||||
val flutterSdkPath = properties.getProperty("flutter.sdk")
|
||||
require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" }
|
||||
flutterSdkPath
|
||||
}
|
||||
|
||||
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
gradlePluginPortal()
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
|
||||
id("com.android.application") version "9.0.1" apply false
|
||||
id("org.jetbrains.kotlin.android") version "2.3.20" apply false
|
||||
}
|
||||
|
||||
include(":app")
|
||||
BIN
frontend/assets/icons/icon.png
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
frontend/assets/icons/icon_foreground.png
Normal file
|
After Width: | Height: | Size: 27 KiB |
17
frontend/assets/icons/logo.svg
Normal file
@@ -0,0 +1,17 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
|
||||
<!-- Grounded mark: a horizon line with a weight resting on it. The bar is
|
||||
the ground; the block is what you are carrying. -->
|
||||
<rect width="512" height="512" fill="#141414"/>
|
||||
|
||||
<!-- The block -->
|
||||
<rect x="176" y="146" width="160" height="160" rx="34" fill="#EDEEEA"/>
|
||||
|
||||
<!-- The notch — a debt taken out of the block -->
|
||||
<rect x="236" y="146" width="40" height="86" rx="20" fill="#141414"/>
|
||||
|
||||
<!-- The ground line -->
|
||||
<rect x="120" y="348" width="272" height="26" rx="13" fill="#2F6F4E"/>
|
||||
|
||||
<!-- Shadow beneath, shortened: the weight sits on the line -->
|
||||
<rect x="168" y="396" width="176" height="14" rx="7" fill="#EDEEEA" opacity="0.22"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 760 B |
BIN
frontend/assets/icons/splash.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
3
frontend/bricks/api_endpoint/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 0.1.0+1
|
||||
|
||||
- TODO: Describe initial release.
|
||||
1
frontend/bricks/api_endpoint/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
83
frontend/bricks/api_endpoint/README.md
Normal file
@@ -0,0 +1,83 @@
|
||||
## 📄 README.md
|
||||
|
||||
### 🚀 API Endpoint Mason Brick
|
||||
A smart, synchronized generator that appends API logic across `Comms`, `ConnectComms`, and `AppDataManager` while handling auto-imports and optional formatting.
|
||||
|
||||
### 🛠 1. First-Time Setup
|
||||
Run these commands to ensure Mason and the Dart hooks are ready to go:
|
||||
|
||||
```bash
|
||||
# 1. Install Mason CLI (if you haven't)
|
||||
dart pub global activate mason_cli
|
||||
|
||||
# 2. Initialize Mason in project root
|
||||
mason init
|
||||
|
||||
# 3. Install Hook dependencies
|
||||
cd bricks/api_endpoint/hooks
|
||||
dart pub get
|
||||
cd ../../../
|
||||
|
||||
# 4. Register the brick
|
||||
mason get
|
||||
```
|
||||
|
||||
### 🔃 2. How to Refresh (When logic or prompts change)
|
||||
If you update the `brick.yaml` or the `post_gen.dart` hook, Mason might use a cached version. Use this "Hard Refresh" command:
|
||||
|
||||
```bash
|
||||
rm -rf .mason && mason get
|
||||
```
|
||||
|
||||
### 🏃 3. Running the Generator
|
||||
To add a new endpoint, simply run:
|
||||
```bash
|
||||
mason make api_endpoint
|
||||
```
|
||||
|
||||
**Interaction Flow:**
|
||||
1. **Endpoint Path:** e.g., `orders/confirm`
|
||||
2. **Function Name:** e.g., `confirmOrder`
|
||||
3. **Method:** Choose `get` or `post`.
|
||||
4. **Request Body:** * **Mandatory for POST**: e.g., `OrderDetails`.
|
||||
* **Optional for GET**: Leave empty or provide a type like `String`.
|
||||
5. **Auto-Import**: The brick scans `lib/` for your Body type and adds the `import` statement automatically.
|
||||
6. **Format**: Choose `y` to run `dart format` on all 4 modified files.
|
||||
|
||||
---
|
||||
|
||||
## 🐚 setup_brick.sh
|
||||
Create this file in your project root to allow one-click setup or refreshing for your team.
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
# setup_brick.sh
|
||||
echo "🧹 Cleaning old Mason cache..."
|
||||
rm -rf .mason
|
||||
|
||||
echo "📦 Fetching Hook dependencies..."
|
||||
if [ -d "bricks/api_endpoint/hooks" ]; then
|
||||
cd bricks/api_endpoint/hooks
|
||||
dart pub get
|
||||
cd ../../../
|
||||
else
|
||||
echo "❌ Error: bricks/api_endpoint/hooks directory not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🧱 Registering Mason Brick..."
|
||||
mason get
|
||||
|
||||
echo "✅ Setup Complete! Run 'mason make api_endpoint' to start."
|
||||
```
|
||||
|
||||
### To use the script:
|
||||
1. Create the file: `touch setup_brick.sh`
|
||||
2. Give it permission: `chmod +x setup_brick.sh`
|
||||
3. Run it: `./setup_brick.sh`
|
||||
|
||||
---
|
||||
|
||||
### 💡 Pro-Tip: Project Name Detection
|
||||
In your `post_gen.dart` hook, ensure you have updated the `package:your_project_name` string to match your real project name from `pubspec.yaml`, otherwise the auto-imports will show a red error in VS Code.
|
||||
25
frontend/bricks/api_endpoint/brick.yaml
Normal file
@@ -0,0 +1,25 @@
|
||||
name: api_endpoint
|
||||
description: Generates Comms and AppDataManager logic for a new endpoint.
|
||||
|
||||
version: 0.1.0+1
|
||||
|
||||
environment:
|
||||
mason: ^0.1.1
|
||||
|
||||
|
||||
vars:
|
||||
path_url:
|
||||
type: string
|
||||
prompt: "🌐 What is the API path? (e.g., auth/login)"
|
||||
function_name:
|
||||
type: string
|
||||
prompt: "🖋️ What is the function name? (e.g., signIn)"
|
||||
request_type:
|
||||
type: string
|
||||
default: get
|
||||
prompt: "🔃 Is this a 'get' or a 'post'?"
|
||||
request_body:
|
||||
type: string
|
||||
default: ""
|
||||
prompt: "📦 Request Body type? (Mandatory for POST, Optional for GET)"
|
||||
|
||||
146
frontend/bricks/api_endpoint/hooks/post_gen.dart
Normal file
@@ -0,0 +1,146 @@
|
||||
import 'dart:io';
|
||||
import 'package:mason/mason.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
void run(HookContext context) async {
|
||||
final logger = context.logger;
|
||||
|
||||
final String pathUrl = context.vars['path_url'] ?? '';
|
||||
final String functionName = context.vars['function_name'] ?? '';
|
||||
final String requestType = (context.vars['request_type'] as String).toLowerCase();
|
||||
final String requestBody = context.vars['request_body'] as String;
|
||||
|
||||
if (requestType == 'post' && requestBody.isEmpty) {
|
||||
logger.err('❌ Error: POST requests require a Request Body type.');
|
||||
return;
|
||||
}
|
||||
|
||||
final cName = functionName.camelCase;
|
||||
final bool hasData = requestBody.isNotEmpty;
|
||||
final String paramType = hasData ? requestBody : 'dynamic';
|
||||
|
||||
// Auto-Detect Project Name
|
||||
String projectName = 'your_project';
|
||||
final pubspecFile = File('pubspec.yaml');
|
||||
if (pubspecFile.existsSync()) {
|
||||
final doc = loadYaml(pubspecFile.readAsStringSync());
|
||||
projectName = doc['name'] ?? projectName;
|
||||
}
|
||||
|
||||
final progress = logger.progress('🚀 Injecting logic...');
|
||||
|
||||
final filesToUpdate = [
|
||||
'lib/Grounded/comms/CommsDirections.dart',
|
||||
'lib/Grounded/comms/Comms.dart',
|
||||
'lib/Grounded/comms/ConnectComms.dart',
|
||||
'lib/Grounded/informatics/AppDataManager.dart'
|
||||
];
|
||||
|
||||
// Find Import Path and Filename
|
||||
String? importLine;
|
||||
String? importFileName;
|
||||
if (hasData && !['String','int','double','bool'].contains(requestBody)) {
|
||||
final result = await _findClassData(requestBody, projectName);
|
||||
importLine = result?['line'];
|
||||
importFileName = result?['fileName'];
|
||||
}
|
||||
|
||||
final String sharedParams = hasData ? '$paramType request' : '';
|
||||
final String callParams = hasData ? 'request' : '';
|
||||
|
||||
// 1. CommsDirections
|
||||
await _inject(filesToUpdate[0], "String ${cName}Path = '$pathUrl';", logger,
|
||||
isClass: false, duplicateCheck: "${cName}Path");
|
||||
|
||||
// 2. comms.dart
|
||||
final String dioData = requestType == 'post' ? 'data: request' : 'options: Options(headers: dio.options.headers)';
|
||||
final String commsMethod = '''
|
||||
@override
|
||||
Future<Response> $cName($sharedParams) async {
|
||||
Pair navigation = await getRequestHeaders(${cName}Path, "");
|
||||
dio.options.headers = navigation.value;
|
||||
return await dio.$requestType(
|
||||
navigation.key,
|
||||
$dioData
|
||||
);
|
||||
}''';
|
||||
await _inject(filesToUpdate[1], commsMethod, logger,
|
||||
importLine: importLine, importFileName: importFileName, duplicateCheck: "Future<Response> $cName");
|
||||
|
||||
// 3. ConnectComms.dart
|
||||
await _inject(filesToUpdate[2], " Future<Response> $cName($sharedParams);", logger,
|
||||
importLine: importLine, importFileName: importFileName, duplicateCheck: "Future<Response> $cName");
|
||||
|
||||
// 4. AppDataManager.dart
|
||||
final String dataManagerMethod = '''
|
||||
@override
|
||||
Future<Response> $cName($sharedParams) async {
|
||||
return await connectComms.$cName($callParams);
|
||||
}''';
|
||||
await _inject(filesToUpdate[3], dataManagerMethod, logger,
|
||||
importLine: importLine, importFileName: importFileName, duplicateCheck: "Future<Response> $cName");
|
||||
|
||||
progress.complete('✨ Injection & Deduplication complete.');
|
||||
|
||||
final shouldFormat = logger.confirm('🎨 Run "dart format" on updated files?', defaultValue: false);
|
||||
if (shouldFormat) {
|
||||
for (final path in filesToUpdate) {
|
||||
await Process.run('dart', ['format', path]);
|
||||
}
|
||||
logger.success('✅ Files formatted.');
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns both the full import line and just the filename (e.g. user_request.dart)
|
||||
Future<Map<String, String>?> _findClassData(String className, String projectName) async {
|
||||
final directory = Directory('lib');
|
||||
if (!directory.existsSync()) return null;
|
||||
final List<FileSystemEntity> files = directory.listSync(recursive: true);
|
||||
for (var file in files) {
|
||||
if (file is File && file.path.endsWith('.dart')) {
|
||||
final content = await file.readAsString();
|
||||
if (content.contains('class $className') || content.contains('enum $className')) {
|
||||
final fileName = file.path.split('/').last;
|
||||
final packagePath = file.path.replaceFirst('lib/Grounded/', '');
|
||||
return {
|
||||
'line': "import 'package:$projectName/$packagePath';",
|
||||
'fileName': fileName,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> _inject(String path, String content, Logger logger,
|
||||
{bool isClass = true, String? importLine, String? importFileName, String? duplicateCheck}) async {
|
||||
final file = File(path);
|
||||
if (!await file.exists()) return;
|
||||
String fileContent = await file.readAsString();
|
||||
|
||||
// 1. Prevent Duplicate Method/Variable
|
||||
if (duplicateCheck != null && fileContent.contains(duplicateCheck)) {
|
||||
return; // Silently skip methods that exist
|
||||
}
|
||||
|
||||
// 2. Smart Import Check: Look for the filename inside any import statement
|
||||
if (importLine != null && importFileName != null) {
|
||||
// Regex matches: import 'any/path/filename.dart'; or "any/path/filename.dart";
|
||||
final importRegex = RegExp("import ['\"].*?$importFileName['\"];");
|
||||
if (!importRegex.hasMatch(fileContent)) {
|
||||
fileContent = "$importLine\n$fileContent";
|
||||
}
|
||||
}
|
||||
|
||||
if (isClass) {
|
||||
final lastBrace = fileContent.lastIndexOf('}');
|
||||
if (lastBrace != -1) {
|
||||
fileContent = fileContent.substring(0, lastBrace).trimRight() + '\n\n$content\n' + fileContent.substring(lastBrace);
|
||||
} else {
|
||||
fileContent += '\n\n$content';
|
||||
}
|
||||
} else {
|
||||
fileContent = fileContent.trimRight() + '\n\n$content\n';
|
||||
}
|
||||
await file.writeAsString(fileContent);
|
||||
}
|
||||
10
frontend/bricks/api_endpoint/hooks/pubspec.yaml
Normal file
@@ -0,0 +1,10 @@
|
||||
name: api_endpoint_hooks
|
||||
description: Hooks for the api_endpoint brick.
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
sdk: ">=2.12.0 <4.0.0"
|
||||
|
||||
dependencies:
|
||||
mason: ^0.1.0-dev.51 # Or the latest version
|
||||
yaml: ^3.1.2
|
||||
20
frontend/bricks/api_endpoint/setup_brick.sh
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/bin/bash
|
||||
|
||||
# setup_brick.sh
|
||||
echo "🧹 Cleaning old Mason cache (Hard Refresh)..."
|
||||
rm -rf .mason
|
||||
|
||||
echo "📦 Fetching Hook dependencies (Yaml/Mason)..."
|
||||
if [ -d "bricks/api_endpoint/hooks" ]; then
|
||||
cd bricks/api_endpoint/hooks
|
||||
dart pub get
|
||||
cd ../../../
|
||||
else
|
||||
echo "❌ Error: Hooks directory not found!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "🧱 Getting latest Brick definition..."
|
||||
mason get
|
||||
|
||||
echo "✅ Ready! Run 'mason make api_endpoint'"
|
||||
3
frontend/bricks/internal_memory/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 0.1.0+1
|
||||
|
||||
- TODO: Describe initial release.
|
||||
1
frontend/bricks/internal_memory/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
92
frontend/bricks/internal_memory/README.md
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
|
||||
# 🔐 Internal Memory Brick
|
||||
|
||||
An advanced **Mason** brick designed for the **Autoreceptive** architecture. It automates the boilerplate for persistent local storage using `flutter_secure_storage` (via `autoreceptiveStorage`), handling JSON serialization for Objects and Lists, and raw storage for Strings.
|
||||
|
||||
## 🚀 Purpose
|
||||
This brick eliminates the manual task of:
|
||||
1. Generating high-entropy, randomized secure keys.
|
||||
2. Writing `get` and `set` interfaces in `ConnectInternalMemory`.
|
||||
3. Implementing JSON encoding/decoding logic in `InternalMemory`.
|
||||
4. Wrapping calls in `AppDataManager` to maintain the **Repository Pattern**.
|
||||
|
||||
---
|
||||
|
||||
## 📂 Target Architecture
|
||||
The brick targets the following specific paths in your project:
|
||||
* **Interface**: `lib/Autoreceptive/memory/ConnectInternalMemory.dart`
|
||||
* **Implementation**: `lib/Autoreceptive/memory/InternalMemory.dart`
|
||||
* **Global Access**: `lib/Autoreceptive/informatics/AppDataManager.dart`
|
||||
|
||||
---
|
||||
|
||||
## 🛠 Installation
|
||||
|
||||
### 1. Register the Brick
|
||||
From your project root, run:
|
||||
```bash
|
||||
mason add internal_memory --path ./bricks/internal_memory
|
||||
```
|
||||
|
||||
### 2. Setup Hooks
|
||||
The brick uses specialized Dart hooks for smart code injection and auto-formatting.
|
||||
```bash
|
||||
cd bricks/internal_memory/hooks && dart pub get && cd ../../../
|
||||
mason get
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📖 Usage Guide
|
||||
|
||||
Run the following command and follow the interactive prompts:
|
||||
```bash
|
||||
mason make internal_memory
|
||||
```
|
||||
|
||||
### Variable Inputs:
|
||||
| Variable | Description | Example |
|
||||
| :--- | :--- | :--- |
|
||||
| `function_name` | The camelCase name of the feature. | `userProfile` or `orderLocations` |
|
||||
| `request_object` | The Dart type to store. | `MeDescription`, `String`, or `List<Location>` |
|
||||
|
||||
---
|
||||
|
||||
## 📋 Logic Breakdown
|
||||
|
||||
### 1. High-Entropy Keys
|
||||
The brick generates a randomized `static const String` key at the **top** of the `InternalMemory` class to prevent key collisions and reverse-engineering:
|
||||
```dart
|
||||
static const String USER_PROFILE = "USER_PROFILE_x8H2_9kLp_mQz1";
|
||||
```
|
||||
|
||||
### 2. Intelligent Type Handling
|
||||
The hook detects the `request_object` type and adjusts the logic:
|
||||
|
||||
* **Standard Objects**: Uses `Type.fromJson(jsonDecode(s))` and `jsonEncode(data.toJson())`.
|
||||
* **Lists**: Uses `.map((item) => Type.fromJson(item)).toList()` for deep serialization.
|
||||
* **Strings**: Bypasses JSON logic for raw string storage.
|
||||
|
||||
### 3. Smart Injection & Spacing
|
||||
* **Clean Pairs**: In the interface, the getter and setter are injected as a tight block with a double-newline buffer from the previous feature.
|
||||
* **Auto-Imports**: Automatically adds `import 'dart:convert';` and searches the `lib/` folder to find and add the correct model imports for your Objects.
|
||||
* **Formatting**: Automatically triggers `dart format` on the `Autoreceptive` folder after injection.
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Requirements
|
||||
* **`autoreceptiveStorage`**: The `InternalMemory` class must have an instance of your secure storage wrapper named `autoreceptiveStorage`.
|
||||
* **Model Factories**: For Objects and Lists, your models must implement:
|
||||
* `factory Model.fromJson(Map<String, dynamic> json)`
|
||||
* `Map<String, dynamic> toJson()`
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Refreshing Logic
|
||||
If you update the `post_gen.dart` hook code, always run this to ensure Mason uses the latest version:
|
||||
```bash
|
||||
rm -rf .mason && mason get
|
||||
```
|
||||
|
||||
---
|
||||
11
frontend/bricks/internal_memory/brick.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
name: internal_memory
|
||||
description: Generates Secure Storage logic with JSON serialization and AppDataManager sync.
|
||||
version: 0.1.0+1
|
||||
|
||||
vars:
|
||||
function_name:
|
||||
type: string
|
||||
prompt: "🖋️ What is the function name? (e.g., myDescription)"
|
||||
request_object:
|
||||
type: string
|
||||
prompt: "📦 What is the Object type to store? (e.g., MeDescription)"
|
||||
186
frontend/bricks/internal_memory/hooks/post_gen.dart
Normal file
@@ -0,0 +1,186 @@
|
||||
import 'dart:io';
|
||||
import 'dart:convert';
|
||||
import 'dart:math';
|
||||
import 'package:mason/mason.dart';
|
||||
import 'package:yaml/yaml.dart';
|
||||
|
||||
void run(HookContext context) async {
|
||||
final logger = context.logger;
|
||||
final String functionName = context.vars['function_name'] ?? '';
|
||||
final String requestObject = context.vars['request_object'] ?? '';
|
||||
|
||||
final cName = functionName.camelCase;
|
||||
final pName = functionName.pascalCase;
|
||||
final uName = functionName.snakeCase.toUpperCase();
|
||||
|
||||
final secureKeyValue = _generateSecureKey(uName);
|
||||
|
||||
String projectName = 'your_project';
|
||||
final pubspecFile = File('pubspec.yaml');
|
||||
if (pubspecFile.existsSync()) {
|
||||
final doc = loadYaml(pubspecFile.readAsStringSync());
|
||||
projectName = doc['name'] ?? projectName;
|
||||
}
|
||||
|
||||
final bool isList = requestObject.startsWith('List<');
|
||||
final bool isString = requestObject.toLowerCase() == 'string';
|
||||
|
||||
String baseType = requestObject;
|
||||
if (isList) {
|
||||
baseType = requestObject.substring(5, requestObject.length - 1);
|
||||
}
|
||||
|
||||
final files = [
|
||||
'lib/Grounded/memory/ConnectInternalMemory.dart',
|
||||
'lib/Grounded/memory/InternalMemory.dart',
|
||||
'lib/Grounded/informatics/AppDataManager.dart'
|
||||
];
|
||||
|
||||
String? importLine;
|
||||
String? importFileName;
|
||||
if (!isString) {
|
||||
final result = await _findClassData(baseType, projectName);
|
||||
importLine = result?['line'];
|
||||
importFileName = result?['fileName'];
|
||||
}
|
||||
|
||||
// --- Implementation Logic ---
|
||||
String getLogic = "";
|
||||
String setLogic = "";
|
||||
|
||||
if (isString) {
|
||||
getLogic = "return await groundedStorage.read(key: $uName) ?? '';";
|
||||
setLogic = "await groundedStorage.write(key: $uName, value: data);";
|
||||
} else if (isList) {
|
||||
getLogic = '''
|
||||
final dataString = await groundedStorage.read(key: $uName);
|
||||
if (dataString != null && dataString.isNotEmpty) {
|
||||
return (jsonDecode(dataString) as List)
|
||||
.map((item) => $baseType.fromJson(item))
|
||||
.toList();
|
||||
}
|
||||
return [];''';
|
||||
setLogic = '''
|
||||
final jsonString = jsonEncode(data.map((item) => item.toJson()).toList());
|
||||
await groundedStorage.write(key: $uName, value: jsonString);''';
|
||||
} else {
|
||||
getLogic = '''
|
||||
final jsonString = await groundedStorage.read(key: $uName);
|
||||
if (jsonString != null && jsonString.isNotEmpty) {
|
||||
return $baseType.fromJson(jsonDecode(jsonString));
|
||||
}
|
||||
return $baseType();''';
|
||||
setLogic = '''
|
||||
await groundedStorage.write(key: $uName, value: jsonEncode(data.toJson()));''';
|
||||
}
|
||||
|
||||
// --- 1. ConnectInternalMemory (No space between the pair) ---
|
||||
final interfaceCode = " Future<$requestObject> get$pName();\n Future set$pName($requestObject data);";
|
||||
await _inject(files[0], interfaceCode, logger, importLine: importLine, importFileName: importFileName, duplicateCheck: "get$pName()");
|
||||
|
||||
// --- 2. InternalMemory (Key spacing at TOP) ---
|
||||
final String keyLine = '\n\n static const String $uName = "$secureKeyValue";\n';
|
||||
final String methods = '''
|
||||
@override
|
||||
Future<$requestObject> get$pName() async {
|
||||
$getLogic
|
||||
}
|
||||
|
||||
@override
|
||||
Future set$pName($requestObject data) async {
|
||||
$setLogic
|
||||
}''';
|
||||
|
||||
await _injectInternalMemory(files[1], keyLine, methods, logger, importLine: importLine, importFileName: importFileName, duplicateCheck: "get$pName()");
|
||||
|
||||
// --- 3. AppDataManager ---
|
||||
final String wrapper = '''
|
||||
@override
|
||||
Future<$requestObject> get$pName() async {
|
||||
return await connectInternalMemory.get$pName();
|
||||
}
|
||||
|
||||
@override
|
||||
Future set$pName($requestObject data) async {
|
||||
return await connectInternalMemory.set$pName(data);
|
||||
}''';
|
||||
await _inject(files[2], wrapper, logger, importLine: importLine, importFileName: importFileName, duplicateCheck: "get$pName()");
|
||||
|
||||
// --- 4. Format ---
|
||||
try {
|
||||
await Process.run('dart', ['format', 'lib/Grounded/']);
|
||||
} catch (_) {}
|
||||
|
||||
logger.success('✨ Internal Memory synced with corrected spacing.');
|
||||
}
|
||||
|
||||
String _generateSecureKey(String base) {
|
||||
final random = Random.secure();
|
||||
final values = List<int>.generate(12, (i) => random.nextInt(256));
|
||||
return "${base}_${base64Url.encode(values).replaceAll('=', '').substring(0, 16)}";
|
||||
}
|
||||
|
||||
Future<Map<String, String>?> _findClassData(String className, String projectName) async {
|
||||
final dir = Directory('lib');
|
||||
if (!dir.existsSync()) return null;
|
||||
for (var f in dir.listSync(recursive: true)) {
|
||||
if (f is File && f.path.endsWith('.dart')) {
|
||||
final content = await f.readAsString();
|
||||
if (content.contains('class $className')) {
|
||||
return {
|
||||
'line': "import 'package:$projectName/${f.path.replaceFirst('lib/', '')}';",
|
||||
'fileName': f.path.split('/').last,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> _inject(String path, String content, Logger logger, {String? importLine, String? importFileName, String? duplicateCheck}) async {
|
||||
final file = File(path);
|
||||
if (!await file.exists()) return;
|
||||
String fileContent = await file.readAsString();
|
||||
if (duplicateCheck != null && fileContent.contains(duplicateCheck)) return;
|
||||
|
||||
if (importLine != null && importFileName != null && !fileContent.contains(importFileName)) {
|
||||
fileContent = "$importLine\n$fileContent";
|
||||
}
|
||||
|
||||
final lastBrace = fileContent.lastIndexOf('}');
|
||||
if (lastBrace != -1) {
|
||||
// Inject with double newlines between previous content and new content
|
||||
fileContent = fileContent.substring(0, lastBrace).trimRight() + '\n\n$content\n' + fileContent.substring(lastBrace);
|
||||
await file.writeAsString(fileContent);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _injectInternalMemory(String path, String keyLine, String methods, Logger logger, {String? importLine, String? importFileName, String? duplicateCheck}) async {
|
||||
final file = File(path);
|
||||
if (!await file.exists()) return;
|
||||
String content = await file.readAsString();
|
||||
|
||||
if (duplicateCheck != null && content.contains(duplicateCheck)) return;
|
||||
|
||||
if (importLine != null && importFileName != null && !content.contains(importFileName)) {
|
||||
content = "$importLine\n$content";
|
||||
}
|
||||
|
||||
if (!content.contains("import 'dart:convert';")) {
|
||||
content = "import 'dart:convert';\n$content";
|
||||
}
|
||||
|
||||
// Inject Key at the top with forced extra spacing
|
||||
final classStart = content.indexOf('{');
|
||||
if (classStart != -1) {
|
||||
content = content.substring(0, classStart + 1) + "$keyLine" + content.substring(classStart + 1);
|
||||
}
|
||||
|
||||
// Inject Methods at the bottom
|
||||
final lastBrace = content.lastIndexOf('}');
|
||||
if (lastBrace != -1) {
|
||||
content = content.substring(0, lastBrace).trimRight() + "\n\n$methods\n" + content.substring(lastBrace);
|
||||
}
|
||||
|
||||
await file.writeAsString(content);
|
||||
}
|
||||
8
frontend/bricks/internal_memory/hooks/pubspec.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
name: internal_memory_hooks
|
||||
description: Hooks for internal_memory.
|
||||
publish_to: none
|
||||
environment:
|
||||
sdk: ">=3.0.0 <4.0.0"
|
||||
dependencies:
|
||||
mason: ^0.1.0-dev.51
|
||||
yaml: ^3.1.2
|
||||
3
frontend/bricks/mvvc_template/CHANGELOG.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# 0.1.0+1
|
||||
|
||||
- TODO: Describe initial release.
|
||||
1
frontend/bricks/mvvc_template/LICENSE
Normal file
@@ -0,0 +1 @@
|
||||
TODO: Add your license here.
|
||||
27
frontend/bricks/mvvc_template/README.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# mvvc_template
|
||||
|
||||
[](https://github.com/felangel/mason)
|
||||
|
||||
A new brick created with the Mason CLI.
|
||||
|
||||
_Generated by [mason][1] 🧱_
|
||||
|
||||
## Getting Started 🚀
|
||||
|
||||
This is a starting point for a new brick.
|
||||
A few resources to get you started if this is your first brick template:
|
||||
|
||||
- [Official Mason Documentation][2]
|
||||
- [Code generation with Mason Blog][3]
|
||||
- [Very Good Livestream: Felix Angelov Demos Mason][4]
|
||||
- [Flutter Package of the Week: Mason][5]
|
||||
- [Observable Flutter: Building a Mason brick][6]
|
||||
- [Meet Mason: Flutter Vikings 2022][7]
|
||||
|
||||
[1]: https://github.com/felangel/mason
|
||||
[2]: https://docs.brickhub.dev
|
||||
[3]: https://verygood.ventures/blog/code-generation-with-mason
|
||||
[4]: https://youtu.be/G4PTjA6tpTU
|
||||
[5]: https://youtu.be/qjA0JFiPMnQ
|
||||
[6]: https://youtu.be/o8B1EfcUisw
|
||||
[7]: https://youtu.be/LXhgiF5HiQg
|
||||
@@ -0,0 +1,2 @@
|
||||
abstract class Connect{{screen}}{
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
||||
import '../parent/ParentViewModel.dart';
|
||||
import 'Connect{{screen}}.dart';
|
||||
|
||||
class View{{screen}} extends ParentViewModel {
|
||||
Connect{{screen}} connection;
|
||||
|
||||
View{{screen}}(BuildContext context, this.connection) : super(context);
|
||||
|
||||
// Business logic goes here. Guard every network call with hasNetwork, wrap
|
||||
// it in showLoading/closeLoading, and push results back through
|
||||
// `connection` rather than touching widgets directly.
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import '{{screen}}State.dart';
|
||||
|
||||
class {{screen}} extends StatefulWidget{
|
||||
const {{screen}} ({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<{{screen}}> createState() => {{screen}}State();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stacked/stacked.dart';
|
||||
|
||||
import 'package:Grounded/Grounded/about/internal/application/TextType.dart';
|
||||
import 'package:Grounded/Grounded/designs/Responsive.dart';
|
||||
import 'package:Grounded/Grounded/designs/Shell.dart';
|
||||
import 'package:Grounded/Grounded/designs/text/Text.dart';
|
||||
import 'package:Grounded/Grounded/utils/Colors.dart';
|
||||
|
||||
import 'Connect{{screen}}.dart';
|
||||
import '{{screen}}.dart';
|
||||
import 'View{{screen}}.dart';
|
||||
|
||||
class {{screen}}State extends State<{{screen}}> implements Connect{{screen}} {
|
||||
View{{screen}}? _model;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ViewModelBuilder<View{{screen}}>.reactive(
|
||||
viewModelBuilder: () => View{{screen}}(context, this),
|
||||
onViewModelReady: (viewModel) {
|
||||
_model = viewModel;
|
||||
_initiate();
|
||||
},
|
||||
builder: (context, viewModel, child) => LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints viewportConstraints) {
|
||||
return Responsive(
|
||||
mobile: _mobileView(viewportConstraints),
|
||||
tablet: _tabletView(viewportConstraints),
|
||||
desktop: _desktopView(viewportConstraints),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _initiate() {
|
||||
// Load initial data through _model here; push results back via the
|
||||
// Connect{{screen}} callbacks below.
|
||||
}
|
||||
|
||||
void _onBack() {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
Widget _mobileView(BoxConstraints viewportConstraints) {
|
||||
return Sheet(
|
||||
eyebrow: "Grounded",
|
||||
title: "{{screen}}",
|
||||
onBack: _onBack,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
displayTitle("{{screen}}"),
|
||||
const SizedBox(height: 14),
|
||||
text(
|
||||
"Replace this with the screen content.",
|
||||
14,
|
||||
TextType.Regular,
|
||||
color: colorGrey2,
|
||||
height: 1.55,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _tabletView(BoxConstraints viewportConstraints) {
|
||||
return _mobileView(viewportConstraints);
|
||||
}
|
||||
|
||||
Widget _desktopView(BoxConstraints viewportConstraints) {
|
||||
return _mobileView(viewportConstraints);
|
||||
}
|
||||
}
|
||||
38
frontend/bricks/mvvc_template/brick.yaml
Normal file
@@ -0,0 +1,38 @@
|
||||
name: mvvc_template
|
||||
description: A new brick created with the Mason CLI.
|
||||
|
||||
# The following defines the brick repository url.
|
||||
# Uncomment and update the following line before publishing the brick.
|
||||
# repository: https://github.com/my_org/my_repo
|
||||
|
||||
# The following defines the version and build number for your brick.
|
||||
# A version number is three numbers separated by dots, like 1.2.34
|
||||
# followed by an optional build number (separated by a +).
|
||||
version: 0.1.0+1
|
||||
|
||||
# The following defines the environment for the current brick.
|
||||
# It includes the version of mason that the brick requires.
|
||||
environment:
|
||||
mason: ^0.1.1
|
||||
|
||||
# Variables specify dynamic values that your brick depends on.
|
||||
# Zero or more variables can be specified for a given brick.
|
||||
# Each variable has:
|
||||
# * a type (string, number, boolean, enum, array, or list)
|
||||
# * an optional short description
|
||||
# * an optional default value
|
||||
# * an optional list of default values (array only)
|
||||
# * an optional prompt phrase used when asking for the variable
|
||||
# * a list of values (enums only)
|
||||
# * an optional separator (list only)
|
||||
vars:
|
||||
project:
|
||||
type: string
|
||||
description: The project name
|
||||
default: Grounded
|
||||
prompt: What is your project name?
|
||||
screen:
|
||||
type: string
|
||||
description: The name of the new screen
|
||||
default: ActivityNew
|
||||
prompt: What is your file name?
|
||||
55
frontend/design.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Grounded — Design Language
|
||||
|
||||
Reference: black device chrome, a white content sheet that rises into it with a
|
||||
large corner radius, oversized light display titles, tiny grey all-caps metadata
|
||||
labels, pill chips, and a lot of whitespace. The app reads as a record, not a
|
||||
dashboard.
|
||||
|
||||
## Type — General Sans
|
||||
|
||||
| Role | Family | Size | Use |
|
||||
|---|---|---|---|
|
||||
| Display | `TextType.Light` | 30–44 | Screen titles. Always light, never bold. |
|
||||
| Title | `TextType.Bold` | 17–20 | Card and section titles. |
|
||||
| Body | `TextType.Regular` | 13–14, `height: 1.5` | Descriptions, copy. |
|
||||
| Label | `TextType.Bold` | 10–11, `letterSpacing: 0.8–1.2`, uppercase, `colorGrey2` | Metadata above a value. |
|
||||
| Metric | `TextType.Bold` | 24–34 | Debt score, counts. |
|
||||
|
||||
The label/value pair is the core unit: a tiny grey all-caps label sitting
|
||||
directly above a large dark value. Used everywhere numbers appear.
|
||||
|
||||
## Geometry
|
||||
|
||||
- Sheet radius `28`, card radius `16`, chip radius `999`, control radius `12`.
|
||||
- Screen padding `20` horizontal. Card padding `16`. Section gap `28`.
|
||||
- Hairlines at `colorDivider` (black 7%), borders at `colorBorder` (black 8%).
|
||||
- One soft shadow only: `0 4 18 rgba(0,0,0,0.03)`. No coloured glows.
|
||||
|
||||
## Colour
|
||||
|
||||
Near-black ink (`colorPrimaryDark #141414`) on warm off-white
|
||||
(`colorPrimaryLight #EDEEEA`), with a single green accent (`colorPrimary
|
||||
#2F6F4E`). Enforcement tiers own the rest of the palette:
|
||||
|
||||
| Standing | Colour |
|
||||
|---|---|
|
||||
| Good | green `#2F6F4E` |
|
||||
| Warned | amber `#C98A04` |
|
||||
| Grounded | rust `#B5442F` |
|
||||
| Lockdown | oxblood `#7A1F14` |
|
||||
|
||||
The tier colour is used consistently — header, chip, meter, queue accent — so
|
||||
the standing is legible without reading the word.
|
||||
|
||||
## Structure
|
||||
|
||||
Every screen is: black `headerBar` (back, title, action) → white sheet with a
|
||||
`28` top radius → `sectionHeader` (label + light display title) → content.
|
||||
|
||||
## Rules
|
||||
|
||||
- Display titles are Light. Bold is for labels and metrics only.
|
||||
- Numbers get a label above them, never beside them.
|
||||
- Chips carry state, never actions.
|
||||
- One primary button per screen; everything else is outlined or text.
|
||||
- Empty states are plain. An empty overdue queue is good news, not a party.
|
||||
57
frontend/fonts/LICENSE-GeneralSans.txt
Normal file
@@ -0,0 +1,57 @@
|
||||
Fontshare EULA
|
||||
|
||||
---—---------------------------------—------------------------------
|
||||
Free Font - End User License Agreement (FF EULA)
|
||||
---—---------------------------------—------------------------------
|
||||
Notice to User
|
||||
Indian Type Foundry designs, produces and distributes font software as digital fonts to end users worldwide. In addition to commercial fonts that are available for a fee, ITF also offers several fonts which can be used free of charge. The free fonts are distributed through a dedicated platform called www.fontshare.com (“Fontshare”) to end users worldwide. These free fonts are subject to this legally binding EULA between the Indian Type Foundry (“Indian Type Foundry” or “Licensor”) and you (“Licensee”).
|
||||
You acknowledge that the Font Software and designs embodied therein are protected by the copyright, other intellectual property rights and industrial property rights and by international treaties. They are and remain at all times the intellectual property of the Indian Type Foundry.
|
||||
In addition to direct download, Fontshare also offers these free fonts via Fonthsare API using a code. In this case, the Font Software is delivered directly from the servers used by Indian Type Foundry to the Licensee's website, without the Licensee having to download the Font Software.
|
||||
By downloading, accessing the API, installing, storing, copying or using one of any Font Software, you agree to the following terms.
|
||||
|
||||
Definitions
|
||||
“Font Software” refers to the set of computer files or programs released under this license that instructs your computer to display and/or print each letters, characters, typographic designs, ornament and so forth. Font Software includes all bitmap and vector representations of fonts and typographic representations and embellishments created by or derived from the Font Software.
|
||||
“Original Version” refers to the Font Software as distributed by the Indian Type Foundry as the copyright holder.
|
||||
“Derivative Work” refers to the pictorial representation of the font created by the Font Software, including typographic characters such as letters, numerals, ornaments, symbols, or punctuation and special characters.
|
||||
|
||||
01. Grant of License
|
||||
You are hereby granted a non-exclusive, non-assignable, non-transferrable, terminable license to access, download and use the Font Software for your personal or commercial use for an unlimited period of time for free of charge.
|
||||
You may use the font Software in any media (including Print, Web, Mobile, Digital, Apps, ePub, Broadcasting and OEM) at any scale, at any location worldwide.
|
||||
You may use the Font Software to create logos and other graphic elements, images on any surface, vector files or other scalable drawings and static images.
|
||||
You may use the Font Software on any number of devices (computer, tablet, phone). The number of output devices (Printers) is not restricted.
|
||||
You may make only such reasonable number of back-up copies suitable to your permitted use.
|
||||
You may but are not required to identify Indian Type Foundry Fonts in your work credits.
|
||||
|
||||
02. Limitations of usage
|
||||
You may not modify, edit, adapt, translate, reverse engineer, decompile or disassemble, alter or otherwise copy the Font Software or the designs embodied therein in whole or in part, without the prior written consent of the Licensor.
|
||||
The Fonts may not - beyond the permitted copies and the uses defined herein - be distributed, duplicated, loaned, resold or licensed in any way, whether by lending, donating or give otherwise to a person or entity. This includes the distribution of the Fonts by e-mail, on USB sticks, CD-ROMs, or other media, uploading them in a public server or making the fonts available on peer-to-peer networks. A passing on to external designers or service providers (design agencies, repro studios, printers, etc.) is also not permitted.
|
||||
You are not allowed to transmit the Font Software over the Internet in font serving or for font replacement by means of technologies such as but not limited to EOT, Cufon, sIFR or similar technologies that may be developed in the future without the prior written consent of the Licensor.
|
||||
|
||||
03. Embedding
|
||||
You may embed the Font Software in PDF and other digital documents provided that is done in a secured, read-only mode. It must be ensured beyond doubt that the recipient cannot use the Font Software to edit or to create new documents. The design data (PDFs) created in this way and under these created design data (PDFs) may be distributed in any number.
|
||||
The extraction of the Font Software in whole or in part is prohibited.
|
||||
|
||||
04. Third party use, Commercial print service provider
|
||||
You may include the Font Software in a non-editable electronic document solely for printing and display purposes and provide that electronic document to the commercial print service provider for the purpose of printing. If the print service needs to install the fonts, they too need to download the Font Software from the Licensor's website.
|
||||
|
||||
05. Derivative Work
|
||||
You are allowed to make derivative works as far as you use them for your personal or commercial use. However, you cannot modify, make changes or reverse engineer the original font software provided to you. Any derivative works are the exclusive property of the Licensor and shall be subject to the terms and conditions of this EULA. Derivative works may not be sub-licensed, sold, leased, rented, loaned, or given away without the express written permission of the Licensor.
|
||||
|
||||
06. Warranty and Liability
|
||||
BECAUSE THIS SOFTWARE IS LICENSED FREE OF CHARGE, INDIAN TYPE FOUNDRY MAKES NO WARRANTIES, EXPRESS OR IMPLIED AS TO THE MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR OTHERWISE. THE FONT SOFTWARE WAS NOT MANUFACTURED FOR USE IN MANUFACTURING CONTROL DEVICES OR NAVIGATION DEVICES OR IN CIRCUMSTANCES THAT COULD RESULT IN ENVIRONMENTAL DAMAGE OR PERSONAL INJURY. WITHOUT LIMITING THE FOREGOING, INDIAN TYPE FOUNDRY SHALL IN NO EVENT BE LIABLE TO THE LICENSED USER OR ANY OTHER THIRD PARTY FOR ANY DIRECT, CONSEQUENTIAL OR INCIDENTAL DAMAGES, INCLUDING DAMAGES FROM LOSS OF BUSINESS PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION NOR FOR LOST PROFITS OR SAVINGS ARISING OUT OF THE USE OR INABILITY TO USE THE PRODUCT EVEN IF NOTIFIED IN ADVANCE, UNDER NO CIRCUMSTANCES SHALL INDIAN TYPE FOUNDRY’S LIABILITY EXCEED THE REPLACEMENT COST OF THE SOFTWARE.
|
||||
IF LICENSEE CHOOSES TO ACCESS THE FONT SOFTWARE THROUGH A CODE (API), IT MAY HAVE A DIRECT IMPACT ON LICENSEE'S WEBSITE OR APPLICATIONS. INDIAN TYPE FOUNDRY IS NOT RESPONSIBLE OR LIABLE FOR ANY INTERRUPTION, MALFUNCTION, DOWNTIME OR OTHER FAILURE OF THE WEBSITE OR ITS API.
|
||||
|
||||
07. Updates, Maintenance and Support Services
|
||||
Licensor will not provide you with any support services for the Software under this Agreement.
|
||||
|
||||
08. Termination
|
||||
Any breach of the terms of this agreement shall be a cause for termination, provided that such breach is notified in writing to the Licensee by the Licensor and the Licensee failed to rectify the breach within 30 days of the receipt of such notification.
|
||||
In the event of termination and without limitation of any remedies under law or equity, you must delete the Font Software and all copies thereof. Proof of this must be provided upon request of the Licensor.
|
||||
We reserve the right to claim damages for the violation of the conditions.
|
||||
|
||||
09. Final Provisions
|
||||
If individual provisions of this agreement are or become invalid, the validity of the remaining provisions shall remain unaffected. Invalid provisions shall be replaced by mutual agreement by such provisions that are suitable to achieve the desired economic purpose, taking into account the interests of both parties. The same shall apply mutatis mutandis to the filling of any gaps which may arise in this agreement.
|
||||
This contract is subject to laws of the Republic of India. Place of performance and exclusive place of jurisdiction for all disputes between the parties arising out of or in connection with this contract is, as far as legally permissible, Ahmedabad, India.
|
||||
-
|
||||
Last Updated on 22 March 2021
|
||||
Copyright 2021 Indian Type Foundry. All rights reserved.
|
||||
BIN
frontend/fonts/bold.ttf
Normal file
BIN
frontend/fonts/light.ttf
Normal file
BIN
frontend/fonts/medium.ttf
Normal file
BIN
frontend/fonts/regular.ttf
Normal file
34
frontend/ios/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
**/dgph
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.moved-aside
|
||||
*.pbxuser
|
||||
*.perspectivev3
|
||||
**/*sync/
|
||||
.sconsign.dblite
|
||||
.tags*
|
||||
**/.vagrant/
|
||||
**/DerivedData/
|
||||
Icon?
|
||||
**/Pods/
|
||||
**/.symlinks/
|
||||
profile
|
||||
xcuserdata
|
||||
**/.generated/
|
||||
Flutter/App.framework
|
||||
Flutter/Flutter.framework
|
||||
Flutter/Flutter.podspec
|
||||
Flutter/Generated.xcconfig
|
||||
Flutter/ephemeral/
|
||||
Flutter/app.flx
|
||||
Flutter/app.zip
|
||||
Flutter/flutter_assets/
|
||||
Flutter/flutter_export_environment.sh
|
||||
ServiceDefinitions.json
|
||||
Runner/GeneratedPluginRegistrant.*
|
||||
|
||||
# Exceptions to above rules.
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.pbxuser
|
||||
!default.perspectivev3
|
||||
24
frontend/ios/Flutter/AppFrameworkInfo.plist
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>App</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>io.flutter.flutter.app</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>App</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
1
frontend/ios/Flutter/Debug.xcconfig
Normal file
@@ -0,0 +1 @@
|
||||
#include "Generated.xcconfig"
|
||||
1
frontend/ios/Flutter/Release.xcconfig
Normal file
@@ -0,0 +1 @@
|
||||
#include "Generated.xcconfig"
|
||||
644
frontend/ios/Runner.xcodeproj/project.pbxproj
Normal file
@@ -0,0 +1,644 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */; };
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */ = {isa = PBXBuildFile; productRef = 78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = 97C146ED1CF9000F007C117D;
|
||||
remoteInfo = Runner;
|
||||
};
|
||||
/* End PBXContainerItemProxy section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */ = {
|
||||
isa = PBXCopyFilesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = "<group>"; };
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = FlutterGeneratedPluginSwiftPackage; path = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
97C146EB1CF9000F007C117D /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
78A318202AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
331C8082294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
331C807B294A618700263BE5 /* RunnerTests.swift */,
|
||||
);
|
||||
path = RunnerTests;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
78E0A7A72DC9AD7400C4905E /* FlutterGeneratedPluginSwiftPackage */,
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
);
|
||||
name = Flutter;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146E51CF9000F007C117D = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9740EEB11CF90186004384FC /* Flutter */,
|
||||
97C146F01CF9000F007C117D /* Runner */,
|
||||
97C146EF1CF9000F007C117D /* Products */,
|
||||
331C8082294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146EF1CF9000F007C117D /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146EE1CF9000F007C117D /* Runner.app */,
|
||||
331C8081294A63A400263BE5 /* RunnerTests.xctest */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146F01CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */,
|
||||
97C146FD1CF9000F007C117D /* Assets.xcassets */,
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
|
||||
97C147021CF9000F007C117D /* Info.plist */,
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
|
||||
7884E8672EC3CC0400C636F2 /* SceneDelegate.swift */,
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
|
||||
);
|
||||
path = Runner;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
331C8080294A63A400263BE5 /* RunnerTests */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */;
|
||||
buildPhases = (
|
||||
331C807D294A63A400263BE5 /* Sources */,
|
||||
331C807F294A63A400263BE5 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */,
|
||||
);
|
||||
name = RunnerTests;
|
||||
productName = RunnerTests;
|
||||
productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */;
|
||||
productType = "com.apple.product-type.bundle.unit-test";
|
||||
};
|
||||
97C146ED1CF9000F007C117D /* Runner */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
|
||||
buildPhases = (
|
||||
9740EEB61CF901F6004384FC /* Run Script */,
|
||||
97C146EA1CF9000F007C117D /* Sources */,
|
||||
97C146EB1CF9000F007C117D /* Frameworks */,
|
||||
97C146EC1CF9000F007C117D /* Resources */,
|
||||
9705A1C41CF9048500538489 /* Embed Frameworks */,
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = Runner;
|
||||
packageProductDependencies = (
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */,
|
||||
);
|
||||
productName = Runner;
|
||||
productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
97C146E61CF9000F007C117D /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
BuildIndependentTargetsInParallel = YES;
|
||||
LastUpgradeCheck = 1510;
|
||||
ORGANIZATIONNAME = "";
|
||||
TargetAttributes = {
|
||||
331C8080294A63A400263BE5 = {
|
||||
CreatedOnToolsVersion = 14.0;
|
||||
TestTargetID = 97C146ED1CF9000F007C117D;
|
||||
};
|
||||
97C146ED1CF9000F007C117D = {
|
||||
CreatedOnToolsVersion = 7.3.1;
|
||||
LastSwiftMigration = 1100;
|
||||
};
|
||||
};
|
||||
};
|
||||
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
|
||||
compatibilityVersion = "Xcode 9.3";
|
||||
developmentRegion = en;
|
||||
hasScannedForEncodings = 0;
|
||||
knownRegions = (
|
||||
en,
|
||||
Base,
|
||||
);
|
||||
mainGroup = 97C146E51CF9000F007C117D;
|
||||
packageReferences = (
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
|
||||
);
|
||||
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
97C146ED1CF9000F007C117D /* Runner */,
|
||||
331C8080294A63A400263BE5 /* RunnerTests */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
331C807F294A63A400263BE5 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EC1CF9000F007C117D /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
|
||||
);
|
||||
name = "Thin Binary";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
9740EEB61CF901F6004384FC /* Run Script */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
alwaysOutOfDate = 1;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "Run Script";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
331C807D294A63A400263BE5 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
97C146EA1CF9000F007C117D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
|
||||
7884E8682EC3CC0700C636F2 /* SceneDelegate.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
331C8086294A63A400263BE5 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = 97C146ED1CF9000F007C117D /* Runner */;
|
||||
targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */;
|
||||
};
|
||||
/* End PBXTargetDependency section */
|
||||
|
||||
/* Begin PBXVariantGroup section */
|
||||
97C146FA1CF9000F007C117D /* Main.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C146FB1CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = Main.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
97C147001CF9000F007C117D /* Base */,
|
||||
);
|
||||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
249021D3217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
249021D4217E4FDB00AE95B9 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = nya.grounded;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
331C8088294A63A400263BE5 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = nya.grounded.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
331C8089294A63A400263BE5 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = nya.grounded.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
331C808A294A63A400263BE5 /* Profile */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
BUNDLE_LOADER = "$(TEST_HOST)";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = nya.grounded.RunnerTests;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_VERSION = 5.0;
|
||||
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner";
|
||||
};
|
||||
name = Profile;
|
||||
};
|
||||
97C147031CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_TESTABILITY = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||
"DEBUG=1",
|
||||
"$(inherited)",
|
||||
);
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147041CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = AppIcon;
|
||||
CLANG_ANALYZER_NONNULL = YES;
|
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
|
||||
CLANG_CXX_LIBRARY = "libc++";
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CLANG_ENABLE_OBJC_ARC = YES;
|
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
|
||||
CLANG_WARN_BOOL_CONVERSION = YES;
|
||||
CLANG_WARN_COMMA = YES;
|
||||
CLANG_WARN_CONSTANT_CONVERSION = YES;
|
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
|
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||
CLANG_WARN_EMPTY_BODY = YES;
|
||||
CLANG_WARN_ENUM_CONVERSION = YES;
|
||||
CLANG_WARN_INFINITE_RECURSION = YES;
|
||||
CLANG_WARN_INT_CONVERSION = YES;
|
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
|
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
|
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
|
||||
CLANG_WARN_STRICT_PROTOTYPES = YES;
|
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES;
|
||||
CLANG_WARN_UNREACHABLE_CODE = YES;
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
ENABLE_NS_ASSERTIONS = NO;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||
GCC_NO_COMMON_BLOCKS = YES;
|
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||
GCC_WARN_UNDECLARED_SELECTOR = YES;
|
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
SDKROOT = iphoneos;
|
||||
SUPPORTED_PLATFORMS = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-O";
|
||||
TARGETED_DEVICE_FAMILY = "1,2";
|
||||
VALIDATE_PRODUCT = YES;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
97C147061CF9000F007C117D /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = nya.grounded;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
97C147071CF9000F007C117D /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
ENABLE_BITCODE = NO;
|
||||
INFOPLIST_FILE = Runner/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = nya.grounded;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
SWIFT_VERSION = 5.0;
|
||||
VERSIONING_SYSTEM = "apple-generic";
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
331C8088294A63A400263BE5 /* Debug */,
|
||||
331C8089294A63A400263BE5 /* Release */,
|
||||
331C808A294A63A400263BE5 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147031CF9000F007C117D /* Debug */,
|
||||
97C147041CF9000F007C117D /* Release */,
|
||||
249021D3217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
97C147061CF9000F007C117D /* Debug */,
|
||||
97C147071CF9000F007C117D /* Release */,
|
||||
249021D4217E4FDB00AE95B9 /* Profile */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCLocalSwiftPackageReference section */
|
||||
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
|
||||
isa = XCLocalSwiftPackageReference;
|
||||
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCLocalSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
78A3181F2AECB46A00862997 /* FlutterGeneratedPluginSwiftPackage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
productName = FlutterGeneratedPluginSwiftPackage;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
}
|
||||
7
frontend/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,119 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.3">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
buildImplicitDependencies = "YES">
|
||||
<PreActions>
|
||||
<ExecutionAction
|
||||
ActionType = "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction">
|
||||
<ActionContent
|
||||
title = "Run Prepare Flutter Framework Script"
|
||||
scriptText = "/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" prepare ">
|
||||
<EnvironmentBuildable>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</EnvironmentBuildable>
|
||||
</ActionContent>
|
||||
</ExecutionAction>
|
||||
</PreActions>
|
||||
<BuildActionEntries>
|
||||
<BuildActionEntry
|
||||
buildForTesting = "YES"
|
||||
buildForRunning = "YES"
|
||||
buildForProfiling = "YES"
|
||||
buildForArchiving = "YES"
|
||||
buildForAnalyzing = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildActionEntry>
|
||||
</BuildActionEntries>
|
||||
</BuildAction>
|
||||
<TestAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES">
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
<Testables>
|
||||
<TestableReference
|
||||
skipped = "NO"
|
||||
parallelizable = "YES">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "331C8080294A63A400263BE5"
|
||||
BuildableName = "RunnerTests.xctest"
|
||||
BlueprintName = "RunnerTests"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</TestableReference>
|
||||
</Testables>
|
||||
</TestAction>
|
||||
<LaunchAction
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
customLLDBInitFile = "$(SRCROOT)/Flutter/ephemeral/flutter_lldbinit"
|
||||
launchStyle = "0"
|
||||
useCustomWorkingDirectory = "NO"
|
||||
ignoresPersistentStateOnLaunch = "NO"
|
||||
debugDocumentVersioning = "YES"
|
||||
debugServiceExtension = "internal"
|
||||
enableGPUValidationMode = "1"
|
||||
allowLocationSimulation = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</LaunchAction>
|
||||
<ProfileAction
|
||||
buildConfiguration = "Profile"
|
||||
shouldUseLaunchSchemeArgsEnv = "YES"
|
||||
savedToolIdentifier = ""
|
||||
useCustomWorkingDirectory = "NO"
|
||||
debugDocumentVersioning = "YES">
|
||||
<BuildableProductRunnable
|
||||
runnableDebuggingMode = "0">
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
|
||||
BuildableName = "Runner.app"
|
||||
BlueprintName = "Runner"
|
||||
ReferencedContainer = "container:Runner.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
</AnalyzeAction>
|
||||
<ArchiveAction
|
||||
buildConfiguration = "Release"
|
||||
revealArchiveInOrganizer = "YES">
|
||||
</ArchiveAction>
|
||||
</Scheme>
|
||||
7
frontend/ios/Runner.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "group:Runner.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>IDEDidComputeMac32BitWarning</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>PreviewsEnabled</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
16
frontend/ios/Runner/AppDelegate.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
import Flutter
|
||||
import UIKit
|
||||
|
||||
@main
|
||||
@objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
|
||||
override func application(
|
||||
_ application: UIApplication,
|
||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
|
||||
) -> Bool {
|
||||
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
}
|
||||
|
||||
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
|
||||
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
{"images":[{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"Icon-App-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"Icon-App-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"Icon-App-40x40@3x.png","scale":"3x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"Icon-App-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"Icon-App-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"Icon-App-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"Icon-App-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"Icon-App-40x40@2x.png","scale":"2x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"Icon-App-50x50@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"Icon-App-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"Icon-App-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"Icon-App-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"Icon-App-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}}
|
||||
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 473 B |
|
After Width: | Height: | Size: 934 B |
|
After Width: | Height: | Size: 1.4 KiB |