#include "frogpilot/ui/qt/offroad/device_settings.h" FrogPilotDevicePanel::FrogPilotDevicePanel(FrogPilotSettingsWindow *parent, bool forceOpen) : FrogPilotListWidget(parent), parent(parent) { forceOpenDescriptions = forceOpen; QStackedLayout *deviceLayout = new QStackedLayout(); addItem(deviceLayout); FrogPilotListWidget *deviceList = new FrogPilotListWidget(this); ScrollView *devicePanel = new ScrollView(deviceList, this); deviceLayout->addWidget(devicePanel); FrogPilotListWidget *deviceManagementList = new FrogPilotListWidget(this); FrogPilotListWidget *screenList = new FrogPilotListWidget(this); ScrollView *deviceManagementPanel = new ScrollView(deviceManagementList, this); ScrollView *screenPanel = new ScrollView(screenList, this); deviceLayout->addWidget(deviceManagementPanel); deviceLayout->addWidget(screenPanel); const std::vector> deviceToggles { {"DeviceManagement", tr("Device Settings"), tr("Settings that control how the device runs, powers off, and manages driving data."), "../../frogpilot/assets/toggle_icons/icon_device.png"}, {"DeviceShutdown", tr("Device Shutdown Timer"), tr("Keep the device on for the set amount of time after a drive before it shuts down automatically."), ""}, {"NoLogging", tr("Disable Logging"), QString("%1

%2").arg(tr("WARNING: This will prevent your drives from being recorded and all data will be unobtainable!")).arg(tr("Prevent the device from saving driving data.")), ""}, {"NoUploads", tr("Disable Uploads"), QString("%1

%2").arg(tr("WARNING: This will prevent your drives from being uploaded to comma connect which will impact debugging and official support from comma!")).arg(tr("Prevent the device from uploading driving data.")), ""}, {"HigherBitrate", tr("High-Quality Recording"), tr("Save drive footage in higher video quality."), ""}, {"LowVoltageShutdown", tr("Low-Voltage Cutoff"), tr("While parked, if the battery voltage falls below the set level, the device shuts down to prevent excessive battery drain."), ""}, {"IncreaseThermalLimits", tr("Raise Temperature Limits"), QString("%1

%2").arg(tr("WARNING: Running at higher temperatures may damage your device!")).arg(tr("Allow the device to run at higher temperatures before throttling or shutting down. Use only if you understand the risks!")), ""}, {"ScreenManagement", tr("Screen Settings"), tr("Settings that control screen brightness, screen recording, and timeout duration."), "../../frogpilot/assets/toggle_icons/icon_light.png"}, {"ScreenBrightness", tr("Screen Brightness (Offroad)"), tr("The screen brightness while not driving."), ""}, {"ScreenBrightnessOnroad", tr("Screen Brightness (Onroad)"), tr("The screen brightness while driving."), ""}, {"ScreenRecorder", tr("Screen Recorder"), tr("Add a button to the driving screen to record the display."), ""}, {"ScreenTimeout", tr("Screen Timeout (Offroad)"), tr("How long the screen stays on after being tapped while not driving."), ""}, {"ScreenTimeoutOnroad", tr("Screen Timeout (Onroad)"), tr("How long the screen stays on after being tapped while driving."), ""}, {"StandbyMode", tr("Standby Mode"), tr("Turn the screen off while driving and automatically wake it up for alerts or engagement state changes."), ""}, {"IgnoreMe", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""}, {"IgnoreMe2", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""}, {"IgnoreMe3", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""}, {"IgnoreMe4", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""}, {"IgnoreMe5", "Ignore Me", "This is simply used to fix the layout when the user opens the descriptions and the menu gets wonky. No idea why it happens, but I can't be asked to properly fix it so whatever. Sue me.", ""} }; for (const auto &[param, title, desc, icon] : deviceToggles) { AbstractControl *deviceToggle; if (param == "DeviceManagement") { FrogPilotManageControl *deviceManagementToggle = new FrogPilotManageControl(param, title, desc, icon); QObject::connect(deviceManagementToggle, &FrogPilotManageControl::manageButtonClicked, [deviceLayout, deviceManagementPanel]() { deviceLayout->setCurrentWidget(deviceManagementPanel); }); deviceToggle = deviceManagementToggle; } else if (param == "DeviceShutdown") { std::map shutdownLabels; for (int i = 0; i <= 33; ++i) { shutdownLabels[i] = i == 0 ? tr("5 mins") : i <= 3 ? QString::number(i * 15) + tr(" mins") : QString::number(i - 3) + (i == 4 ? tr(" hour") : tr(" hours")); } deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, 0, 33, QString(), shutdownLabels); } else if (param == "NoUploads") { std::vector uploadsToggles{"DisableOnroadUploads"}; std::vector uploadsToggleNames{tr("Disable Onroad Only")}; deviceToggle = new FrogPilotButtonToggleControl(param, title, desc, icon, uploadsToggles, uploadsToggleNames); } else if (param == "LowVoltageShutdown") { deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, 11.8, 12.5, tr(" volts"), std::map(), 0.1); } else if (param == "ScreenManagement") { FrogPilotManageControl *screenToggle = new FrogPilotManageControl(param, title, desc, icon); QObject::connect(screenToggle, &FrogPilotManageControl::manageButtonClicked, [deviceLayout, screenPanel]() { deviceLayout->setCurrentWidget(screenPanel); }); deviceToggle = screenToggle; } else if (param == "ScreenBrightness" || param == "ScreenBrightnessOnroad") { std::map brightnessLabels; int minBrightness = (param == "ScreenBrightnessOnroad") ? 0 : 1; for (int i = 0; i <= 101; ++i) { brightnessLabels[i] = i == 0 ? tr("Screen Off") : i == 101 ? tr("Auto") : QString::number(i) + "%"; } deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, minBrightness, 101, QString(), brightnessLabels, 1, true); } else if (param == "ScreenTimeout" || param == "ScreenTimeoutOnroad") { deviceToggle = new FrogPilotParamValueControl(param, title, desc, icon, 5, 60, tr(" seconds"), {}, 5); } else { deviceToggle = new ParamControl(param, title, desc, icon); } toggles[param] = deviceToggle; if (deviceManagementKeys.contains(param)) { deviceManagementList->addItem(deviceToggle); } else if (screenKeys.contains(param)) { screenList->addItem(deviceToggle); } else { deviceList->addItem(deviceToggle); parentKeys.insert(param); } if (FrogPilotManageControl *frogPilotManageToggle = qobject_cast(deviceToggle)) { QObject::connect(frogPilotManageToggle, &FrogPilotManageControl::manageButtonClicked, [this]() { emit openSubPanel(); openDescriptions(forceOpenDescriptions, toggles); }); } QObject::connect(deviceToggle, &AbstractControl::hideDescriptionEvent, [this]() { update(); }); QObject::connect(deviceToggle, &AbstractControl::showDescriptionEvent, [this]() { update(); }); } static_cast(toggles["IncreaseThermalLimits"])->setConfirmation(true, false); static_cast(toggles["NoLogging"])->setConfirmation(true, false); static_cast(toggles["NoUploads"])->setConfirmation(true, false); QSet brightnessKeys = {"ScreenBrightness", "ScreenBrightnessOnroad"}; for (const QString &key : brightnessKeys) { FrogPilotParamValueControl *paramControl = static_cast(toggles[key]); QObject::connect(paramControl, &FrogPilotParamValueControl::valueChanged, [key, this](int value) { if (!started && key == "ScreenBrightness") { Hardware::set_brightness(value); } else if (started && key == "ScreenBrightnessOnroad") { Hardware::set_brightness(value); } }); } QSet forceUpdateKeys = {"NoUploads"}; for (const QString &key : forceUpdateKeys) { QObject::connect(static_cast(toggles[key]), &FrogPilotButtonToggleControl::buttonClicked, this, &FrogPilotDevicePanel::updateToggles); QObject::connect(static_cast(toggles[key]), &ToggleControl::toggleFlipped, this, &FrogPilotDevicePanel::updateToggles); } QSet rebootKeys = {"HigherBitrate"}; for (const QString &key : rebootKeys) { QObject::connect(static_cast(toggles[key]), &ToggleControl::toggleFlipped, [key, this](bool state) { QString filePath; if (key == "HigherBitrate") { filePath = "/cache/use_HD"; } if (!filePath.isEmpty()) { QFile toggleFile(filePath); if (state) { if (!toggleFile.exists()) { toggleFile.open(QIODevice::WriteOnly); toggleFile.close(); } } else { if (toggleFile.exists()) { toggleFile.remove(); } } } if (FrogPilotConfirmationDialog::toggleReboot(this)) { Hardware::reboot(); } }); } openDescriptions(forceOpenDescriptions, toggles); QObject::connect(parent, &FrogPilotSettingsWindow::closeSubPanel, [deviceLayout, devicePanel, this] { openDescriptions(forceOpenDescriptions, toggles); deviceLayout->setCurrentWidget(devicePanel); }); QObject::connect(uiState(), &UIState::uiUpdate, this, &FrogPilotDevicePanel::updateState); } void FrogPilotDevicePanel::showEvent(QShowEvent *event) { updateToggles(); } void FrogPilotDevicePanel::updateState(const UIState &s) { if (!isVisible()) { return; } started = s.scene.started; } void FrogPilotDevicePanel::updateToggles() { for (auto &[key, toggle] : toggles) { if (parentKeys.contains(key)) { toggle->setVisible(false); } } for (auto &[key, toggle] : toggles) { if (parentKeys.contains(key)) { continue; } bool setVisible = parent->tuningLevel >= parent->frogpilotToggleLevels[key].toDouble(); if (key == "HigherBitrate") { setVisible &= params.getBool("DeviceManagement") && params.getBool("NoUploads") && !params.getBool("DisableOnroadUploads"); } toggle->setVisible(setVisible); if (setVisible) { if (deviceManagementKeys.contains(key)) { toggles["DeviceManagement"]->setVisible(true); } else if (screenKeys.contains(key)) { toggles["ScreenManagement"]->setVisible(true); } } } openDescriptions(forceOpenDescriptions, toggles); update(); }