feat(train): OpenFreeMap's dark style in a dark theme, and MAP_DARK_STYLE_URL for a provider's
The maps follow the theme where the source names a dark style, which only the instance's own map did: OpenFreeMap, the default source, had none, so a dark phone showed Liberty's bright map. The default now hands OpenFreeMap's Dark style beside Liberty, and an operator setting MAP_STYLE_URL may set MAP_DARK_STYLE_URL (HTTPS, else none) beside it, passed on by compose.train.yaml and named in .env.example. ADR 0030, D65. Whats-New: The map is dark in a dark theme. Whats-New-De: Die Karte ist im dunklen Design dunkel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
This commit is contained in:
parent
615d66554b
commit
1c67310c93
5 changed files with 39 additions and 4 deletions
|
|
@ -3,10 +3,12 @@ import 'dart:io';
|
||||||
import 'package:halkyon_train_server/src/generated/protocol.dart';
|
import 'package:halkyon_train_server/src/generated/protocol.dart';
|
||||||
|
|
||||||
/// The map source where the operator sets none (ADR 0030, D11): OpenFreeMap,
|
/// The map source where the operator sets none (ADR 0030, D11): OpenFreeMap,
|
||||||
/// which takes no key and makes no contract, its Liberty style.
|
/// which takes no key and makes no contract, its Liberty style, and its Dark
|
||||||
|
/// one in a dark theme (D65).
|
||||||
final openFreeMap = MapSource(
|
final openFreeMap = MapSource(
|
||||||
name: 'OpenFreeMap',
|
name: 'OpenFreeMap',
|
||||||
styleUrl: 'https://tiles.openfreemap.org/styles/liberty',
|
styleUrl: 'https://tiles.openfreemap.org/styles/liberty',
|
||||||
|
darkStyleUrl: 'https://tiles.openfreemap.org/styles/dark',
|
||||||
attribution: 'OpenFreeMap © OpenMapTiles Data from OpenStreetMap',
|
attribution: 'OpenFreeMap © OpenMapTiles Data from OpenStreetMap',
|
||||||
aboutUrl: 'https://openfreemap.org',
|
aboutUrl: 'https://openfreemap.org',
|
||||||
);
|
);
|
||||||
|
|
@ -21,7 +23,8 @@ MapConfig mapConfig() => mapConfigFrom(Platform.environment);
|
||||||
/// The map [environment] sets. `MAP_TILES_URL` (D50), the instance's own
|
/// The map [environment] sets. `MAP_TILES_URL` (D50), the instance's own
|
||||||
/// Protomaps tiles as an HTTPS `{z}/{x}/{y}` template, drawn by Train's
|
/// Protomaps tiles as an HTTPS `{z}/{x}/{y}` template, drawn by Train's
|
||||||
/// style, served beside them at `/map/style/light.json` and `dark.json`;
|
/// style, served beside them at `/map/style/light.json` and `dark.json`;
|
||||||
/// else `MAP_STYLE_URL`, a provider's MapLibre style over HTTPS; else
|
/// else `MAP_STYLE_URL`, a provider's MapLibre style over HTTPS, with
|
||||||
|
/// `MAP_DARK_STYLE_URL` its dark one (HTTPS, else none, D65); else
|
||||||
/// [openFreeMap]. Both with `MAP_SOURCE_NAME` (else the host),
|
/// [openFreeMap]. Both with `MAP_SOURCE_NAME` (else the host),
|
||||||
/// `MAP_ATTRIBUTION` (else OpenStreetMap's credit, and Protomaps' for the
|
/// `MAP_ATTRIBUTION` (else OpenStreetMap's credit, and Protomaps' for the
|
||||||
/// instance's tiles) and `MAP_ABOUT_URL` (HTTPS, else none).
|
/// instance's tiles) and `MAP_ABOUT_URL` (HTTPS, else none).
|
||||||
|
|
@ -59,6 +62,7 @@ MapConfig mapConfigFrom(Map<String, String> environment) {
|
||||||
source: MapSource(
|
source: MapSource(
|
||||||
name: set('MAP_SOURCE_NAME') ?? style.host,
|
name: set('MAP_SOURCE_NAME') ?? style.host,
|
||||||
styleUrl: style.toString(),
|
styleUrl: style.toString(),
|
||||||
|
darkStyleUrl: _https(environment['MAP_DARK_STYLE_URL'])?.toString(),
|
||||||
attribution: set('MAP_ATTRIBUTION') ?? '© OpenStreetMap contributors',
|
attribution: set('MAP_ATTRIBUTION') ?? '© OpenStreetMap contributors',
|
||||||
aboutUrl: about,
|
aboutUrl: about,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@ void main() {
|
||||||
expect(source.styleUrl, 'https://tiles.openfreemap.org/styles/liberty');
|
expect(source.styleUrl, 'https://tiles.openfreemap.org/styles/liberty');
|
||||||
expect(source.attribution, contains('OpenStreetMap'));
|
expect(source.attribution, contains('OpenStreetMap'));
|
||||||
expect(source.aboutUrl, 'https://openfreemap.org');
|
expect(source.aboutUrl, 'https://openfreemap.org');
|
||||||
|
// Its dark style in a dark theme (D65).
|
||||||
|
expect(source.darkStyleUrl, 'https://tiles.openfreemap.org/styles/dark');
|
||||||
});
|
});
|
||||||
|
|
||||||
test("an operator's provider is named as they set it", () {
|
test("an operator's provider is named as they set it", () {
|
||||||
|
|
@ -31,6 +33,26 @@ void main() {
|
||||||
expect(source.aboutUrl, 'https://www.maptiler.com/privacy-policy/');
|
expect(source.aboutUrl, 'https://www.maptiler.com/privacy-policy/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("an operator's provider has a dark style where they set one over "
|
||||||
|
'HTTPS (D65), none otherwise', () {
|
||||||
|
const style = 'https://maps.example.org/light.json';
|
||||||
|
expect(
|
||||||
|
mapSourceFrom(const {
|
||||||
|
'MAP_STYLE_URL': style,
|
||||||
|
'MAP_DARK_STYLE_URL': 'https://maps.example.org/dark.json',
|
||||||
|
}).darkStyleUrl,
|
||||||
|
'https://maps.example.org/dark.json',
|
||||||
|
);
|
||||||
|
for (final dark in [null, '', 'http://maps.example.org/dark.json']) {
|
||||||
|
expect(
|
||||||
|
mapSourceFrom({'MAP_STYLE_URL': style, 'MAP_DARK_STYLE_URL': ?dark})
|
||||||
|
.darkStyleUrl,
|
||||||
|
isNull,
|
||||||
|
reason: dark,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
test('a provider without a name is named by its host, and credits '
|
test('a provider without a name is named by its host, and credits '
|
||||||
'OpenStreetMap', () {
|
'OpenStreetMap', () {
|
||||||
final source = mapSourceFrom(const {
|
final source = mapSourceFrom(const {
|
||||||
|
|
|
||||||
|
|
@ -69,9 +69,11 @@ COMPOSE_FILE=compose.learn.yaml
|
||||||
# or subscriptions needs a paid plan: its key.
|
# or subscriptions needs a paid plan: its key.
|
||||||
#WEATHER=
|
#WEATHER=
|
||||||
#OPEN_METEO_API_KEY=
|
#OPEN_METEO_API_KEY=
|
||||||
# Train's map (ADR 0030, D22): a MapLibre style over HTTPS, with its name, credit and
|
# Train's map (ADR 0030, D22): a MapLibre style over HTTPS, with its dark one for a
|
||||||
# page; empty: OpenFreeMap's.
|
# dark theme (D65; empty: the light one in both), its name, credit and page; empty:
|
||||||
|
# OpenFreeMap's, Liberty and Dark.
|
||||||
#MAP_STYLE_URL=
|
#MAP_STYLE_URL=
|
||||||
|
#MAP_DARK_STYLE_URL=
|
||||||
#MAP_SOURCE_NAME=
|
#MAP_SOURCE_NAME=
|
||||||
#MAP_ATTRIBUTION=
|
#MAP_ATTRIBUTION=
|
||||||
#MAP_ABOUT_URL=
|
#MAP_ABOUT_URL=
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ services:
|
||||||
OPEN_METEO_API_KEY: ${OPEN_METEO_API_KEY:-}
|
OPEN_METEO_API_KEY: ${OPEN_METEO_API_KEY:-}
|
||||||
# The map source (D22); empty: OpenFreeMap.
|
# The map source (D22); empty: OpenFreeMap.
|
||||||
MAP_STYLE_URL: ${MAP_STYLE_URL:-}
|
MAP_STYLE_URL: ${MAP_STYLE_URL:-}
|
||||||
|
MAP_DARK_STYLE_URL: ${MAP_DARK_STYLE_URL:-}
|
||||||
MAP_SOURCE_NAME: ${MAP_SOURCE_NAME:-}
|
MAP_SOURCE_NAME: ${MAP_SOURCE_NAME:-}
|
||||||
MAP_ATTRIBUTION: ${MAP_ATTRIBUTION:-}
|
MAP_ATTRIBUTION: ${MAP_ATTRIBUTION:-}
|
||||||
MAP_ABOUT_URL: ${MAP_ABOUT_URL:-}
|
MAP_ABOUT_URL: ${MAP_ABOUT_URL:-}
|
||||||
|
|
|
||||||
|
|
@ -1725,6 +1725,12 @@ Strava. What was found, 27 Oct:
|
||||||
map showing in the corners. The bar names the activity (Running), not the
|
map showing in the corners. The bar names the activity (Running), not the
|
||||||
workout, whose name is the sheet's first line: once in sight, not twice (D63 had
|
workout, whose name is the sheet's first line: once in sight, not twice (D63 had
|
||||||
the bar take the sheet's title).
|
the bar take the sheet's title).
|
||||||
|
- **A dark map on OpenFreeMap too**: the maps followed the theme where the source
|
||||||
|
has a dark style (D50), which only the instance's own map had. OpenFreeMap's
|
||||||
|
default source now hands its Dark style beside Liberty, and an operator's
|
||||||
|
provider takes one from `MAP_DARK_STYLE_URL` (HTTPS, else none: the light style
|
||||||
|
in both themes). A dark Liberty made in the app (its colours inverted) was the
|
||||||
|
alternative, a style of the app's own for a provider's tiles it can't know.
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
- Train's sensors are one pattern: open profiles read by the app itself, on the phone;
|
- Train's sensors are one pattern: open profiles read by the app itself, on the phone;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue