BigUI : Nav on device, maybe?

This commit is contained in:
firestarsdog
2026-08-09 19:30:35 -04:00
parent d8528595b3
commit 98f856a548
5 changed files with 1318 additions and 4 deletions
@@ -2,10 +2,9 @@ from __future__ import annotations
from collections.abc import Callable
import pyray as rl
from openpilot.common.params import Params
from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.lib.multilang import tr, tr_noop
from openpilot.system.ui.lib.application import MousePos, gui_app, FontWeight
from openpilot.system.ui.lib.application import MousePos
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import StarPilotPanelType, StarPilotPanelInfo, FrameCachedParams
from openpilot.selfdrive.ui.layouts.settings.starpilot.sounds import StarPilotSoundsLayout
@@ -13,6 +12,7 @@ from openpilot.selfdrive.ui.layouts.settings.starpilot.driving_model import Star
from openpilot.selfdrive.ui.layouts.settings.starpilot.longitudinal import StarPilotLongitudinalLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.lateral import StarPilotLateralLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.maps import StarPilotMapsLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.navigation import StarPilotNavigationLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.system_settings import StarPilotSystemLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.appearance import StarPilotAppearanceLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.vehicle import StarPilotVehicleSettingsLayout
@@ -32,9 +32,9 @@ class StarPilotLayout(Widget):
"buttons": [("Driving Model", "DRIVING_MODEL", "aicar"), ("Gas / Brake", "LONGITUDINAL", "road"), ("Steering", "LATERAL", "steering")],
},
{
"title": "Map Data",
"title": "Navigation & Maps",
"icon": "navigate",
"panel": "MAPS",
"buttons": [("Map Data", "MAPS", "navigate"), ("Navigation", "NAVIGATION", "road")],
},
{
"title": "System",
@@ -75,6 +75,7 @@ class StarPilotLayout(Widget):
StarPilotPanelType.LONGITUDINAL: StarPilotPanelInfo(tr_noop("Gas / Brake"), StarPilotLongitudinalLayout()),
StarPilotPanelType.LATERAL: StarPilotPanelInfo(tr_noop("Steering"), StarPilotLateralLayout()),
StarPilotPanelType.MAPS: StarPilotPanelInfo(tr_noop("Map Data"), StarPilotMapsLayout()),
StarPilotPanelType.NAVIGATION: StarPilotPanelInfo(tr_noop("Navigation"), StarPilotNavigationLayout()),
StarPilotPanelType.VISUALS: StarPilotPanelInfo(tr_noop("Appearance"), StarPilotAppearanceLayout()),
StarPilotPanelType.VEHICLE: StarPilotPanelInfo(tr_noop("Vehicle Settings"), StarPilotVehicleSettingsLayout()),
}
@@ -85,6 +86,7 @@ class StarPilotLayout(Widget):
StarPilotPanelType.SYSTEM,
StarPilotPanelType.LATERAL,
StarPilotPanelType.MAPS,
StarPilotPanelType.NAVIGATION,
StarPilotPanelType.VISUALS,
StarPilotPanelType.VEHICLE,
)
@@ -177,6 +179,7 @@ class StarPilotLayout(Widget):
"LONGITUDINAL": StarPilotPanelType.LONGITUDINAL,
"LATERAL": StarPilotPanelType.LATERAL,
"MAPS": StarPilotPanelType.MAPS,
"NAVIGATION": StarPilotPanelType.NAVIGATION,
"VISUALS": StarPilotPanelType.VISUALS,
"VEHICLE": StarPilotPanelType.VEHICLE,
}
File diff suppressed because it is too large Load Diff
@@ -71,6 +71,7 @@ class StarPilotPanelType(IntEnum):
VISUALS = 8
VEHICLE = 10
SYSTEM = 12
NAVIGATION = 13
@dataclass
@@ -0,0 +1,169 @@
import hashlib
import json
from openpilot.selfdrive.ui.layouts.settings.starpilot.navigation import (
MapboxSearchClient,
_NavigationParams,
_add_favorite_destination,
_favorite_destination_id,
_favorite_payload_for_galaxy,
_load_favorite_destinations,
_remove_favorite_destination,
_update_favorite_destination,
)
def test_favorites_get_stable_ids_and_deduplicate_by_id():
favorite = {
"name": "Home",
"latitude": "41.881832",
"longitude": "-87.623177",
"routeId": "main",
}
expected_id = _favorite_destination_id(favorite)
added = _add_favorite_destination("[]", favorite)
duplicate = _add_favorite_destination(json.dumps(added), {**favorite, "id": expected_id})
assert added == [{**favorite, "latitude": 41.881832, "longitude": -87.623177, "id": expected_id}]
assert duplicate == added
assert _load_favorite_destinations(json.dumps(added)) == added
def test_favorite_id_preserves_galaxy_hash_input_for_numeric_coordinates():
favorite = {"name": "One", "latitude": 1.0, "longitude": 2.0}
expected = hashlib.sha1(b"2.0,1.0||One").hexdigest()
assert _favorite_destination_id(favorite) == expected
def test_new_favorites_use_galaxys_default_route_id_contract():
destination = {"name": "Home", "latitude": 1.0, "longitude": 2.0}
assert _favorite_payload_for_galaxy(destination)["routeId"] == "main"
assert _favorite_payload_for_galaxy({**destination, "routeId": "alternate"})["routeId"] == "alternate"
def test_favorite_special_locations_are_mutually_exclusive():
raw = json.dumps([
{"id": "home", "name": "Home", "latitude": 1, "longitude": 2, "is_home": True},
{"id": "work", "name": "Work", "latitude": 3, "longitude": 4},
])
updated = _update_favorite_destination(raw, {"id": "work"}, is_work=True)
assert updated is not None
assert updated[0].get("is_home") is True
assert updated[1].get("is_work") is True
assert updated[1].get("is_home") is None
def test_favorite_rename_can_target_legacy_route_id_without_coordinates():
raw = json.dumps([{
"name": "Old name",
"routeId": "route-1",
"latitude": 1,
"longitude": 2,
}])
updated = _update_favorite_destination(raw, {"routeId": "route-1"}, name="New name")
assert updated is not None
assert updated[0]["name"] == "New name"
def test_favorite_can_be_removed_by_legacy_payload_identity():
raw = json.dumps([
{"name": "Keep", "latitude": 1, "longitude": 2},
{"name": "Remove", "latitude": 3, "longitude": 4},
])
updated = _remove_favorite_destination(raw, {"name": "Remove", "latitude": 3, "longitude": 4})
assert [favorite["name"] for favorite in updated] == ["Keep"]
def test_navigation_params_commits_destination_and_clears_runtime_state():
class FakeParams:
def __init__(self):
self.values = {}
self.removed = []
def get(self, key, encoding=None, default=None):
value = self.values.get(key, default)
if encoding == "utf-8" and isinstance(value, bytes):
return value.decode("utf-8")
return value
def put(self, key, value):
self.values[key] = value
def remove(self, key):
self.removed.append(key)
self.values.pop(key, None)
params = FakeParams()
memory = FakeParams()
navigation = _NavigationParams(params, memory)
destination = navigation.set_destination({"name": "Home", "latitude": 1, "longitude": 2})
assert navigation.clear_navigation() is True
assert destination["place_name"] == "Home"
assert params.values["ApiCache_NavDestinations"][0]["place_name"] == "Home"
assert "NavDestination" in params.removed
assert memory.removed == ["NavInstructionState", "NavInstructionCollapsed"]
class FakeResponse:
def __init__(self, payload, status_code=200):
self._payload = payload
self.status_code = status_code
def raise_for_status(self):
if self.status_code >= 400:
raise RuntimeError(f"HTTP {self.status_code}")
def json(self):
return self._payload
class FakeSession:
def __init__(self):
self.calls = []
def get(self, url, *, params, timeout):
self.calls.append((url, params, timeout))
if url.endswith("/suggest"):
return FakeResponse({
"suggestions": [{
"name": "OpenAI",
"full_address": "OpenAI, San Francisco, CA",
"mapbox_id": "place.openai",
}],
})
return FakeResponse({
"features": [{
"properties": {"name": "OpenAI", "full_address": "OpenAI, San Francisco, CA"},
"geometry": {"coordinates": [-122.401, 37.789]},
}],
})
def test_mapbox_search_and_retrieve_use_public_token_only():
session = FakeSession()
client = MapboxSearchClient(session=session)
results = client.search("openai", "public-token", "session-token", proximity=(-122.4, 37.8), language="en")
resolved = client.resolve(results[0], "public-token", "session-token")
assert results[0].name == "OpenAI"
assert results[0].latitude is None
assert resolved.to_destination() == {
"name": "OpenAI",
"place_name": "OpenAI",
"latitude": 37.789,
"longitude": -122.401,
}
assert session.calls[0][1]["access_token"] == "public-token"
assert "secret" not in session.calls[0][1]
@@ -0,0 +1,46 @@
from openpilot.selfdrive.ui.layouts.settings.starpilot.main_panel import StarPilotLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.navigation import StarPilotNavigationLayout
from openpilot.selfdrive.ui.layouts.settings.starpilot.panel import StarPilotPanelType
def test_navigation_and_maps_is_the_parent_folder_for_map_data_and_navigation():
category = next(item for item in StarPilotLayout.CATEGORIES if item["title"] == "Navigation & Maps")
assert "panel" not in category
assert category["buttons"] == [
("Map Data", "MAPS", "navigate"),
("Navigation", "NAVIGATION", "road"),
]
assert all(item["title"] != "Map Data" for item in StarPilotLayout.CATEGORIES)
assert StarPilotPanelType.NAVIGATION.value == 13
def test_navigation_start_is_the_summary_action_not_a_duplicate_rail_target():
layout = object.__new__(StarPilotNavigationLayout)
layout._draft_destination = {
"name": "Home",
"place_name": "Home",
"latitude": 1.0,
"longitude": 2.0,
}
layout._selected_favorite = None
layout._favorites = []
action_ids = [action[0] for action in layout._action_definitions()]
assert action_ids == ["action:favorite", "action:home", "action:work"]
def test_rejected_search_invalidates_an_in_flight_request_generation():
layout = object.__new__(StarPilotNavigationLayout)
layout._search_generation = 3
layout._query = "previous"
layout._search_results = []
layout._search_error = ""
layout._draft_destination = None
layout._selected_favorite = None
layout._start_search("ab")
assert layout._search_generation == 4
assert layout._search_error