Replace the customer app with Doormile CX

Book a pickup, track it to delivery — the rebuilt customer app.

- Design language from doormile-screens.html: brand #8F0F06, Manrope +
  Geist Mono (variable fonts), bordered cards instead of shadows, crimson
  brand headers, sliding tab indicator, mono for anything read digit by digit.
- lib/data (one live API implementation, plus a debug-only offline fake),
  lib/state, lib/ui (tokens, widgets, screens).
- 84 tests, plus a design snapshot harness that renders every screen with the
  real fonts: flutter test test/design_snapshot_test.dart --run-skipped
  --update-goldens

This replaces the previous app (pubspec 'doormile', app id
com.doormile.customer). That tree remains in history at 6c7d656; note its
android/app/google-services.json is not carried over, and the application id
here is in.doormile.customer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-15 16:07:33 +05:30
parent 6c7d656de5
commit 0d66627c3c
305 changed files with 21930 additions and 11056 deletions

8
.gitignore vendored
View File

@@ -43,3 +43,11 @@ app.*.map.json
/android/app/debug
/android/app/profile
/android/app/release
# Widget Preview related
.widget_preview/
# Android signing — never commit these
android/key.properties
**/*.jks
**/*.keystore

View File

@@ -4,7 +4,7 @@
# This file should be version controlled and should not be manually edited.
version:
revision: "924134a44c189315be2148659913dda1671cbe99"
revision: "d3b14c876900e553bc736ca19295fc09e3853e8e"
channel: "stable"
project_type: app
@@ -13,20 +13,17 @@ project_type: app
migration:
platforms:
- platform: root
create_revision: 924134a44c189315be2148659913dda1671cbe99
base_revision: 924134a44c189315be2148659913dda1671cbe99
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
- platform: android
create_revision: 924134a44c189315be2148659913dda1671cbe99
base_revision: 924134a44c189315be2148659913dda1671cbe99
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
- platform: ios
create_revision: 924134a44c189315be2148659913dda1671cbe99
base_revision: 924134a44c189315be2148659913dda1671cbe99
- platform: macos
create_revision: 924134a44c189315be2148659913dda1671cbe99
base_revision: 924134a44c189315be2148659913dda1671cbe99
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
- platform: web
create_revision: 924134a44c189315be2148659913dda1671cbe99
base_revision: 924134a44c189315be2148659913dda1671cbe99
create_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
base_revision: d3b14c876900e553bc736ca19295fc09e3853e8e
# User provided section

364
README.md
View File

@@ -1,63 +1,321 @@
# Doormile — EV-First Parcel Delivery (Flutter)
# Doormile — Customer App
A complete, fully-navigable Flutter app built from the Doormile design brief.
EV-first delivery, MileTruth AI routing narrative, corporate-red design system.
A Flutter app for the Doormile customer journey:
## What's inside (all screens implemented)
**Book pickup → Track → Delivered**
| Flow | Screens |
|------|---------|
| Onboarding | Splash → 3-slide Onboarding |
| Auth | Login (phone) → OTP verify |
| Home | Home hub (hero, quick actions, active shipment, eco banner) |
| Booking | Pickup/Drop → Parcel details & slot → Service & price → Review → Payment sheet → Success |
| Tracking | My Parcels (filters) → Live Tracking (map + rider) → Shipment Journey timeline |
| Wallet | Balance card, add money, saved methods, transactions |
| Profile | Stats, settings list, logout |
| Support | FAQ accordion + chat assistant |
Everything is wired with real navigation and in-memory state (Provider):
placing an order adds it to **My Parcels**, paying by wallet deducts the balance,
"Add money" updates the wallet, logout returns to login, etc.
## Design system
- **Colours / type / spacing** mirror `DESIGN.md` (primary `#960019`, Public Sans).
- Public Sans is **bundled** (`assets/fonts/PublicSans.ttf`) — no network fonts.
- Reusable widgets in `lib/widgets/` (cards, buttons, chips, progress bars).
## How to run
Open the Terminal app, then (the `flutter` tool lives in Homebrew):
```bash
export PATH="/opt/homebrew/bin:$PATH"
cd /Users/apple/Desktop/Doormile-app/doormile
# Pick ONE target:
flutter run -d chrome # opens in Chrome (fastest, no setup)
flutter run -d macos # native macOS window
flutter run # phone/emulator if one is connected
```
Demo tips: at login enter **any 10-digit number**, and at OTP enter **any 6 digits** —
there's no backend, it's a front-end prototype.
## Project layout
State is a `ChangeNotifier` behind an `InheritedNotifier`; navigation is
`Navigator` with named booking steps. Real maps come from `flutter_map` over
OpenStreetMap/CARTO tiles and real positions from `geolocator` — no API key and
no billing account required. Everything else is the Flutter SDK.
```
lib/
main.dart # app entry, theme, named routes
theme/ # colours + text styles (design tokens)
models/ # Order, AddressEntry, WalletTransaction, ...
state/app_state.dart # Provider store + mock data + booking draft
widgets/ # shared UI (AppCard, PrimaryButton, StatusChip, logo)
screens/ # one file per screen, grouped by flow
test/ # smoke, full-journey, and per-screen render tests
main.dart app entry, theme, page transitions
data/
models.dart Booking, Destination, DeliveryDetails, JourneyStage…
doormile_api.dart the service surface — one implementation
live_doormile_api.dart ← the ONLY place the app talks to a server
location_service.dart ← the ONLY place device GPS is touched
map_config.dart ← the ONLY place tile URLs, attribution + keys live
state/
app_state.dart single source of truth + stage transitions
app_scope.dart InheritedNotifier plumbing
ui/
tokens.dart colours, radii, type scale, shadows (Inter)
format.dart greeting / relative time / date labels
widgets/ buttons, chrome, inputs, option tiles, milestones…
map_tiles.dart config → flutter_map layer, + attribution
map_panel.dart real pannable map, pin locked to the centre
route_map.dart real route map: polyline, hubs, live Miler
screens/
auth/ login · sign up · OTP (shared brand scaffold)
shell_screen.dart Home · Orders · Account bottom navigation
home_screen.dart orders_screen.dart account_screen.dart
order_details_screen.dart receipt for a finished order
tracking_screen.dart live tracking, driven by stage
booking/ pickup → destination → time → review → confirmed
sheets/ place search, delivery details, cancel booking
store/ Play Console listing assets
```
## The product model this encodes
The customer creates a **pickup booking**, not a shipment.
Booking is four steps:
```
Home ▸ Book a Pickup
1. Pickup point map pin, pre-filled from the device location
2. Destination state → district, then "How many packages?" (defaults to 1)
"+ Send to another place" adds another destination
3. Pickup time windows the backend still has capacity for
4. Review one line per place, combined estimate, Book Pickup
```
**One pickup booking → one or more destinations → order(s) created after
collection.** A single Miler visit can collect packages bound for several
districts; each destination becomes its own tracked order only once the Miler
completes the pickup. The customer never sees carrier vocabulary — no
consignment, no waybill, no AWB.
* **Required:** pickup location, and for each destination a serviceable
**state** + **district**. Package count defaults to 1.
* **Optional:** exact street, landmark, recipient name and phone, delivery
instructions — per destination, in a sheet opened from the destination card
or Review. Never blocking, and shown as
*"Not added — the Miler can confirm this at pickup."*
* **Weight is never asked.** The Miler verifies it at pickup, which is when the
price settles.
* **Caps** come from `BookingLimits` (backend-served, defaults 20 packages /
5 destinations per pickup). Nothing in the UI hardcodes them.
* **Cancellation** is whole-pickup only, and only while
`DoormileApi.isCancellable(stage)` allows it.
A customer sending one package to one district sees exactly what they saw
before: pick a place, tap Next. The multi-destination machinery appears only
when they ask for it.
Stages shown to the customer (`JourneyStage`; raw backend keys never reach a
screen):
```
Pickup booked → Miler assigned → Miler on the way → Miler arrived →
Package picked up → Order created → In transit → Out for delivery → Delivered
```
**Cancellation** is offered only while `DoormileApi.isCancellable(stage)` is
true — through *Miler arrived*. Once the Miler has custody the footer becomes a
support action instead.
## Maps and location
Both maps are real. `flutter_map` renders OpenStreetMap data through CARTO's
basemaps — no API key, no billing, no per-request cost to develop against.
**No widget knows a tile URL.** `lib/data/map_config.dart` is the only place a
template, a subdomain list, an attribution string or a map API key exists;
`lib/ui/widgets/map_tiles.dart` turns that into a layer. Changing provider is a
build flag, never a map-screen edit — and a test fails the build if a URL ever
reappears under `lib/ui/`.
* **Pickup** (`DmMapPanel`) — the pin is welded to the centre of the map and the
map moves under it. When it settles, the coordinates under the pin are
reverse-geocoded and the address appears in the box below, inside the same
card. Drag, and the address follows.
* **The customer's own position** is a blue dot with an accuracy halo drawn at
true map scale, so it shrinks as they zoom in. It is a real coordinate, not a
screen overlay: dragging moves the crimson pickup pin and leaves the dot
where the customer actually is, which is how they judge how far they have
moved the pin from themselves. No fix means no dot — a dot in the wrong place
is worse than none.
* **Route** (`DmRouteMap`) — pickup and destination hub as real markers joined
by the transit arc, with the Miler's live position along it. Non-interactive
on purpose: it summarises a booking and must never steal a scroll gesture.
* **Position** (`LocationService`) — the only place `geolocator` is touched.
Every platform call is bounded by a timeout and every failure comes back as a
typed `LocationDenial`, so a refused permission or a wedged plugin can never
freeze the booking flow. It falls back to the service-area centre and says
why.
### Choosing a tile provider
CARTO is the development default and is *not* assumed to be the production
contract. Everything is set at build time:
```bash
# CARTO with a proper API key — the likely production step
flutter build appbundle --dart-define=DM_MAP_KEY=$CARTO_API_KEY
# a different vendor
flutter run --dart-define=DM_MAP_PROVIDER=maptiler --dart-define=DM_MAP_KEY=…
flutter run --dart-define=DM_MAP_PROVIDER=stadia --dart-define=DM_MAP_KEY=…
# self-hosted or anything else
flutter run \
--dart-define=DM_MAP_PROVIDER=custom \
--dart-define=DM_MAP_URL=https://tiles.doormile.in/streets/{z}/{x}/{y}.png \
--dart-define=DM_MAP_URL_MUTED=https://tiles.doormile.in/light/{z}/{x}/{y}.png \
--dart-define=DM_MAP_ATTRIBUTION='© Doormile · © OpenStreetMap contributors'
```
| Define | Effect |
| --- | --- |
| `DM_MAP_PROVIDER` | `carto` (default) · `osm` · `maptiler` · `stadia` · `custom` |
| `DM_MAP_KEY` | Appended as the provider's key parameter (`api_key`, `key`) |
| `DM_MAP_URL` / `DM_MAP_URL_MUTED` | Templates for `custom` |
| `DM_MAP_SUBDOMAINS` | Comma-separated `{s}` shards |
| `DM_MAP_ATTRIBUTION` / `_URL` | Credit line and licence link |
| `DM_MAP_MAX_ZOOM` | Deepest native zoom the provider serves |
| `DM_APP_VERSION` | Goes into the `User-Agent` |
A provider that needs a key but was given none falls back to CARTO with a
`warning` on the config rather than rendering a blank map. Every tile request
carries `User-Agent: Doormile/<version> (in.doormile.customer)`, so the provider
can attribute and rate-limit our traffic properly. `keepBuffer`/`panBuffer` stay
at flutter_map's defaults — the app fetches the tiles it is about to draw and
nothing more. There is no bulk prefetch or offline tile scraping, by design.
The credit line is rendered on **every** map, its text taken from whichever
provider is configured, so it stays correct after a swap.
`ACCESS_FINE_LOCATION` / `ACCESS_COARSE_LOCATION` are declared on Android and
`NSLocationWhenInUseUsageDescription` on iOS; GPS hardware is marked optional so
Play does not filter the app off devices without it.
## Running it
```bash
flutter pub get
flutter run # any connected device or simulator
flutter test # 79 tests covering the whole flow
```
`flutter run` talks to `https://api.doormile.com/api/v1`. Point it somewhere
else with a define:
```bash
flutter run --dart-define=DM_API_BASE=https://<staging-host>/api/v1
```
### Signing in for development
A shipping build has **one** API implementation, `LiveDoormileApi`, and it talks
to a server. Nothing invented can reach a customer.
But the real backend has no SMS gateway yet, so the OTP never arrives and you
cannot sign in against it. Two dev-only ways in, both `!kReleaseMode` — no define
can put either in a release build, and the Account screen prints the mode it is
in:
**Offline dev data** — the whole app, no server, any 4-digit code signs in:
```bash
flutter run --dart-define=DM_MOCK=true
# login screen → 9876543210 → 1234 → in.
# add --dart-define=DM_DEV_LOGIN=true to skip the login screen entirely.
```
This swaps in `DevDoormileApi`: in-memory serviceability, slots, fare and
bookings, so you can walk signup → book → track without a backend. **A booking
made here stays on the device — it reaches no server and no admin console.** The
Account screen reads `DEV DATA (offline)`.
**Real token** — talk to the live server, skip only the OTP round trip. Not a
bypass: the server authorises every request it signs, and a revoked token signs
the build straight back out:
```bash
flutter run --dart-define=DM_DEV_TOKEN=eyJ... \
--dart-define=DM_DEV_REFRESH_TOKEN=...
```
### Walking a booking through its stages
Against dev data, the tracking screen's stepper walks the in-memory booking.
Against a non-production backend it drives the server's own QA helper
(`POST /customer/ops/bookings/{ref}/stage`) — each tap posts and re-reads, so
what appears is the stage the **server** recorded:
```bash
flutter run --dart-define=DM_API_BASE=https://<staging-host>/api/v1 \
--dart-define=DM_ALLOW_STAGE_OVERRIDE=true
```
The backend gates it too, with `CX_ALLOW_STAGE_OVERRIDE`. The app refuses to
send it on production regardless.
### Walking a booking through its stages
On a non-production backend, the tracking screen can offer a stepper that drives
the server's own QA helper (`POST /customer/ops/bookings/{ref}/stage`). Each tap
posts and then re-reads the booking, so what appears is the stage the **server**
recorded:
```bash
flutter run --dart-define=DM_API_BASE=https://<staging-host>/api/v1 \
--dart-define=DM_ALLOW_STAGE_OVERRIDE=true
```
The backend gates it too, with `CX_ALLOW_STAGE_OVERRIDE`. The app refuses to
send it on production regardless.
## The backend
Every screen's data comes from `lib/data/live_doormile_api.dart`, which is a
thin translation between the app's models and the wire contract — the transport
concerns (envelope, error codes, bearer auth and its silent refresh,
idempotency, `ETag`, keyset paging, retries) all live in `api_client.dart`.
`DmAsyncList` wraps every backend-driven list, so loading skeletons, empty
states and retry-on-error come with any new endpoint for free.
`District` carries `lat`/`lng` for its hub, which is what the route map draws
to; without them it simply draws the pickup end.
Still to wire: push notifications (`POST /customer/devices` is implemented but
no SDK produces a token), deep links (`GET /customer/orders/{trackingId}` is
implemented but no intent filter or URL type is registered), and a post-booking
edit screen for `PATCH …/destinations/{i}`. The contract is in
[`docs/API_READINESS.md`](docs/API_READINESS.md).
## Releasing to Google Play
The app is configured for a Play upload: application ID `in.doormile.customer`,
label **Doormile**, portrait only, `INTERNET` declared in the main manifest,
adaptive + monochrome launcher icon, an Android 12+ splash screen, R8 shrinking
on release, and backup/device-transfer disabled.
1. **Create the upload key** (once):
```bash
keytool -genkey -v -keystore android/upload-keystore.jks \
-keyalg RSA -keysize 2048 -validity 10000 -alias upload
```
2. **Point Gradle at it**: copy `android/key.properties.example` to
`android/key.properties` and fill in the four values. Both the keystore and
`key.properties` are git-ignored — never commit them. Without this file the
release build falls back to debug signing so `flutter run --release` keeps
working locally.
3. **Set the version** in `pubspec.yaml` (`version: 1.0.0+1` → `versionName` +
`versionCode`); bump the build number for every upload.
4. **Build the bundle**:
```bash
flutter build appbundle --release
# build/app/outputs/bundle/release/app-release.aab
```
5. **Upload** to Play Console. Listing assets are in `store/`:
`play_store_icon_512.png` and `play_feature_graphic_1024x500.png`. You still
need phone screenshots, a short/full description, a privacy policy URL, the
data-safety form (this build collects nothing — no analytics, no third-party
SDKs) and a content rating.
A JDK 17 is required for Android builds (`flutter doctor` will confirm) — the
one bundled with Android Studio works:
`flutter config --jdk-dir "/Applications/Android Studio.app/Contents/jbr/Contents/Home"`.
## Tests
```bash
flutter test # 18 tests: boot, full user journey, every screen renders clean
```
The test suite is the only place a fake backend exists:
`test/support/fake_doormile_api.dart`, injected through
`DoormileApi.overrideInstance`. It owns its bookings and its stage machine
exactly as the server does — no test reaches into `AppState` to plant one.
`test/live_api_wire_test.dart` checks what the app actually puts on the wire,
field by field, against the customer API document.
`test/booking_flow_test.dart` drives the app end to end: signing in through the
OTP screen; dragging the pickup map and watching the address re-resolve; a
refused location falling back without blocking the booking; booking one package to one district with every optional field
skipped; four packages to one place; three destinations with mixed counts and
the review total; the package cap and destination cap; state→district
serviceability filtering; packages staying together until collection and then
splitting into their own orders; cancelling; a delivered order's receipt; and
the empty/error/retry service-area states.

View File

@@ -9,6 +9,13 @@
# packages, and plugins designed to encourage good coding practices.
include: package:flutter_lints/flutter.yaml
analyzer:
exclude:
- build/**
- android/**
- ios/**
- web/**
linter:
# The lint rules applied to this project can be customized in the
# section below to disable rules from the `package:flutter_lints/flutter.yaml`

View File

@@ -1,22 +1,25 @@
import java.util.Properties
import java.io.FileInputStream
val keystorePropertiesFile = rootProject.file("key.properties")
val keystoreProperties = Properties()
if (keystorePropertiesFile.exists()) {
keystoreProperties.load(FileInputStream(keystorePropertiesFile))
}
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
// The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins.
id("dev.flutter.flutter-gradle-plugin")
id("com.google.gms.google-services")
}
// Upload-key credentials live outside version control. Copy
// `android/key.properties.example` to `android/key.properties` and fill it in
// before building a release bundle; without it we fall back to debug signing so
// `flutter run --release` still works on a developer machine.
val keystoreProperties = Properties().apply {
val file = rootProject.file("key.properties")
if (file.exists()) {
file.inputStream().use { load(it) }
}
}
val hasUploadKey = keystoreProperties.getProperty("storeFile") != null
android {
namespace = "com.doormile.customer"
namespace = "in.doormile.customer"
compileSdk = flutter.compileSdkVersion
ndkVersion = flutter.ndkVersion
@@ -26,33 +29,46 @@ android {
}
defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId = "com.doormile.customer"
// 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
applicationId = "in.doormile.customer"
minSdk = 24
targetSdk = flutter.targetSdkVersion
versionCode = flutter.versionCode
versionName = flutter.versionName
}
signingConfigs {
create("release") {
keyAlias = keystoreProperties["keyAlias"] as String?
keyPassword = keystoreProperties["keyPassword"] as String?
storeFile = keystoreProperties["storeFile"]?.let { file(it as String) }
storePassword = keystoreProperties["storePassword"] as String?
if (hasUploadKey) {
create("release") {
keyAlias = keystoreProperties.getProperty("keyAlias")
keyPassword = keystoreProperties.getProperty("keyPassword")
storeFile = rootProject.file(keystoreProperties.getProperty("storeFile"))
storePassword = keystoreProperties.getProperty("storePassword")
}
}
}
buildTypes {
release {
signingConfig = if (keystorePropertiesFile.exists()) {
signingConfig = if (hasUploadKey) {
signingConfigs.getByName("release")
} else {
signingConfigs.getByName("debug")
}
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro",
)
}
debug {
applicationIdSuffix = ".debug"
versionNameSuffix = "-debug"
}
}
bundle {
language { enableSplit = false }
}
}
@@ -65,10 +81,3 @@ kotlin {
flutter {
source = "../.."
}
dependencies {
// Import the Firebase BoM
implementation(platform("com.google.firebase:firebase-bom:34.14.1"))
// Add the dependencies for Firebase products you want to use
implementation("com.google.firebase:firebase-analytics")
}

View File

@@ -1,29 +0,0 @@
{
"project_info": {
"project_number": "923472686173",
"project_id": "doormilecustomer",
"storage_bucket": "doormilecustomer.firebasestorage.app"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:923472686173:android:175b38552da45f2d4ef1b4",
"android_client_info": {
"package_name": "com.doormile.customer"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": "AIzaSyAoxaF4fmYXU372qZkYAo7WftFqgiEg_7k"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": []
}
}
}
],
"configuration_version": "1"
}

View File

@@ -1,24 +1,3 @@
# Flutter Wrapper
-keep class io.flutter.app.** { *; }
-keep class io.flutter.plugin.** { *; }
-keep class io.flutter.util.** { *; }
-keep class io.flutter.view.** { *; }
-keep class io.flutter.** { *; }
-keep class io.flutter.plugins.** { *; }
# Firebase
-keep class com.google.firebase.** { *; }
# Flutter Deferred Components (Play Core)
-dontwarn com.google.android.play.core.**
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in C:\sdk\tools\proguard\proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# Flutter's own rules are applied by the Flutter Gradle plugin. Keep this file
# for app-specific rules — e.g. models used with reflection by a JSON codec.
-keep class in.doormile.customer.** { *; }

View File

@@ -1,7 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<!-- 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"/>
<!-- DEBUG ONLY. Android 9+ blocks cleartext HTTP by default, which makes a
local backend (http://<dev-machine-ip>:8080) unreachable from a real
handset. This override lives in the debug manifest, so a release build
is unaffected and still refuses cleartext.
-->
<application
android:usesCleartextTraffic="true"
tools:replace="android:usesCleartextTraffic" />
</manifest>

View File

@@ -1,13 +1,29 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<!-- The app talks to the Doormile backend for serviceability, slots and
bookings. Declared in the main manifest so release builds have it too. -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- Drops the pickup pin at the customer's door. Both are optional at
runtime: refusing either leaves the map on the service-area centre and
the address can still be searched. -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<!-- The app is useful without GPS hardware, so Play should not filter it
out for devices that lack it. -->
<uses-feature
android:name="android.hardware.location.gps"
android:required="false" />
<application
android:label="doormile"
android:label="Doormile"
android:name="${applicationName}"
android:icon="@mipmap/launcher_icon">
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:enableOnBackInvokedCallback="true"
android:allowBackup="false"
android:fullBackupContent="false"
android:dataExtractionRules="@xml/data_extraction_rules">
<activity
android:name=".MainActivity"
android:exported="true"
@@ -16,6 +32,7 @@
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
@@ -30,10 +47,6 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Google Maps API key — replace with your key from Google Cloud Console -->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="AIzaSyBhkGfnq27sN0wV5y_S-M2KojpFTk_by-Q" />
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
@@ -50,8 +63,5 @@
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</intent>
<intent>
<action android:name="android.intent.action.DIAL" />
</intent>
</queries>
</manifest>

View File

@@ -1,4 +1,4 @@
package com.doormile.customer
package `in`.doormile.customer
import io.flutter.embedding.android.FlutterActivity

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

View File

@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Shown from process start until the first Flutter frame. Matches the white
Login screen so the handover is invisible. -->
<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>
<item android:drawable="@color/dm_surface" />
<item
android:gravity="center"
android:width="120dp"
android:height="120dp"
android:drawable="@drawable/dm_mark_brand" />
</layer-list>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 728 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 B

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Doormile mark in brand maroon, for the launch screen.
Art is authored on a 24x24 grid and scaled into the 66dp safe zone. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="2.2" android:scaleY="2.2"
android:translateX="27.6" android:translateY="27.6">
<path
android:pathData="M3.6,9.2 L12,4 L20.4,9.2 L20.4,20 L3.6,20 Z"
android:strokeColor="#960019"
android:strokeWidth="1.8"
android:strokeLineJoin="round"
android:strokeLineCap="round" />
<path
android:pathData="M9.6,20 L9.6,13.4 L14.4,13.4 L14.4,20"
android:strokeColor="#960019"
android:strokeWidth="1.8"
android:strokeLineJoin="round"
android:strokeLineCap="round" />
</group>
</vector>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Doormile mark in white, for the adaptive-icon foreground.
Art is authored on a 24x24 grid and scaled into the 66dp safe zone. -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<group android:scaleX="2.2" android:scaleY="2.2"
android:translateX="27.6" android:translateY="27.6">
<path
android:pathData="M3.6,9.2 L12,4 L20.4,9.2 L20.4,20 L3.6,20 Z"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.8"
android:strokeLineJoin="round"
android:strokeLineCap="round" />
<path
android:pathData="M9.6,20 L9.6,13.4 L14.4,13.4 L14.4,20"
android:strokeColor="#FFFFFF"
android:strokeWidth="1.8"
android:strokeLineJoin="round"
android:strokeLineCap="round" />
</group>
</vector>

View File

@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Shown from process start until the first Flutter frame. Matches the white
Login screen so the handover is invisible. -->
<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>
<item android:drawable="@color/dm_surface" />
<item
android:gravity="center"
android:width="120dp"
android:height="120dp"
android:drawable="@drawable/dm_mark_brand" />
</layer-list>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/dm_brand" />
<foreground android:drawable="@drawable/dm_mark_white" />
<monochrome android:drawable="@drawable/dm_mark_white" />
</adaptive-icon>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/dm_brand" />
<foreground android:drawable="@drawable/dm_mark_white" />
<monochrome android:drawable="@drawable/dm_mark_white" />
</adaptive-icon>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 544 B

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 442 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

View File

@@ -1,21 +1,13 @@
<?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">#FFFFFF</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
<!-- Android 12+ uses the platform splash screen API. -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowSplashScreenBackground">@color/dm_surface</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/dm_mark_brand</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/dm_surface</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 name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">@color/dm_surface</item>
</style>
</resources>

View File

@@ -1,22 +1,11 @@
<?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 -->
<!-- Theme applied to the Android Window while the process starts. -->
<style name="LaunchTheme" parent="@android:style/Theme.Light.NoTitleBar">
<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>
<!-- Theme applied once Flutter takes over drawing. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">@color/dm_surface</item>
</style>
</resources>

View File

@@ -1,21 +1,13 @@
<?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 -->
<!-- Android 12+ uses the platform splash screen API. -->
<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">#FFFFFF</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/android12splash</item>
<item name="android:windowBackground">@drawable/launch_background</item>
<item name="android:windowSplashScreenBackground">@color/dm_surface</item>
<item name="android:windowSplashScreenAnimatedIcon">@drawable/dm_mark_brand</item>
<item name="android:windowSplashScreenIconBackgroundColor">@color/dm_surface</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>
<item name="android:windowBackground">@color/dm_surface</item>
</style>
</resources>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Doormile brand tokens, mirrored from lib/ui/tokens.dart -->
<color name="dm_brand">#960019</color>
<color name="dm_surface">#FFFFFF</color>
</resources>

View File

@@ -1,22 +1,11 @@
<?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 -->
<!-- Theme applied to the Android Window while the process starts. -->
<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. -->
<!-- Theme applied once Flutter takes over drawing. -->
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item>
<item name="android:windowBackground">@color/dm_surface</item>
</style>
</resources>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Nothing in this app should be backed up or transferred between devices:
the session is re-established by signing in. -->
<data-extraction-rules>
<cloud-backup>
<exclude domain="root" />
<exclude domain="file" />
<exclude domain="database" />
<exclude domain="sharedpref" />
</cloud-backup>
<device-transfer>
<exclude domain="root" />
<exclude domain="file" />
<exclude domain="database" />
<exclude domain="sharedpref" />
</device-transfer>
</data-extraction-rules>

View File

@@ -1,10 +1,6 @@
org.gradle.jvmargs=-Xmx2560m -XX:MaxMetaspaceSize=1024m -Dfile.encoding=UTF-8
org.gradle.parallel=false
org.gradle.workers.max=1
org.gradle.daemon=false
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
kotlin.incremental=false

View File

@@ -2,4 +2,4 @@ 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
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip

View File

@@ -0,0 +1,6 @@
# Copy to android/key.properties and fill in before `flutter build appbundle`.
# Never commit the real file or the .jks keystore.
storePassword=your-keystore-password
keyPassword=your-key-password
keyAlias=upload
storeFile=upload-keystore.jks

View File

@@ -19,9 +19,8 @@ pluginManagement {
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
id("com.google.gms.google-services") version "4.4.4" apply false
id("com.android.application") version "9.1.0" apply false
id("org.jetbrains.kotlin.android") version "2.4.0" apply false
}
include(":app")

View File

@@ -0,0 +1,93 @@
Copyright 2024 The Geist Project Authors (https://github.com/vercel/geist-font.git)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
https://openfontlicense.org
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

Binary file not shown.

View File

@@ -0,0 +1,93 @@
Copyright 2018 The Manrope Project Authors (https://github.com/sharanda/manrope)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

BIN
assets/fonts/Manrope-VF.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 898 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1015 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 662 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 570 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

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