Skip to content

Monorepo - #9

Merged
antiv merged 17 commits into
mainfrom
monorepo
Sep 19, 2026
Merged

antiv merged 17 commits into
mainfrom
monorepo

Conversation

@antiv

@antiv antiv commented Sep 19, 2026

Copy link
Copy Markdown
Owner

No description provided.

antiv and others added 17 commits August 28, 2026 17:55
Flutter app (Android + iOS) for field surveys of reptiles and amphibians:
record a transect on a Google Map, drop a point per finding, and attach one
observation record per animal — species, locality, development stage, sex,
counts, habitat and more. Surveys export as CSV or KML; the whole database
backs up to JSON.

The record fields and the 50-species catalog follow the survey data dictionary
in "Vrste za aplikaciju.xlsx". The app started as a copy of Bird Tracker
(rs.antonijevic.bird_tracker) and ships as a separate app; that history stays
in the bird_tracker repository.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat: add backup/restore functionality with media assets and integrat…
…tion, Maps NaN camera)

Herp Tracker was forked from Bird Tracker with this code intact, so both
production crashes reported on the Play Console for bird_tracker#8 are
reachable here too — the fixes are ported as-is, with the herp-specific
export code (altitude/accuracy columns, the KML balloon rows) left alone.

Location: every path that starts updates now goes through
ensureLocationPermission() — the location plugin's changeSettings started
native updates without checking, and without ACCESS_FINE_LOCATION Android
answered with a SecurityException in a GMS callback that nothing in Dart could
catch. The gate is re-run every time (an "Only this time" grant expires), the
startup permission flow and the "unfinished transect" dialog are sequenced, and
a double tap on Start no longer opens two transect rows or leaks a subscription.
Upgraded `location` 8.0.1 -> 10.0.2, which also turns that SecurityException
into a PERMISSION_DENIED error. Android 12+ "Approximate location" is refused
with a FINE-only request over the MainActivity channel, which is the only
request that shows the upgrade-to-precise dialog.

Map: the camera follows the user only while the app is resumed; updates kept
arriving from the foreground service with the screen off and animating the
paused MapView every second fed the renderer NaN targets. The
_HomePageState.controller field was never assigned, so following did not work
at all before. Coordinates are validated on every way in (double.parse('NaN')
succeeds), KML routes split on any whitespace.

Background mode is now tied to recording — enabled in _startListener, disabled
in _stopListener — instead of on every launch and my-location tap, which left
the Android foreground service tracking with no transect in progress.

Also: iOS deployment target 15.0, openSettings works on iOS, stale Isar
proguard rule removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YH1jd4b3FFvSrntnsXfjCo
…e again

easy_localization walks a key as a path through the JSON, splitting on '.', so
'species.Pelophylax kl. esculentus' was looked up as
species -> "Pelophylax kl" -> " esculentus", found nothing, fell back to a flat
top-level key that does not exist either, and came back as the raw key. The
edible frog therefore showed up as "species.Pelophylax kl. esculentus" in the
autocomplete list — the only one of the 50 catalog names carrying an
abbreviation.

The translation key loses the dots; kSpecies keeps the real Latin name, which
is what lands in the database, the CSV and the KML payload, so nothing already
recorded or exported changes. Both call sites go through speciesLabel() rather
than interpolating the name into the key by hand, and a test asserts every
catalog entry resolves, so the next name that needs the same treatment fails
loudly instead of silently rendering as a key.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YH1jd4b3FFvSrntnsXfjCo
Port the Bird Tracker crash fixes, and fix the one species name with a dot in it
First step of the monorepo: the app becomes one workspace member so a
shared tracker_core package can sit next to it. No code changes — every
tracked file is a rename, and the root gains only the workspace pubspec,
a generic .gitignore and a README.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…y preserved)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

git-subtree-dir: apps/herp_tracker
git-subtree-mainline: b906626
git-subtree-split: 50b22f9
- apps/herp_tracker joins the pub workspace (resolution: workspace); the
  per-app lock files give way to one root pubspec.lock
- tool/check_all.sh runs analyze + test for every package and app; CI
  runs the same script on every PR
- the two `(_, __)` lint infos that already failed `flutter analyze` in
  both apps use Dart's wildcard `_` instead

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Everything the tracker apps share moves into packages/tracker_core: the
map screen, GPS transect recording, photos, sembast storage, zip backup,
CSV/KML/KMZ export and import, the drawer and the record form shell. An
app supplies a TrackerConfig — branding plus its record type, species
catalog, export columns and form fields — and calls runTrackerApp.

- TrackerRecord is what the core knows about a record: species, photos,
  toJson, a summary and a list subtitle. Placemark holds List<TrackerRecord>
  under the same 'species' JSON key every stored transect and KML uses.
- The record form is split: RecordFormShell owns the species field, the
  photo strip with its file-deletion rules and the buttons; the app's
  RecordFieldsState owns its own fields and builds the record on save.
- Herp Tracker's export improvements come along for every app: altitude
  and accuracy on the point, RFC 4180 CSV cells, the record columns
  driving both the CSV and one <Data> row per field in the KML balloon.
- The KML payload is read by local name whatever namespace wrote it, so a
  survey exported by one tracker imports into another; the legacy
  description fallback is an app hook (bird has one, herp never needed it).
- Translations merge: core UI strings first, the app's file on top;
  strings naming the app take it as {app}.
- Bird's CSV keeps its columns and English headers, gains the transect,
  point and photo columns and RFC 4180 quoting; its test pins that.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The duplicated infrastructure goes; what stays is the herp domain —
HerpRecord, the field options and catalog, HerpFormFields, and a
TrackerConfig with the export columns of "Vrste za aplikaciju.xlsx". The
translation files keep only the domain blocks and the strings worded for
reptiles and amphibians; everything else comes from the core.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The atlas-code button and the −/+ count field were written out in full
in each app's form; both now come from the core, along with the DMS
helper the CSV exports use.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The white stork nest census from the old `rode` branch, rewritten as a
third tracker app: one species (no species field), one nest per point,
the surveyor's details in every export row. Only the domain is written —
NestRecord, the nest position/state options, the form fields and the
census sheet's columns; map, recording, photos, backup, KML/KMZ and the
crash fixes come from the core. The android/ and ios/ shells are Bird
Tracker's with the package, bundle id, name, permission prose and icons
changed.

Also: build_release.sh names the bundle after the app in all three apps,
the root CLAUDE.md carries the shared knowledge and each app's only its
domain.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rmission plugin

The ~100 lines of MainActivity.kt that request ACCESS_BACKGROUND_LOCATION
and ACCESS_FINE_LOCATION one at a time were copied into every app. They
are now one Android plugin package in the workspace (FlutterPlugin +
ActivityAware + RequestPermissionsResultListener), with the Dart wrapper
moved out of tracker_core; every app's MainActivity is the plain
FlutterActivity and the channel name no longer depends on the package.
Android only — the Dart side already short-circuits to success on iOS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…rget to 15.0

feat: add devtools_options.yaml for Dart & Flutter DevTools settings
refactor: enhance SembastService to ensure database readiness before operations
test: add home_page_test to validate UI behavior without active transects
@antiv
antiv merged commit d115116 into main Sep 19, 2026
1 check passed
@antiv
antiv deleted the monorepo branch September 19, 2026 06:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant