From b4dbc18a14d4001e4cff113631c3e03d379911d9 Mon Sep 17 00:00:00 2001 From: firestar5683 <168790843+firestar5683@users.noreply.github.com> Date: Mon, 14 Sep 2026 11:39:02 -0500 Subject: [PATCH] mario --- selfdrive/ui/mici/onroad/hud_renderer.py | 2 + selfdrive/ui/onroad/exp_button.py | 7 +- .../ui/tests/test_rivian_lateral_mode.py | 20 ++ starpilot/car/ford/lateral.py | 27 +- starpilot/car/ford/tests/test_lateral.py | 63 ++++ .../common/assets/device_settings_layout.json | 4 +- .../the_galaxy/assets/mobile/css/material.css | 335 +++++++++++++++++- .../system/the_galaxy/assets/mobile/js/api.js | 2 + .../system/the_galaxy/assets/mobile/js/app.js | 4 +- .../assets/mobile/js/components/AppShell.js | 22 +- .../mobile/js/components/LanguageSelector.js | 10 +- .../components/NavigationDestinationPanel.js | 164 +++++++-- .../the_galaxy/assets/mobile/js/i18n.js | 182 +++++++++- .../the_galaxy/assets/mobile/js/store.js | 16 + .../assets/mobile/js/views/Navigation.js | 32 +- .../assets/mobile/js/views/Settings.js | 4 +- .../assets/mobile/js/views/SystemTools.js | 53 +-- 17 files changed, 857 insertions(+), 90 deletions(-) diff --git a/selfdrive/ui/mici/onroad/hud_renderer.py b/selfdrive/ui/mici/onroad/hud_renderer.py index 982f615155..f5861b8dfa 100644 --- a/selfdrive/ui/mici/onroad/hud_renderer.py +++ b/selfdrive/ui/mici/onroad/hud_renderer.py @@ -195,10 +195,12 @@ class HudRenderer(Widget): controls_state = sm['controlsState'] car_state = sm['carState'] rivian_lateral_mode.update() + starpilot_car_state = sm['starpilotCarState'] if sm.valid.get('starpilotCarState', False) else None self._wheel_tint = get_wheel_tint( getattr(car_state, "brakePressed", False), rivian_lateral_mode.wheel_tint, ui_state.ui_params.get_bool("ShowBrakeStatus"), + getattr(starpilot_car_state, "brakeLights", False), ) v_cruise_cluster = car_state.vCruiseCluster diff --git a/selfdrive/ui/onroad/exp_button.py b/selfdrive/ui/onroad/exp_button.py index 6e753551a1..927e78d142 100644 --- a/selfdrive/ui/onroad/exp_button.py +++ b/selfdrive/ui/onroad/exp_button.py @@ -16,8 +16,9 @@ from openpilot.starpilot.common.experimental_state import ( BRAKE_WHEEL_COLOR = rl.Color(255, 0, 0, 255) -def get_wheel_tint(brake_pressed: bool, mode_tint: rl.Color | None, brake_status_enabled: bool) -> rl.Color | None: - return BRAKE_WHEEL_COLOR if brake_status_enabled and brake_pressed else mode_tint +def get_wheel_tint(brake_pressed: bool, mode_tint: rl.Color | None, brake_status_enabled: bool, + brake_lights: bool = False) -> rl.Color | None: + return BRAKE_WHEEL_COLOR if brake_status_enabled and (brake_pressed or brake_lights) else mode_tint class ExpButton(Widget): @@ -111,10 +112,12 @@ class ExpButton(Widget): texture = self._txt_exp if exp_mode else self._txt_wheel color = self._white_color tint = None + starpilot_car_state = ui_state.sm["starpilotCarState"] if getattr(ui_state.sm, "valid", {}).get("starpilotCarState", False) else None wheel_tint = get_wheel_tint( getattr(ui_state.sm["carState"], "brakePressed", False), self.wheel_tint, self._params.get_bool("ShowBrakeStatus"), + getattr(starpilot_car_state, "brakeLights", False), ) if wheel_tint is not None: tint = rl.Color(wheel_tint.r, wheel_tint.g, wheel_tint.b, self._white_color.a) diff --git a/selfdrive/ui/tests/test_rivian_lateral_mode.py b/selfdrive/ui/tests/test_rivian_lateral_mode.py index e7042a4060..eaff996d75 100644 --- a/selfdrive/ui/tests/test_rivian_lateral_mode.py +++ b/selfdrive/ui/tests/test_rivian_lateral_mode.py @@ -311,6 +311,26 @@ def test_non_mici_wheel_icon_turns_red_when_brakes_are_pressed(monkeypatch): assert (texture_color.r, texture_color.g, texture_color.b, texture_color.a) == (255, 0, 0, 255) +def test_non_mici_wheel_icon_uses_reported_brake_lights(monkeypatch): + module, draws = load_exp_button(monkeypatch) + button = module.ExpButton(192, 144) + button.wheel_tint = FakeColor(0x4D, 0x9D, 0xFF, 255) + class FakeUiSubMaster(dict): + pass + + module.ui_state.sm = FakeUiSubMaster(module.ui_state.sm) + module.ui_state.sm.valid = {"starpilotCarState": True} + module.ui_state.sm["starpilotCarState"] = SimpleNamespace(brakeLights=True) + module.ui_state.ui_params.get_bool = lambda key, *args, **kwargs: key == "ShowBrakeStatus" + button._update_state() + + button._render(FakeRectangle(0, 0, 192, 192)) + + assert len(draws["textures"]) == 1 + texture_color = draws["textures"][0][-1] + assert (texture_color.r, texture_color.g, texture_color.b, texture_color.a) == (255, 0, 0, 255) + + def test_non_mici_wheel_icon_brake_tint_is_disabled_by_default(monkeypatch): module, draws = load_exp_button(monkeypatch) button = module.ExpButton(192, 144) diff --git a/starpilot/car/ford/lateral.py b/starpilot/car/ford/lateral.py index 6a0f6f1a78..5170bf4658 100644 --- a/starpilot/car/ford/lateral.py +++ b/starpilot/car/ford/lateral.py @@ -52,6 +52,12 @@ MACH_E_DIRECTION_CHANGE_MIN_PREVIEW_CURVATURE = 0.0005 MACH_E_DIRECTION_CHANGE_FULL_PREVIEW_CURVATURE = 0.002 MACH_E_DIRECTION_CHANGE_MIN_LAG_CURVATURE = 0.0008 MACH_E_DIRECTION_CHANGE_FULL_LAG_CURVATURE = 0.0015 +MACH_E_LOW_SPEED_DIRECTION_CHANGE_START_SPEED = 1.8 +MACH_E_LOW_SPEED_DIRECTION_CHANGE_FULL_SPEED = 2.0 +MACH_E_LOW_SPEED_DIRECTION_CHANGE_HOLD_SPEED = 2.8 +MACH_E_LOW_SPEED_DIRECTION_CHANGE_FADE_SPEED = 3.5 +MACH_E_LOW_SPEED_DIRECTION_CHANGE_MIN_CURVATURE = 0.0004 +MACH_E_LOW_SPEED_DIRECTION_CHANGE_FULL_CURVATURE = 0.0006 FORD_CURVATURE_LOOKAHEAD = { CAR.FORD_EXPLORER_MK6: 0.20, } @@ -261,6 +267,21 @@ class FordLateralController: )) return preview_weight * lag_weight + @staticmethod + def _low_speed_direction_change_weight(v_ego: float, desired: float) -> float: + speed_weight = float(np.interp( + v_ego, + [MACH_E_LOW_SPEED_DIRECTION_CHANGE_START_SPEED, MACH_E_LOW_SPEED_DIRECTION_CHANGE_FULL_SPEED, + MACH_E_LOW_SPEED_DIRECTION_CHANGE_HOLD_SPEED, MACH_E_LOW_SPEED_DIRECTION_CHANGE_FADE_SPEED], + [0.0, 1.0, 1.0, 0.0], + )) + curvature_weight = float(np.interp( + abs(desired), + [MACH_E_LOW_SPEED_DIRECTION_CHANGE_MIN_CURVATURE, MACH_E_LOW_SPEED_DIRECTION_CHANGE_FULL_CURVATURE], + [0.0, 1.0], + )) + return speed_weight * curvature_weight + def _manual_turn(self, CC, CS) -> bool: if not CC.latActive: self.human_turn.reset() @@ -329,11 +350,15 @@ class FordLateralController: turn_in_predicted = self._predicted_curvature(v_ego, lookahead + MACH_E_TURN_IN_LOOKAHEAD_EXTRA) direction_change_predicted = turn_in_predicted direction_change_weight = 0.0 - if v_ego > MACH_E_DIRECTION_CHANGE_MIN_SPEED and not CS.out.steeringPressed and not self._lane_change()[0]: + direction_change_speed_weight = float(v_ego > MACH_E_DIRECTION_CHANGE_MIN_SPEED) + if direction_change_speed_weight == 0.0: + direction_change_speed_weight = self._low_speed_direction_change_weight(v_ego, desired) + if direction_change_speed_weight > 0.0 and not CS.out.steeringPressed and not self._lane_change()[0]: direction_change_lookahead_extra = self._direction_change_lookahead_extra(v_ego) if direction_change_lookahead_extra > MACH_E_TURN_IN_LOOKAHEAD_EXTRA: direction_change_predicted = self._predicted_curvature(v_ego, lookahead + direction_change_lookahead_extra) direction_change_weight = self._direction_change_preview_weight(desired, direction_change_predicted, current) + direction_change_weight *= direction_change_speed_weight if direction_change_weight > 0.0: predicted = float(np.interp(direction_change_weight, [0.0, 1.0], [predicted, direction_change_predicted])) allow_opposite_preview = True diff --git a/starpilot/car/ford/tests/test_lateral.py b/starpilot/car/ford/tests/test_lateral.py index cf33a9b183..20cde4c0ef 100644 --- a/starpilot/car/ford/tests/test_lateral.py +++ b/starpilot/car/ford/tests/test_lateral.py @@ -199,6 +199,21 @@ def test_mach_e_direction_change_lookahead_extra_fades_by_speed(controller, spee assert controller._direction_change_lookahead_extra(speed) == pytest.approx(expected) +@pytest.mark.parametrize("speed,desired,expected", ( + (1.8, 0.0010, 0.0), + (1.9, 0.0010, 0.5), + (2.0, 0.0010, 1.0), + (2.8, 0.0010, 1.0), + (3.15, 0.0010, 0.5), + (3.5, 0.0010, 0.0), + (2.5, 0.0004, 0.0), + (2.5, 0.0005, 0.5), + (2.5, 0.0006, 1.0), +)) +def test_mach_e_low_speed_direction_change_weight(controller, speed, desired, expected): + assert controller._low_speed_direction_change_weight(speed, desired) == pytest.approx(expected) + + @pytest.mark.parametrize("sign", (1.0, -1.0)) def test_mach_e_direction_change_preview_leads_a_lagging_unwind(controller, sign): controller.CP.carFingerprint = CAR.FORD_MUSTANG_MACH_E_MK1 @@ -257,6 +272,30 @@ def test_mach_e_direction_change_preview_uses_far_path_when_unwind_lags(controll pytest.approx(0.003), True)] +def test_mach_e_direction_change_preview_leads_low_speed_handoff(controller, monkeypatch): + controller.CP.carFingerprint = CAR.FORD_MUSTANG_MACH_E_MK1 + controller.sm["liveDelay"].lateralDelay = 0.4 + controller.desired_curvature_last = 0.002 + blend_inputs = [] + monkeypatch.setattr( + controller, "_predicted_curvature", + lambda _v_ego, lookahead: 0.002 if lookahead < 1.0 else -0.002, + ) + monkeypatch.setattr( + controller, "_blend_and_scale", + lambda desired, predicted, v_ego, current, allow_opposite_preview=False: + blend_inputs.append((desired, predicted, v_ego, current, allow_opposite_preview)) or (0.0, 1), + ) + + controller.update( + SimpleNamespace(latActive=True), car_state(speed=2.5, curvature=0.003), + SimpleNamespace(curvature=0.0015), + ) + + assert blend_inputs == [(pytest.approx(0.0015), pytest.approx(-0.002), pytest.approx(2.5), + pytest.approx(0.003), True)] + + def test_mach_e_direction_change_preview_uses_extended_horizon_at_medium_speed(controller, monkeypatch): controller.CP.carFingerprint = CAR.FORD_MUSTANG_MACH_E_MK1 controller.sm["liveDelay"].lateralDelay = 0.4 @@ -310,8 +349,12 @@ def test_mach_e_extended_direction_horizon_does_not_replace_turn_in_preview(cont @pytest.mark.parametrize("speed,steering_pressed,lane_change", ( + (1.8, False, False), + (3.5, False, False), (8.0, False, False), (9.0, False, False), + (2.5, True, False), + (2.5, False, True), (15.0, True, False), (15.0, False, True), )) @@ -340,6 +383,26 @@ def test_non_mach_e_direction_change_preview_is_unchanged(controller): desired=0.0015, preview=-0.002, current=0.003) == 0.0 +def test_non_mach_e_bypasses_low_speed_direction_change_preview(controller, monkeypatch): + controller.desired_curvature_last = 0.002 + lookaheads = [] + monkeypatch.setattr( + controller, "_predicted_curvature", + lambda _v_ego, lookahead: lookaheads.append(lookahead) or -0.002, + ) + monkeypatch.setattr( + controller, "_low_speed_direction_change_weight", + lambda *_args: pytest.fail("low-speed direction-change preview must remain Mach-E-only"), + ) + + controller.update( + SimpleNamespace(latActive=True), car_state(speed=2.5, curvature=0.003), + SimpleNamespace(curvature=0.0015), + ) + + assert lookaheads == [pytest.approx(0.2)] + + def test_mach_e_turn_in_preview_uses_extra_model_horizon(controller, monkeypatch): controller.CP.carFingerprint = CAR.FORD_MUSTANG_MACH_E_MK1 controller.sm["liveDelay"].lateralDelay = 0.4 diff --git a/starpilot/common/assets/device_settings_layout.json b/starpilot/common/assets/device_settings_layout.json index abcaf762a2..2ddb93a4cf 100644 --- a/starpilot/common/assets/device_settings_layout.json +++ b/starpilot/common/assets/device_settings_layout.json @@ -2842,8 +2842,8 @@ { "key": "ShowBrakeStatus", "label": "Show Brake Status", - "description": "Tint the on-screen steering-wheel icon red while the car reports that the brake pedal is pressed.", - "picker_description": "Tints the on-screen steering-wheel icon red while braking.", + "description": "Tint the on-screen steering-wheel icon red while the car reports that its brake lights are on.", + "picker_description": "Tints the on-screen steering-wheel icon red while the brake lights are on.", "data_type": "bool", "ui_type": "toggle", "galaxy_only": true, diff --git a/starpilot/system/the_galaxy/assets/mobile/css/material.css b/starpilot/system/the_galaxy/assets/mobile/css/material.css index 46b9799de9..1704438797 100644 --- a/starpilot/system/the_galaxy/assets/mobile/css/material.css +++ b/starpilot/system/the_galaxy/assets/mobile/css/material.css @@ -360,7 +360,8 @@ ul { list-style: none; margin: 0; padding: 0; } } .gx-appbar .gx-appbar__back, -.gx-appbar .gx-theme-toggle { +.gx-appbar .gx-theme-toggle, +.gx-appbar .gx-appbar__pin { background: var(--glass-bg); backdrop-filter: var(--glass-blur); -webkit-backdrop-filter: var(--glass-blur); @@ -464,6 +465,7 @@ ul { list-style: none; margin: 0; padding: 0; } .gx-icon-btn i { font-size: 1.3rem; } .gx-back-btn { display: none; } .gx-menu-btn { display: inline-flex; } +.gx-appbar .gx-appbar__pin { display: none; } .gx-searchwrap { align-items: center; @@ -1297,6 +1299,336 @@ button.gx-chip:hover { letter-spacing: -0.02em; } +.gx-drawer__pin { + color: var(--text-muted); + margin-left: auto; +} + +.gx-drawer__pin:hover, +.gx-drawer__pin[aria-pressed="true"] { + color: var(--primary); +} + +.gx-language-card { + margin-bottom: var(--sp-4); +} + +.gx-language-card__row { + align-items: center; + display: flex; + flex-wrap: wrap; + gap: var(--sp-3); +} + +.gx-language-card__label { + align-items: center; + display: flex; + flex: 1 1 360px; + gap: var(--sp-4); + min-width: 220px; +} + +.gx-language-card__select { + margin-left: var(--sp-2); + max-width: 220px; +} + +.gx-language-card__hint { + margin-left: auto; +} + +@media (min-width: 768px) { + .gx-app.gx-nav-pinned .gx-content { + margin-left: 320px; + width: calc(100% - 320px); + } + + .gx-app.gx-nav-pinned .gx-appbar { + margin-left: 320px; + width: calc(100% - 320px); + } +} + +@media (max-width: 767px) { + .gx-language-card__label { + flex-basis: 100%; + } + + .gx-language-card__hint { + margin-left: 0; + width: 100%; + } +} + +/* The destination view is a map-first screen. Search and route details float + over the map, matching the classic navigation experience. */ +.gx-navigation-view { + margin: calc(-1 * var(--sp-4)); + min-height: calc(100dvh - var(--appbar-height)); + position: relative; +} + +.gx-navigation-stage { + background: var(--surface-container-low); + min-height: calc(100dvh - var(--appbar-height)); + overflow: hidden; + position: relative; + width: 100%; +} + +.gx-navigation-map { + height: calc(100dvh - var(--appbar-height)); + min-height: 520px; + width: 100%; +} + +.gx-navigation-map .mapboxgl-canvas { + outline: none; +} + +/* Route details use a light Mapbox popup over the map. Keep every text span + readable when the route is changed, without affecting the destination cards + or the classic navigation view. */ +.gx-navigation-stage .route-tooltip .mapboxgl-popup-content, +.gx-navigation-stage .route-tooltip .custom-tooltip, +.gx-navigation-stage .route-tooltip .tooltip-row, +.gx-navigation-stage .route-tooltip .tooltip-row .label, +.gx-navigation-stage .route-tooltip .tooltip-row .value { + color: #000 !important; +} + +.gx-navigation-stage .route-tooltip .mapboxgl-popup-content { + background: #fff !important; +} + +.gx-navigation-overlay { + inset: 0; + padding: var(--sp-4); + pointer-events: none; + position: absolute; + z-index: 2; +} + +.gx-navigation-overlay > * { + pointer-events: auto; +} + +.gx-navigation-search, +.gx-navigation-summary, +.gx-navigation-recent, +.gx-navigation-error { + max-width: min(500px, calc(100vw - 32px)); +} + +.gx-navigation-search { + margin: 0; + overflow: visible; + padding: var(--sp-2); +} + +.gx-navigation-search__row { + align-items: center; + display: flex; + gap: var(--sp-2); +} + +.gx-navigation-search__row > i { + color: var(--primary); + font-size: 1.15rem; + padding-left: var(--sp-2); +} + +.gx-navigation-search .gx-field { + background: transparent; + border: 0; + box-shadow: none; + flex: 1; + min-width: 0; + padding-left: var(--sp-1); +} + +.gx-navigation-send { + color: var(--primary); + flex: 0 0 auto; +} + +.gx-navigation-status, +.gx-navigation-recent__title { + color: var(--text-muted); + font-size: var(--fs-sm); + padding: var(--sp-2) var(--sp-3) var(--sp-1); +} + +.gx-navigation-suggestions { + background: var(--card-scroll-bg); + border-top: 1px solid var(--outline); + display: grid; + gap: 2px; + margin: var(--sp-2) calc(-1 * var(--sp-2)) calc(-1 * var(--sp-2)); + max-height: 300px; + overflow-y: auto; + padding: var(--sp-2); +} + +.gx-navigation-suggestion { + align-items: center; + background: transparent; + border: 0; + border-radius: var(--radius-sm); + color: var(--on-surface); + cursor: pointer; + display: flex; + gap: var(--sp-3); + justify-content: space-between; + min-height: 52px; + padding: var(--sp-2) var(--sp-3); + text-align: left; + width: 100%; +} + +.gx-navigation-suggestion:hover, +.gx-navigation-suggestion:focus-visible { + background: var(--glass-active-bg); +} + +.gx-navigation-suggestion > span { + display: grid; + gap: 2px; + min-width: 0; +} + +.gx-navigation-suggestion strong, +.gx-navigation-suggestion small { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.gx-navigation-suggestion small { + color: var(--text-muted); +} + +.gx-navigation-summary { + margin: var(--sp-4) 0 0; + padding: var(--sp-3); +} + +.gx-navigation-summary__title { + background: var(--surface-container-high); + border-radius: var(--radius-md); + font-size: var(--fs-lg); + font-weight: var(--fw-bold); + overflow: hidden; + padding: var(--sp-2) var(--sp-3); + text-align: center; + text-overflow: ellipsis; + white-space: nowrap; +} + +.gx-navigation-summary__rows { + display: grid; + gap: var(--sp-1); + padding: var(--sp-3) var(--sp-2); +} + +.gx-navigation-summary__rows > div { + align-items: center; + display: grid; + gap: var(--sp-2); + grid-template-columns: 28px 90px 1fr; + min-height: 28px; +} + +.gx-navigation-summary__rows strong { + font-weight: var(--fw-bold); +} + +.gx-navigation-summary__icon { + font-size: 1.15rem; + text-align: center; +} + +.gx-navigation-summary__actions { + display: flex; + flex-wrap: wrap; + gap: var(--sp-2); + justify-content: center; +} + +.gx-navigation-summary__actions .gx-btn { + flex: 1 1 190px; + min-width: 0; +} + +.gx-btn--success { background: var(--success); color: var(--on-secondary); } +.gx-btn--success:hover { background: #6df3e9; } +.gx-btn--danger { background: var(--error); color: var(--on-error); } +.gx-btn--danger:hover { background: #ff7492; } +.gx-btn--favorite { background: var(--accent-rose); color: #fff; } +.gx-btn--favorite:hover, +.gx-btn--favorite.active { background: #ed4f94; } + +.gx-navigation-recent { + margin: var(--sp-4) 0 0; + padding: var(--sp-2); +} + +.gx-navigation-recent .gx-navigation-suggestion + .gx-navigation-suggestion { + border-top: 1px solid var(--outline); +} + +.gx-navigation-error { + color: var(--error); + margin: var(--sp-4) 0 0; + padding: var(--sp-3); +} + +.gx-navigation-empty { + align-items: center; + display: flex; + flex-direction: column; + gap: var(--sp-3); + justify-content: center; + margin: 0; + min-height: calc(100dvh - var(--appbar-height)); + padding: var(--sp-6); + text-align: center; +} + +.gx-navigation-empty p { + color: var(--text-muted); + margin: 0; +} + +.gx-navigation-tabs { + pointer-events: auto; + position: absolute; + right: var(--sp-4); + top: var(--sp-4); + z-index: 3; +} + +@media (max-width: 767px) { + .gx-navigation-view { + margin: calc(-1 * var(--sp-3)); + } + + .gx-navigation-overlay { + padding: var(--sp-3); + } + + .gx-navigation-tabs { + bottom: calc(var(--bottomnav-height) + var(--sp-3)); + left: var(--sp-3); + right: auto; + top: auto; + } + + .gx-navigation-summary__rows > div { + grid-template-columns: 28px 82px 1fr; + } +} + .gx-nav-section { margin-bottom: var(--sp-3); } .gx-nav-section__title { @@ -1868,6 +2200,7 @@ button.gx-chip:hover { .gx-back-btn { display: inline-flex; } .gx-appbar__search { flex: 1; min-width: 0; } .gx-status-pill { display: none; } + .gx-appbar .gx-appbar__pin { display: inline-flex; } .gx-content { padding-left: var(--sp-3); padding-right: var(--sp-3); } } diff --git a/starpilot/system/the_galaxy/assets/mobile/js/api.js b/starpilot/system/the_galaxy/assets/mobile/js/api.js index be5e5e6934..829e0de492 100644 --- a/starpilot/system/the_galaxy/assets/mobile/js/api.js +++ b/starpilot/system/the_galaxy/assets/mobile/js/api.js @@ -185,6 +185,7 @@ export const api = { getNavigation() { return request("/api/navigation") }, setNavigation(body) { return request("/api/navigation", { method: "POST", data: body }) }, + clearNavigation() { return request("/api/navigation", { method: "DELETE" }) }, getNavigationFavorites() { return request("/api/navigation/favorite", { cache: "no-store" }) }, mapboxSuggest(query, accessToken, sessionToken, context = {}) { const params = new URLSearchParams({ access_token: accessToken, session_token: sessionToken, q: query, limit: "4", ...context }) @@ -207,6 +208,7 @@ export const api = { getNavigationKeys() { return request("/api/navigation_key") }, setNavigationKey(body) { return request("/api/navigation_key", { method: "POST", data: body }) }, navigationFavorite(body) { return request("/api/navigation/favorite", { method: "POST", data: body }) }, + deleteNavigationFavorite(body) { return request("/api/navigation/favorite", { method: "DELETE", data: body }) }, deleteNavigationKey(type) { return request(`/api/navigation_key?type=${encodeURIComponent(type)}`, { method: "DELETE" }) }, async systemMonitor(signal) { diff --git a/starpilot/system/the_galaxy/assets/mobile/js/app.js b/starpilot/system/the_galaxy/assets/mobile/js/app.js index e246e00f7b..3710275dca 100644 --- a/starpilot/system/the_galaxy/assets/mobile/js/app.js +++ b/starpilot/system/the_galaxy/assets/mobile/js/app.js @@ -6,7 +6,7 @@ import { Tools } from "./views/Tools.js" import { Recordings } from "./views/Recordings.js" import { Logs } from "./views/Logs.js" import { Tuning } from "./views/Tuning.js" -import { Navigation } from "./views/Navigation.js?v=nav-destination-2" +import { Navigation } from "./views/Navigation.js?v=nav-destination-3" import { Vehicle } from "./views/Vehicle.js" import { Bluetooth } from "./views/Bluetooth.js" import { SystemTools } from "./views/SystemTools.js" @@ -22,6 +22,7 @@ import { ModelLaboratory } from "./views/ModelLaboratory.js" import { Cameras } from "./views/Cameras.js" import { store, initRouter, navigate } from "./store.js" import { showSnackbar } from "./api.js" +import { installDomTranslator } from "./i18n.js" window.__galaxyVue = { createApp, h } @@ -87,6 +88,7 @@ const app = createApp({ }) app.mount("#galaxy-app") +installDomTranslator(document.getElementById("galaxy-app")) initRouter() diff --git a/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js b/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js index 577c00fa99..013f5bde4e 100644 --- a/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js +++ b/starpilot/system/the_galaxy/assets/mobile/js/components/AppShell.js @@ -1,4 +1,4 @@ -import { store, navigate, goBack, toolHref, toggleTheme } from "../store.js" +import { store, navigate, goBack, toolHref, toggleTheme, toggleNavPinned } from "../store.js" import { api } from "../api.js" import { usePolling } from "../composables.js" import { languageState, setLanguage, t } from "../i18n.js" @@ -40,6 +40,7 @@ export const AppShell = { online() { return store.online }, statusLabel() { return store.online ? t(store.deviceStatus, store.deviceStatus) : t("Offline") }, isLight() { return store.theme === "light" }, + navPinned() { return store.navPinned }, drawerOpen: { get() { return store.drawerOpen }, set(v) { store.drawerOpen = v }, @@ -59,7 +60,7 @@ export const AppShell = { }, methods: { tr(key, fallback = key) { return t(key, fallback) }, - closeDrawer() { store.drawerOpen = false }, + closeDrawer() { if (!store.navPinned) store.drawerOpen = false }, back() { goBack() }, async refreshStatus() { try { @@ -84,6 +85,7 @@ export const AppShell = { this.$nextTick(() => { const el = this.$refs.searchInput; if (el) el.focus() }) }, themeToggle() { toggleTheme() }, + toggleNavPin() { toggleNavPinned() }, navTo(link) { this.closeDrawer() navigate(toolHref(link)) @@ -107,7 +109,7 @@ export const AppShell = { this.statusPoll?.destroy() }, template: ` -