Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
25a34aa
chore(deps): upgrade minor/patch dependencies within existing constra…
dougborg Feb 9, 2026
e72d557
chore(android): bump AGP to 8.9.1 and Java compatibility to 17
dougborg Feb 9, 2026
206b3af
chore(deps): move flutter_web_auth_2 and flutter_secure_storage to st…
dougborg Feb 9, 2026
fcf7ff7
Merge pull request #82 from dougborg/chore/deps-minor-patch
stopflock Feb 25, 2026
6c52541
Merge pull request #84 from dougborg/chore/deps-auth-stable
stopflock Feb 25, 2026
dba375c
chore(deps): update app_links and package_info_plus to latest major v…
dougborg Feb 10, 2026
b6bcd23
chore(android): bump Dart SDK floor, desugar_jdk_libs, and fix Kotlin…
dougborg Feb 10, 2026
90a806a
chore(deps): upgrade minor/patch dependencies within existing constra…
dougborg Feb 25, 2026
abd8682
Build with iOS 26 SDK to meet App Store deadline
dougborg Feb 14, 2026
e1cca2f
Merge pull request #85 from dougborg/chore/deps-applinks-packageinfo
stopflock Feb 25, 2026
dc817e5
Merge pull request #115 from dougborg/chore/ios26-sdk
stopflock Feb 25, 2026
30f546b
Update pubspec.yaml
stopflock Feb 26, 2026
b56e932
Update changelog.json
stopflock Feb 26, 2026
4941c27
don't require trailing new line in build.keys.conf
Feb 15, 2026
bc671c4
Fix phantom FOVs, reorderable profiles
stopflock Mar 2, 2026
57df8e8
fix tests for profile order, add correct migration
stopflock Mar 2, 2026
aeb1903
Merge pull request #135 from subfloor201/chore/update-do_builds.sh
stopflock Mar 3, 2026
5728b4f
Force simulate mode when OSM OAuth secrets are missing
dougborg Mar 7, 2026
be446fb
Merge pull request #140 from FoggedLens/fix/force-simulate-without-se…
stopflock Mar 7, 2026
2d92214
Add offline-first tile system with per-provider caching and error retry
dougborg Mar 3, 2026
f3f40f3
Allow OSM offline downloads, disable button for restricted providers
dougborg Mar 4, 2026
91e5177
Detect config drift in cached tile providers and replace stale instances
dougborg Mar 4, 2026
122b303
Merge pull request #132 from dougborg/fix/tile-retry-on-error
stopflock Mar 7, 2026
de65cec
bump ver
stopflock Mar 7, 2026
f719e5c
Add Gatling load tests for overpass.deflock.org
dougborg Mar 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions .github/workflows/load-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Manual-trigger workflow to run Gatling load tests against overpass.deflock.org.
#
# Trigger from the Actions tab → "Load Test" → "Run workflow".
# The HTML report is uploaded as a downloadable artifact (retained 30 days).
#
# Only one load test can run at a time (concurrency group prevents overlapping
# runs from skewing results or overwhelming the Overpass instance).

name: Load Test

on:
workflow_dispatch:

concurrency:
group: load-test
cancel-in-progress: true

jobs:
load-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5

- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21

# Caches Gradle wrapper and dependencies between runs
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Run Gatling load test
working-directory: load-tests
run: ./gradlew gatlingRun

- name: Upload Gatling report
if: always()
uses: actions/upload-artifact@v4
with:
name: gatling-report
path: load-tests/build/reports/gatling/
retention-days: 30
4 changes: 2 additions & 2 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ jobs:
build-ios:
name: Build iOS
needs: get-version
runs-on: macos-latest
runs-on: macos-26
steps:
- name: Checkout repository
uses: actions/checkout@v5
Expand Down Expand Up @@ -290,7 +290,7 @@ jobs:
upload-to-stores:
name: Upload to App Stores
needs: [get-version, build-android-aab, build-ios]
runs-on: macos-latest # Need macOS for iOS uploads
runs-on: macos-26 # Need macOS for iOS uploads
if: needs.get-version.outputs.should_upload_to_stores == 'true'
steps:
- name: Download AAB artifact for Google Play
Expand Down
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,13 @@ fuchsia/build/
web/build/

# ───────────────────────────────
# IDE / Editor Settings
# IDE / Editor / AI Tool Settings
# ───────────────────────────────
.idea/
.idea/**/workspace.xml
.idea/**/tasks.xml
.vscode/
.claude/settings.local.json
# Swap files
*.swp
*.swo
Expand All @@ -102,4 +103,4 @@ build_keys.conf
linux/
macos/
web/
windows/
windows/
18 changes: 8 additions & 10 deletions android/app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,28 +17,27 @@ if (keystorePropertiesFile.exists()) {
android {
namespace = "me.deflock.deflockapp"

// Matches current stable Flutter (compileSdk 34 as of July 2025)
compileSdk = 36

// NDK only needed if you build native plugins; keep your pinned version
ndkVersion = "27.0.12077973"

compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
isCoreLibraryDesugaringEnabled = true
}
kotlinOptions {
jvmTarget = JavaVersion.VERSION_11.toString()
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}

defaultConfig {
// Application ID (package name)
applicationId = "me.deflock.deflockapp"

// ────────────────────────────────────────────────────────────
// oauth2_client 4.x & flutter_web_auth_2 5.x require minSdk 23
// ────────────────────────────────────────────────────────────
// oauth2_client 4.x & flutter_web_auth_2 5.x require minSdk 23
minSdk = maxOf(flutter.minSdkVersion, 23)
targetSdk = 36

Expand Down Expand Up @@ -76,6 +75,5 @@ flutter {
}

dependencies {
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
}

2 changes: 1 addition & 1 deletion android/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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-8.12-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-all.zip
4 changes: 2 additions & 2 deletions android/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ pluginManagement {

plugins {
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
id("com.android.application") version "8.7.3" apply false
id("org.jetbrains.kotlin.android") version "2.1.0" apply false
id("com.android.application") version "8.11.1" apply false
id("org.jetbrains.kotlin.android") version "2.2.20" apply false
}

include(":app")
18 changes: 17 additions & 1 deletion assets/changelog.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,23 @@
{
"2.9.0": {
"content": [
"• Caching, tile retries, offline areas, now working properly. Map imagery should load correctly."
]
},
"2.8.1": {
"content": [
"• Fixed bug where the \"existing tags\" profile would incorrectly add default FOV ranges during submission",
"• Added drag handles so profiles can be reordered to customize dropdown order when submitting"
]
},
"2.8.0": {
"content": [
"• Update dependencies and build chain tools; no code changes"
]
},
"2.7.2": {
"content": [
"• Now following OSM UserAgent guidelines."
"• Now following OSM UserAgent guidelines"
]
},
"2.7.1": {
Expand Down
2 changes: 1 addition & 1 deletion do_builds.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ read_from_file() {
echo "$v"
return 0
fi
done < "$file"
done < <(cat "$file"; echo)

return 1
}
Expand Down
4 changes: 4 additions & 0 deletions lib/app_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,10 @@ class AppState extends ChangeNotifier {
_profileState.addOrUpdateProfile(p);
}

void reorderProfiles(int oldIndex, int newIndex) {
_profileState.reorderProfiles(oldIndex, newIndex);
}

void deleteProfile(NodeProfile p) {
_profileState.deleteProfile(p);
}
Expand Down
16 changes: 10 additions & 6 deletions lib/keys.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
// OpenStreetMap OAuth client IDs for this app.
// These must be provided via --dart-define at build time.

/// Whether OSM OAuth secrets were provided at build time.
/// When false, the app should force simulate mode.
bool get kHasOsmSecrets {
const prod = String.fromEnvironment('OSM_PROD_CLIENTID');
const sandbox = String.fromEnvironment('OSM_SANDBOX_CLIENTID');
return prod.isNotEmpty && sandbox.isNotEmpty;
}

String get kOsmProdClientId {
const fromBuild = String.fromEnvironment('OSM_PROD_CLIENTID');
if (fromBuild.isNotEmpty) return fromBuild;

throw Exception('OSM_PROD_CLIENTID not configured. Use --dart-define=OSM_PROD_CLIENTID=your_id');
return fromBuild;
}

String get kOsmSandboxClientId {
const fromBuild = String.fromEnvironment('OSM_SANDBOX_CLIENTID');
if (fromBuild.isNotEmpty) return fromBuild;

throw Exception('OSM_SANDBOX_CLIENTID not configured. Use --dart-define=OSM_SANDBOX_CLIENTID=your_id');
return fromBuild;
}
20 changes: 13 additions & 7 deletions lib/localizations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,10 @@
"offlineModeWarning": "Downloads im Offline-Modus deaktiviert. Deaktivieren Sie den Offline-Modus, um neue Bereiche herunterzuladen.",
"areaTooBigMessage": "Zoomen Sie auf mindestens Stufe {} heran, um Offline-Bereiche herunterzuladen. Downloads großer Gebiete können die App zum Absturz bringen.",
"downloadStarted": "Download gestartet! Lade Kacheln und Knoten...",
"downloadFailed": "Download konnte nicht gestartet werden: {}"
"downloadFailed": "Download konnte nicht gestartet werden: {}",
"offlineNotPermitted": "Der {}-Server erlaubt keine Offline-Downloads. Wechseln Sie zu einem Kachelanbieter, der Offline-Nutzung unterstützt (z. B. Bing Maps, Mapbox oder ein selbst gehosteter Kachelserver).",
"currentTileProvider": "aktuelle Kachel",
"noTileProviderSelected": "Kein Kachelanbieter ausgewählt. Bitte wählen Sie einen Kartenstil, bevor Sie einen Offlinebereich herunterladen."
},
"downloadStarted": {
"title": "Download gestartet",
Expand Down Expand Up @@ -292,13 +295,16 @@
"addProfileChoiceMessage": "Wie möchten Sie ein Profil hinzufügen?",
"createCustomProfile": "Benutzerdefiniertes Profil Erstellen",
"createCustomProfileDescription": "Erstellen Sie ein Profil von Grund auf mit Ihren eigenen Tags",
"importFromWebsite": "Von Webseite Importieren",
"importFromWebsite": "Von Webseite Importieren",
"importFromWebsiteDescription": "Profile von deflock.me/identify durchsuchen und importieren"
},
"mapTiles": {
"title": "Karten-Kacheln",
"manageProviders": "Anbieter Verwalten",
"attribution": "Karten-Zuschreibung"
"attribution": "Karten-Zuschreibung",
"mapAttribution": "Kartenquelle: {}",
"couldNotOpenLink": "Link konnte nicht geöffnet werden",
"openLicense": "Lizenz öffnen: {}"
},
"profileEditor": {
"viewProfile": "Profil Anzeigen",
Expand All @@ -325,7 +331,7 @@
},
"operatorProfileEditor": {
"newOperatorProfile": "Neues Betreiber-Profil",
"editOperatorProfile": "Betreiber-Profil Bearbeiten",
"editOperatorProfile": "Betreiber-Profil Bearbeiten",
"operatorName": "Betreiber-Name",
"operatorNameHint": "z.B. Polizei Austin",
"operatorNameRequired": "Betreiber-Name ist erforderlich",
Expand Down Expand Up @@ -520,15 +526,15 @@
"updateFailed": "Aktualisierung der verdächtigen Standorte fehlgeschlagen",
"neverFetched": "Nie abgerufen",
"daysAgo": "vor {} Tagen",
"hoursAgo": "vor {} Stunden",
"hoursAgo": "vor {} Stunden",
"minutesAgo": "vor {} Minuten",
"justNow": "Gerade eben"
},
"suspectedLocation": {
"title": "Verdächtiger Standort #{}",
"ticketNo": "Ticket-Nr.",
"address": "Adresse",
"street": "Straße",
"street": "Straße",
"city": "Stadt",
"state": "Bundesland",
"intersectingStreet": "Kreuzende Straße",
Expand All @@ -552,4 +558,4 @@
"metricDescription": "Metrisch (km, m)",
"imperialDescription": "Imperial (mi, ft)"
}
}
}
24 changes: 15 additions & 9 deletions lib/localizations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"submitAnyway": "Submit Anyway",
"nodeType": {
"alpr": "ALPR/ANPR Camera",
"publicCamera": "Public Surveillance Camera",
"publicCamera": "Public Surveillance Camera",
"camera": "Surveillance Camera",
"amenity": "{}",
"device": "{} Device",
Expand Down Expand Up @@ -181,7 +181,10 @@
"offlineModeWarning": "Downloads disabled while in offline mode. Disable offline mode to download new areas.",
"areaTooBigMessage": "Zoom in to at least level {} to download offline areas. Large area downloads can cause the app to become unresponsive.",
"downloadStarted": "Download started! Fetching tiles and nodes...",
"downloadFailed": "Failed to start download: {}"
"downloadFailed": "Failed to start download: {}",
"offlineNotPermitted": "The {} server does not permit offline downloads. Switch to a tile provider that allows offline use (e.g., Bing Maps, Mapbox, or a self-hosted tile server).",
"currentTileProvider": "current tile",
"noTileProviderSelected": "No tile provider is selected. Please select a map style before downloading an offline area."
},
"downloadStarted": {
"title": "Download Started",
Expand Down Expand Up @@ -329,13 +332,16 @@
"addProfileChoiceMessage": "How would you like to add a profile?",
"createCustomProfile": "Create Custom Profile",
"createCustomProfileDescription": "Build a profile from scratch with your own tags",
"importFromWebsite": "Import from Website",
"importFromWebsite": "Import from Website",
"importFromWebsiteDescription": "Browse and import profiles from deflock.me/identify"
},
"mapTiles": {
"title": "Map Tiles",
"manageProviders": "Manage Providers",
"attribution": "Map Attribution"
"attribution": "Map Attribution",
"mapAttribution": "Map attribution: {}",
"couldNotOpenLink": "Could not open link",
"openLicense": "Open license: {}"
},
"profileEditor": {
"viewProfile": "View Profile",
Expand All @@ -362,7 +368,7 @@
},
"operatorProfileEditor": {
"newOperatorProfile": "New Operator Profile",
"editOperatorProfile": "Edit Operator Profile",
"editOperatorProfile": "Edit Operator Profile",
"operatorName": "Operator name",
"operatorNameHint": "e.g., Austin Police Department",
"operatorNameRequired": "Operator name is required",
Expand Down Expand Up @@ -443,7 +449,7 @@
"mobileEditors": "Mobile Editors",
"iDEditor": "iD Editor",
"iDEditorSubtitle": "Full-featured web editor - always works",
"rapidEditor": "RapiD Editor",
"rapidEditor": "RapiD Editor",
"rapidEditorSubtitle": "AI-assisted editing with Facebook data",
"vespucci": "Vespucci",
"vespucciSubtitle": "Advanced Android OSM editor",
Expand Down Expand Up @@ -520,15 +526,15 @@
"updateFailed": "Failed to update suspected locations",
"neverFetched": "Never fetched",
"daysAgo": "{} days ago",
"hoursAgo": "{} hours ago",
"hoursAgo": "{} hours ago",
"minutesAgo": "{} minutes ago",
"justNow": "Just now"
},
"suspectedLocation": {
"title": "Suspected Location #{}",
"ticketNo": "Ticket No",
"address": "Address",
"street": "Street",
"street": "Street",
"city": "City",
"state": "State",
"intersectingStreet": "Intersecting Street",
Expand All @@ -552,4 +558,4 @@
"metricDescription": "Metric (km, m)",
"imperialDescription": "Imperial (mi, ft)"
}
}
}
Loading