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
This commit is contained in:
alvocool
2026-07-27 09:11:17 +03:00
commit 16bff634b5
315 changed files with 19132 additions and 0 deletions

27
.gitattributes vendored Normal file
View File

@@ -0,0 +1,27 @@
# Normalise line endings so the repo stays clean across Windows and CI.
* text=auto eol=lf
# Windows-only tooling keeps CRLF.
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# Binaries — never touched, never diffed as text.
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.ttf binary
*.otf binary
*.woff binary
*.woff2 binary
*.pdf binary
*.zip binary
*.jar binary
*.keystore binary
*.jks binary
# Generated / vendored — collapse in diffs and exclude from language stats.
pubspec.lock linguist-generated=true -diff
**/ios/Runner.xcodeproj/project.pbxproj -diff

209
.gitignore vendored Normal file
View File

@@ -0,0 +1,209 @@
# ─────────────────────────────────────────────────────────────────────────────
# Grounded — repository ignore rules
# ─────────────────────────────────────────────────────────────────────────────
# ── Secrets & environment ────────────────────────────────────────────────────
# .env carries the backend hosts and app version. Committing it leaks the
# deployment topology, so the template is tracked and the real file is not.
.env
.env.*
!.env.example
*.pem
*.key
*.p12
*.jks
*.keystore
*.mobileprovision
key.properties
secrets.properties
google-services.json
GoogleService-Info.plist
firebase_options.dart
service-account*.json
credentials.json
*.retrofit.dart.log
# ── Dart / Flutter ───────────────────────────────────────────────────────────
.dart_tool/
.flutter-plugins
.flutter-plugins-dependencies
.packages
.pub-cache/
.pub/
build/
coverage/
doc/api/
**/doc/api/
*.dart.js
*.info.json
*.js_
*.js.deps
*.js.map
.flutter-versions
pubspec_overrides.yaml
# Generated sources
*.g.dart
*.freezed.dart
*.mocks.dart
*.config.dart
# Symbolication / obfuscation
app.*.symbols
app.*.map.json
# ── Mason ────────────────────────────────────────────────────────────────────
# Bricks themselves are tracked; the resolved cache is not.
.mason/
**/hooks/.dart_tool/
**/hooks/pubspec.lock
# ── Android ──────────────────────────────────────────────────────────────────
**/android/**/gradle-wrapper.jar
**/android/.gradle
**/android/captures/
**/android/gradlew
**/android/gradlew.bat
**/android/local.properties
**/android/**/GeneratedPluginRegistrant.java
**/android/key.properties
**/android/app/release/
**/android/app/debug/
**/android/app/profile/
*.apk
*.aab
*.ap_
*.dex
.cxx/
# ── iOS ──────────────────────────────────────────────────────────────────────
**/ios/**/*.mode1v3
**/ios/**/*.mode2v3
**/ios/**/*.moved-aside
**/ios/**/*.pbxuser
**/ios/**/*.perspectivev3
**/ios/**/*sync/
**/ios/**/.sconsign.dblite
**/ios/**/.tags*
**/ios/**/.vagrant/
**/ios/**/DerivedData/
**/ios/**/Icon?
**/ios/**/Pods/
**/ios/**/.symlinks/
**/ios/**/profile
**/ios/**/xcuserdata
**/ios/.generated/
**/ios/Flutter/App.framework
**/ios/Flutter/Flutter.framework
**/ios/Flutter/Flutter.podspec
**/ios/Flutter/Generated.xcconfig
**/ios/Flutter/ephemeral/
**/ios/Flutter/app.flx
**/ios/Flutter/app.zip
**/ios/Flutter/flutter_assets/
**/ios/Flutter/flutter_export_environment.sh
**/ios/Flutter/.last_build_id
**/ios/ServiceDefinitions.json
**/ios/Runner/GeneratedPluginRegistrant.*
*.ipa
*.dSYM.zip
*.dSYM
# ── macOS ────────────────────────────────────────────────────────────────────
**/macos/Flutter/GeneratedPluginRegistrant.swift
**/macos/Flutter/ephemeral/
**/macos/Flutter/Flutter-Debug.xcconfig
**/macos/Flutter/Flutter-Release.xcconfig
**/macos/Flutter/Flutter-Profile.xcconfig
**/macos/Pods/
**/xcuserdata/
**/DerivedData/
# ── Windows ──────────────────────────────────────────────────────────────────
**/windows/flutter/generated_plugin_registrant.cc
**/windows/flutter/generated_plugin_registrant.h
**/windows/flutter/generated_plugins.cmake
**/windows/flutter/ephemeral/
*.exe
*.msix
*.pdb
*.ilk
# ── Linux ────────────────────────────────────────────────────────────────────
**/linux/flutter/generated_plugin_registrant.cc
**/linux/flutter/generated_plugin_registrant.h
**/linux/flutter/generated_plugins.cmake
**/linux/flutter/ephemeral/
# ── Web ──────────────────────────────────────────────────────────────────────
**/web/*.g.dart
lib/generated_plugin_registrant.dart
# ── IDEs & editors ───────────────────────────────────────────────────────────
.idea/
*.iml
*.ipr
*.iws
.vscode/
!.vscode/launch.json
!.vscode/settings.json
*.swp
*.swo
*~
.history/
.atom/
.buildlog/
.build/
migrate_working_dir/
.metals/
.bloop/
# ── OS noise ─────────────────────────────────────────────────────────────────
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Thumbs.db:encryptable
desktop.ini
$RECYCLE.BIN/
*.lnk
# ── Logs, temp, caches ───────────────────────────────────────────────────────
*.log
*.tmp
*.temp
*.bak
*.orig
*.rej
*.pyc
__pycache__/
*.class
.cache/
tmp/
temp/
node_modules/
# ── Archives & large binaries ────────────────────────────────────────────────
*.zip
*.tar
*.tar.gz
*.tgz
*.rar
*.7z
*.iso
*.dmg
# ── Working scratch ──────────────────────────────────────────────────────────
# Icon exploration output and other throwaways.
**/assets/icons/_*.png
**/assets/icons/try_*.png
scratch/
scratchpad/
*.local
# ── Agent tooling ────────────────────────────────────────────────────────────
.claude/settings.local.json
.agents/

94
README.md Normal file
View File

@@ -0,0 +1,94 @@
# Grounded
*A to-do app that doesn't believe you.*
Most to-do apps are neutral ledgers — they record intent and never object when
you ignore it. Grounded is an **enforcement layer**: it holds a model of what
you committed to, notices when reality diverges, and imposes escalating
consequences you agreed to in advance.
Design axiom: **the checkbox is the enemy.** Every feature exists because
self-reported completion is worthless to someone trying to stop lying to
themselves.
---
## Repository
```
frontend/ Flutter app (Android · iOS · Web · Windows)
```
See [`frontend/CLAUDE.md`](frontend/CLAUDE.md) for the architecture and
conventions, and [`frontend/design.md`](frontend/design.md) for the design
language.
---
## The model
Three primitives; everything else is derived.
| Primitive | Meaning |
|---|---|
| **Commitment** | Something you said you'd do. Has a due *window*, a class, and a proof requirement. |
| **Debt** | The weight of what you've missed — a decaying, weighted score rather than a count. |
| **Standing** | `Good → Warned → Grounded → Lockdown`. Derived from debt; decides what the app lets you do. |
Streaks reward perfection and collapse permanently on one miss. Debt is
continuous, forgiving in shape, hard to ignore, and gives you a way back.
**Goals** contain commitments — "Workout" holds "Monday shoulders". A goal
never carries debt; the tasks inside it do.
---
## What makes it different
- **Due windows, not due dates.** `Mon 06:0008:00` can actually close. A miss
is a permanent event, never a silent rollover to today.
- **Capacity blocking.** Chronic overdue is usually overcommitment misdiagnosed
as laziness. The app plans against what you *historically complete*, learns
your per-category estimation multiplier, and refuses plans that don't fit.
- **Excuses get clustered.** *"'Too tired' has appeared 14 times this month, 11
of them on gym days, 9 of them after 7pm. Consider moving gym to morning."*
- **Proof of completion.** Honour · Photo · Timer · Location · Health · Witness.
Completing outside the window records as *late complete* — distinct in
history, and it never reduces debt to zero.
- **A live runner.** Starting a task takes over the screen, keeps time from
wall-clock so screen-off can't cheat it, and pauses when you leave the app.
- **Plyometrics is where it stops you.** Weekly ground-contact ceilings and
enforced recovery gaps — connective tissue doesn't recover on a motivation
schedule.
## And what keeps it usable
An app built on guilt has an obvious failure mode: the people who need it most
delete it during their worst week. So — rationed **amnesty tokens**, **sick and
travel mode** that pauses debt entirely, a **tone slider** hard-capped so no
copy ever attacks the person rather than the behaviour, and **distress
detection** that drops the strict persona completely when debt spikes while
engagement and readiness fall. Strictness is never the response to someone who
is actually struggling.
---
## Running it
```bash
cd frontend
cp .env.example .env # then point it at your backend
flutter pub get
flutter run
```
Requires Flutter with Dart `^3.6.2`.
---
## Status
Frontend scaffold complete: the full architecture, the debt/standing/capacity/
integrity engines, and every screen in the MVP cut. The backend is not in this
repository yet — `CommsDirections.dart` defines the contract it needs to
satisfy.

10
frontend/.env.example Normal file
View 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
View File

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

39
frontend/.metadata Normal file
View 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
View 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
View 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.

View 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
View File

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

View File

@@ -0,0 +1,45 @@
plugins {
id("com.android.application")
// 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 = "../.."
}

View File

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

View File

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

View File

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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View 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">
<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>

View 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>

View 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>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#141414</color>
</resources>

View 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>

View File

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

View File

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

View File

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

View File

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

View 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")

Binary file not shown.

Binary file not shown.

View 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>

Binary file not shown.

View File

@@ -0,0 +1,3 @@
# 0.1.0+1
- TODO: Describe initial release.

View File

@@ -0,0 +1 @@
TODO: Add your license here.

View 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.

View 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)"

View 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);
}

View 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

View 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'"

View File

@@ -0,0 +1,3 @@
# 0.1.0+1
- TODO: Describe initial release.

View File

@@ -0,0 +1 @@
TODO: Add your license here.

View 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
```
---

View 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)"

View 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);
}

View 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

View File

@@ -0,0 +1,3 @@
# 0.1.0+1
- TODO: Describe initial release.

View File

@@ -0,0 +1 @@
TODO: Add your license here.

View File

@@ -0,0 +1,27 @@
# mvvc_template
[![Powered by Mason](https://img.shields.io/endpoint?url=https%3A%2F%2Ftinyurl.com%2Fmason-badge)](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

View File

@@ -0,0 +1,2 @@
abstract class Connect{{screen}}{
}

View File

@@ -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.
}

View File

@@ -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();
}

View File

@@ -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);
}
}

View 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
View 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` | 3044 | Screen titles. Always light, never bold. |
| Title | `TextType.Bold` | 1720 | Card and section titles. |
| Body | `TextType.Regular` | 1314, `height: 1.5` | Descriptions, copy. |
| Label | `TextType.Bold` | 1011, `letterSpacing: 0.81.2`, uppercase, `colorGrey2` | Metadata above a value. |
| Metric | `TextType.Bold` | 2434 | 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.

View 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 FOUNDRYS 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

Binary file not shown.

BIN
frontend/fonts/light.ttf Normal file

Binary file not shown.

BIN
frontend/fonts/medium.ttf Normal file

Binary file not shown.

BIN
frontend/fonts/regular.ttf Normal file

Binary file not shown.

34
frontend/ios/.gitignore vendored Normal file
View 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

View 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>

View File

@@ -0,0 +1 @@
#include "Generated.xcconfig"

View File

@@ -0,0 +1 @@
#include "Generated.xcconfig"

View 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 */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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 &quot;$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh&quot; prepare&#10;">
<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>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Runner.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -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>

View File

@@ -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>

View 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)
}
}

View File

@@ -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"}}

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