Code Navigation
The directory structure has been devised many years ago when the author has been learning Flutter development, so it's not the most effective, but it works. This page walks you through it, so you understand what goes where.
Root
android
: Android build files go here. Of most importance areapp/build.gradle
andapp/src/main/AndroidManifest.xml
. If you don't know why, please stay away from those.- Built apk and aab files are put into
android/app/prod/release
. - Note that published apk's on Github use Ilya's personal certificate, while all beta apk's, including those published to Releases, are built with a secret certificate for Actions.
- Built apk and aab files are put into
ios
: iOS build files. In XCode, you openRunner.xcworkspace
.- Built distribution package is put into
build/ios/archive/Runner.xcarchive
. Open it with XCode to upload it to AppStore.
- Built distribution package is put into
assets
: files that are packaged with the app. Mostly presets and images.- The production version of presets is uploaded to Textual.
vendor
: here are git submodules for building. Currently just Flutter SDK.metadata
: text files for F-Droid, translated on Weblate. Might be good to go full Fastlane.tools
: scripts in Python, Dart, and Bash to process data for the editor.test
: yup, tests. Currently mostly unit tests for algorithmic helpers.lib
: code.pubspec.yaml
: The most important file for a Dart project, lists dependencies and stuff.
Tools
common_hours.py
: the opening hours panel offers common starting and endind times. This script find those in the TagInfo database.encode_url.dart
: encodes URLs with keys for imagery constants.print_common_keys.py
: this script prepares thelib/helpers/tags/common_keys.dart
, used in the raw tag editor.test_sqlite_tags.py
: preset queries are pretty complex (seelib/providers/presets.dart
), so this script was used to test those.
Language Codes
language_names.py
: I've extracted the table from this Wikipedia page to a CSV (language_codes.csv
), and extracted language names and ISO codes to a Dart constant.match_country_langs.py
: this script build a reference table for languages in each country. The Unicode CLDR data might have been better, but this one uses Organic Maps data.
Building the Database
In short, run update.sh
passing it a path to taginfo-db.db
and wait.
It does five things:
- Creates a Python virtual environment to run other scripts.
- Runs
json_to_sqlite.py
: it downloads or reads distribution files from two repositories, Tagging Schema and NSI, and repackages the info into an SQLite database. All preset processing, translations, and search indices are built there. - Runs
add_taginfo.py
. It requests keys for combo fields from this SQLite database, then runs queries on the TagInfo database (which is very big, so the queries are slow) to get the most popular values for those keys, and store them into presets. - Runs
add_imagery.py
. It stores the JSON data from the Layer Index repository in the SQLite database almost 1:1. Coverage polygons are converted into a geohash lookup table. - Packages NSI polygon collection into a constant string inside the code.
Lib
main.dart
: the main executable file for the app. Contains theMaterialApp
with necessary wrappers. Logging, colors, and Let's Encrypt certificate are all set up here.constants.dart
: all the constants for various parts of the app. Including the app title and version, and API endpoints.l10n
: localizationarb
files, translated with Weblate. Theapp_en.arb
is the source and the only one you should edit.- During the build phase, those are compiled into
lib/generated
.
- During the build phase, those are compiled into
There is also commit_info.g.dart
generated into the lib
root with the
commit_info package.
Models and Controllers
models
: classes that are passed between the parts. The most important one is inamenity.dart
with the POI definition. Everything editable is anOsmChange
. Also notefield.dart
with two long functions to create a field from a preset record.helpers
: non-visual functions and classes, and sometimes dictionaries. Most algorithmic stuff goes here, and into providers too. Frankly it's a mess, there's even a provider in there (legend.dart
).geometry
: geometric and geodetic functions, e.g. distance calculation, or snapping points to lines.tags
: everything related to tags and tag filtering. Some of it is described here.
providers
: all the Riverpod providers. They basically keep an application-wide state, and often are used for a pure storage (tied to an app context). Some providers (likeuploader.dart
) do not have a state, but link multiple providers together for convenience.
Views
screens
: all the panes from the app. The app starts with theloading.dart
, then switches tobrowser.dart
, which displays the current mode page.modes
: mode pages that rely on correspondingdefinitions
. The idea being, you can override a definition to create or modify a mode. There are four base modes, plusnavigate.dart
when you zoom out too far.editor
: panes and sheets used not only from the editor pane, but also from modes. E.g.building
andentrance
are displayed when you tap a button in the entrances mode. They all edit anOsmChange
or display information related to it.settings
: all the panes accessible from the Settings menu.
widgets
: building blocks for the app: buttons, markers, info blocks, forms. The biggest thing ismap.dart
with a universal map widget.fields
: classes inheritingPresetField
that implement editors for various field types. Custom fields should go here.hours
: the opening hours editor is the most complex in the app, and all its parts are here.helpers
: helpers and panes that some fields open, e.g. a direction chooser with a map.
Data
Not exactly about the code, but the important thing to understand is, where the data is stored. In the app, it is distributed among four sources:
- Android secure storage and shared preferences. Mostly for settings and tokens. For example, switches state from the Settings panel is stored there.
- Presets SQLite database. It is packaged with the app and is read-only. It is
accessed solely through
PresetProvider
. - App SQLite database. Mostly for downloaded OSM data, but also for location-dependent
indices and settings, e.g. payment tags. See the
DatabaseHelper
for the schema and access. - Transient in-memory storage, in virtually every provider. Mostly caches.