mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 02:48:38 -04:00
- Add MapLibre GL JS viewer with light/dark themes, terrain layer, and embedded static map page for coordinate sharing - Add map pin support with persistent map_pins.yaml config - Add map region subscriptions and downloader with progress tracking, sourcing pre-extracted PMTiles from a cold CDN - Add map export to PNG and GPS coordinate copy via context menu - Add MapViewer React component alongside reworked Map page - Add map catalog and region-building script (build_map_regions.py) - Remove OSM import/render scripts, leaflet files, Apache configs, renderd service, and osm-map-dumper Docker container - Update Caddyfile to serve PMTiles and map static assets - Update build/install/repair scripts for Protomaps dependencies - Drop map_file table, add/drop map_subscription table (alembic) - Adding button to skip primary drive mounting during onboarding.
100 lines
2.7 KiB
Python
100 lines
2.7 KiB
Python
from dataclasses import dataclass, field
|
|
from typing import List
|
|
|
|
from wrolpi.common import ConfigFile, logger
|
|
from wrolpi.dates import now
|
|
from wrolpi.switches import register_switch_handler, ActivateSwitchMethod
|
|
|
|
logger = logger.getChild(__name__)
|
|
|
|
|
|
@dataclass
|
|
class MapPinsConfigValidator:
|
|
version: int = None
|
|
pins: list = field(default_factory=list)
|
|
|
|
|
|
class MapPinsConfig(ConfigFile):
|
|
file_name = 'map_pins.yaml'
|
|
default_config = dict(
|
|
version=0,
|
|
pins=[],
|
|
)
|
|
validator = MapPinsConfigValidator
|
|
|
|
def import_config(self, file=None, send_events=False):
|
|
super().import_config(file, send_events)
|
|
self.successful_import = True
|
|
|
|
@property
|
|
def pins(self) -> List[dict]:
|
|
return list(self._config.get('pins', []))
|
|
|
|
@pins.setter
|
|
def pins(self, value: List[dict]):
|
|
self.update({'pins': value})
|
|
|
|
def _next_pin_id(self) -> int:
|
|
"""Return the next available pin ID (max existing ID + 1)."""
|
|
pins = self.pins
|
|
if not pins:
|
|
return 1
|
|
return max(p.get('id', 0) for p in pins) + 1
|
|
|
|
def add_pin(self, lat: float, lon: float, label: str, color: str = 'red') -> dict:
|
|
pin = dict(
|
|
id=self._next_pin_id(),
|
|
lat=round(lat, 6),
|
|
lon=round(lon, 6),
|
|
label=label,
|
|
color=color,
|
|
created=str(now().date()),
|
|
)
|
|
pins = self.pins
|
|
pins.append(pin)
|
|
self.pins = pins
|
|
save_map_pins_config.activate_switch()
|
|
return pin
|
|
|
|
def delete_pin(self, pin_id: int) -> bool:
|
|
pins = self.pins
|
|
new_pins = [p for p in pins if p.get('id') != pin_id]
|
|
if len(new_pins) == len(pins):
|
|
return False
|
|
self.pins = new_pins
|
|
save_map_pins_config.activate_switch()
|
|
return True
|
|
|
|
def update_pin(self, pin_id: int, label: str = None, color: str = None) -> bool:
|
|
pins = self.pins
|
|
for pin in pins:
|
|
if pin.get('id') == pin_id:
|
|
if label is not None:
|
|
pin['label'] = label
|
|
if color is not None:
|
|
pin['color'] = color
|
|
self.pins = pins
|
|
save_map_pins_config.activate_switch()
|
|
return True
|
|
return False
|
|
|
|
|
|
MAP_PINS_CONFIG: MapPinsConfig = MapPinsConfig()
|
|
|
|
# Test override.
|
|
TEST_MAP_PINS_CONFIG = None
|
|
|
|
|
|
def get_map_pins_config() -> MapPinsConfig:
|
|
global TEST_MAP_PINS_CONFIG
|
|
if isinstance(TEST_MAP_PINS_CONFIG, ConfigFile):
|
|
return TEST_MAP_PINS_CONFIG
|
|
return MAP_PINS_CONFIG
|
|
|
|
|
|
@register_switch_handler('save_map_pins_config')
|
|
def save_map_pins_config():
|
|
get_map_pins_config().save()
|
|
|
|
|
|
save_map_pins_config: ActivateSwitchMethod
|