diff --git a/lib/I18n/translations/english.yaml b/lib/I18n/translations/english.yaml index a868933c..c30e04b0 100644 --- a/lib/I18n/translations/english.yaml +++ b/lib/I18n/translations/english.yaml @@ -110,6 +110,7 @@ STR_TIME_TO_SLEEP: "Time to Sleep" STR_SHOW_HIDDEN_FILES: "Show Hidden Files" STR_SHOW_FILE_EXTENSIONS: "Show File Extensions" STR_USE_CLOCK: "Use Clock" +STR_USE_WEATHER: "Use Weather" STR_CLOCK_SETTINGS: "Clock Settings" STR_CLOCK_SETTINGS_WARNING: "Uses more battery; clock may drift" STR_CLOCK: "Clock" @@ -379,6 +380,7 @@ STR_AUTO_TURN_ENABLED: "Auto Turn Enabled: " STR_AUTO_TURN_PAGES_PER_MIN: "Auto Turn (Pages Per Minute)" STR_WEATHER: "Weather" STR_WEATHER_LOCATION: "Location" +STR_WEATHER_UNITS: "Units" STR_WEATHER_NO_LOCATION: "No location set for weather" STR_WEATHER_FETCH_FAILED: "Failed to fetch weather" STR_WEATHER_SETTINGS: "Weather Settings" diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index 8a788d98..7334ca71 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -271,6 +271,8 @@ class CrossPointSettings { // Use clock and keep the LP timer running during deep sleep (GPIO13 HIGH) // so time can be accurately restored on wake. Increases sleep current by ~3-4 mA. uint8_t useClock = 0; + // Show the Weather home screen menu item (1 = enabled, 0 = hidden) + uint8_t useWeather = 1; ~CrossPointSettings() = default; diff --git a/src/SettingsList.h b/src/SettingsList.h index b7643590..f108e2ec 100644 --- a/src/SettingsList.h +++ b/src/SettingsList.h @@ -143,6 +143,7 @@ inline const std::vector list = { StrId::STR_TZ_EST, StrId::STR_TZ_CST, StrId::STR_TZ_MST, StrId::STR_TZ_PST}, "timeZone", StrId::STR_CAT_SYSTEM), SettingInfo::Toggle(StrId::STR_USE_CLOCK, &CrossPointSettings::useClock, "useClock", StrId::STR_CAT_SYSTEM), + SettingInfo::Toggle(StrId::STR_USE_WEATHER, &CrossPointSettings::useWeather, "useWeather", StrId::STR_CAT_SYSTEM), // --- KOReader Sync (web-only, uses KOReaderCredentialStore) --- SettingInfo::DynamicString( diff --git a/src/activities/home/HomeActivity.cpp b/src/activities/home/HomeActivity.cpp index f3bade9c..a010c778 100644 --- a/src/activities/home/HomeActivity.cpp +++ b/src/activities/home/HomeActivity.cpp @@ -100,7 +100,10 @@ int getHomeCoverRenderHeight(const HomeScreenLayout& layout) { } // namespace int HomeActivity::getMenuItemCount() const { - int count = 5; // File Browser, Recents, File transfer, Weather, Settings + int count = 4; // File Browser, Recents, File transfer, Settings + if (SETTINGS.useWeather) { + count++; + } if (!recentBooks.empty()) { count += recentBooks.size(); } @@ -283,12 +286,13 @@ void HomeActivity::loop() { int idx = 0; int menuSelectedIndex = selectorIndex - static_cast(recentBooks.size()); const bool hasGlobalBookmarks = !GLOBAL_BOOKMARKS.isEmpty(); + const bool hasWeather = SETTINGS.useWeather; const int fileBrowserIdx = idx++; const int recentsIdx = idx++; const int globalBookmarksIdx = hasGlobalBookmarks ? idx++ : -1; const int opdsLibraryIdx = hasOpdsUrl ? idx++ : -1; const int fileTransferIdx = idx++; - const int weatherIdx = idx++; + const int weatherIdx = hasWeather ? idx++ : -1; const int settingsIdx = idx; if (selectorIndex < recentBooks.size()) { @@ -321,9 +325,17 @@ void HomeActivity::render(RenderLock&&) { GUI.drawHeader(renderer, Rect{contentRect.x, metrics.topPadding, contentRect.width, metrics.homeTopPadding}, nullptr); // Build menu items dynamically + const char* weatherMenuLabel = SETTINGS.useWeather ? tr(STR_WEATHER) : tr(STR_SETTINGS_TITLE); + const UIIcon weatherMenuIcon = SETTINGS.useWeather ? Weather : Settings; + std::vector menuItems = {tr(STR_BROWSE_FILES), tr(STR_MENU_RECENT_BOOKS), tr(STR_FILE_TRANSFER), - tr(STR_WEATHER), tr(STR_SETTINGS_TITLE)}; - std::vector menuIcons = {Folder, Recent, Transfer, Weather, Settings}; + weatherMenuLabel, tr(STR_SETTINGS_TITLE)}; + std::vector menuIcons = {Folder, Recent, Transfer, weatherMenuIcon, Settings}; + + if (!SETTINGS.useWeather) { + menuItems.erase(menuItems.begin() + 3); + menuIcons.erase(menuIcons.begin() + 3); + } int insertAfterRecents = 2; if (!GLOBAL_BOOKMARKS.isEmpty()) { diff --git a/src/activities/settings/ClockSettingsActivity.cpp b/src/activities/settings/ClockSettingsActivity.cpp index 0137b77a..854b2347 100644 --- a/src/activities/settings/ClockSettingsActivity.cpp +++ b/src/activities/settings/ClockSettingsActivity.cpp @@ -6,7 +6,6 @@ #include "CrossPointSettings.h" #include "DetectTimezoneActivity.h" -#include "MappedInputManager.h" #include "SyncTimeActivity.h" #include "components/UITheme.h" #include "fontIds.h" @@ -19,94 +18,48 @@ const StrId timeZoneNames[CrossPointSettings::TIMEZONE_COUNT] = { StrId::STR_TZ_EST, StrId::STR_TZ_CST, StrId::STR_TZ_MST, StrId::STR_TZ_PST}; } // namespace -std::string ClockSettingsActivity::MenuItem::getTitle() const { - const auto t = I18N.get(labelId); - return isSeparator ? UITheme::makeSeparatorTitle(t) : t; +void ClockSettingsActivity::buildMenuItems() { + menuItems.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_TITLE)); + menuItems.push_back( + SettingInfo::Toggle(StrId::STR_USE_CLOCK, &CrossPointSettings::useClock, "useClock", StrId::STR_CAT_SYSTEM)); + menuItems.push_back(SettingInfo::Enum(StrId::STR_CLOCK_FORMAT, &CrossPointSettings::clockFormat12h, + {StrId::STR_24H, StrId::STR_12H}, "clockFormat12h", StrId::STR_CAT_SYSTEM)); + menuItems.push_back( + SettingInfo::Enum(StrId::STR_TIMEZONE, &CrossPointSettings::timeZone, + {StrId::STR_TZ_UTC, StrId::STR_TZ_CET, StrId::STR_TZ_EET, StrId::STR_TZ_MSK, + StrId::STR_TZ_UTC_PLUS4, StrId::STR_TZ_IST, StrId::STR_TZ_UTC_PLUS7, StrId::STR_TZ_UTC_PLUS8, + StrId::STR_TZ_UTC_PLUS9, StrId::STR_TZ_AEST, StrId::STR_TZ_NZST, StrId::STR_TZ_UTC_MINUS3, + StrId::STR_TZ_EST, StrId::STR_TZ_CST, StrId::STR_TZ_MST, StrId::STR_TZ_PST}, + "timeZone", StrId::STR_CAT_SYSTEM)); + + menuItems.push_back(SettingInfo::Action(StrId::STR_DETECT_TIMEZONE, SettingAction::DetectTimezone) + .withSubcategory(StrId::STR_READER_TOOLS)); + menuItems.push_back(SettingInfo::Action(StrId::STR_SYNC_TIME, SettingAction::SyncTime)); } -std::vector ClockSettingsActivity::buildMenuItems() { - std::vector items; - items.reserve(7); - // Settings - items.push_back(MenuItem::separator(StrId::STR_SETTINGS_TITLE)); - items.push_back({Action::USE_CLOCK, StrId::STR_USE_CLOCK}); - items.push_back({Action::CLOCK_FORMAT, StrId::STR_CLOCK_FORMAT}); - items.push_back({Action::TIMEZONE, StrId::STR_TIMEZONE}); - - // Tools - items.push_back(MenuItem::separator(StrId::STR_READER_TOOLS)); - items.push_back({Action::DETECT_TIMEZONE, StrId::STR_DETECT_TIMEZONE}); - items.push_back({Action::SYNC_TIME, StrId::STR_SYNC_TIME}); - return items; -} - -void ClockSettingsActivity::onEnter() { - Activity::onEnter(); - const auto pred = UITheme::makeSelectablePredicate(static_cast(menuItems.size()), - [this](int i) { return menuItems[i].getTitle(); }); - buttonNavigator.setSelectablePredicate(pred, static_cast(menuItems.size())); - if (!pred(selectedIndex)) { - selectedIndex = buttonNavigator.nextIndex(selectedIndex); +void ClockSettingsActivity::onActionSelected(int index) { + const auto& item = menuItems[index]; + if (item.nameId == StrId::STR_DETECT_TIMEZONE) { + auto resultHandler = [](const ActivityResult&) { SETTINGS.saveToFile(); }; + startActivityForResult(std::make_unique(renderer, mappedInput), resultHandler); + } else if (item.nameId == StrId::STR_SYNC_TIME) { + auto resultHandler = [](const ActivityResult&) { SETTINGS.saveToFile(); }; + startActivityForResult(std::make_unique(renderer, mappedInput), resultHandler); } - requestUpdate(); } -void ClockSettingsActivity::onExit() { Activity::onExit(); } - -void ClockSettingsActivity::loop() { - if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { - finish(); - return; - } - - if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { - handleSelection(); - requestUpdate(); - return; - } - - buttonNavigator.onNextRelease([this] { - selectedIndex = buttonNavigator.nextIndex(selectedIndex); - requestUpdate(); - }); - - buttonNavigator.onPreviousRelease([this] { - selectedIndex = buttonNavigator.previousIndex(selectedIndex); - requestUpdate(); - }); - - buttonNavigator.onNextContinuous([this] { - selectedIndex = buttonNavigator.nextIndex(selectedIndex); - requestUpdate(); - }); - - buttonNavigator.onPreviousContinuous([this] { - selectedIndex = buttonNavigator.previousIndex(selectedIndex); - requestUpdate(); - }); -} - -void ClockSettingsActivity::handleSelection() { - const auto action = menuItems[selectedIndex].action; - if (action == Action::USE_CLOCK) { - SETTINGS.useClock = (SETTINGS.useClock + 1) % 2; +void ClockSettingsActivity::onSettingToggled(int index) { + const auto& item = menuItems[index]; + if (item.nameId == StrId::STR_USE_CLOCK) { if (!SETTINGS.useClock) { SETTINGS.statusBarClock = 0; } SETTINGS.saveToFile(); - } else if (action == Action::CLOCK_FORMAT) { - SETTINGS.clockFormat12h = (SETTINGS.clockFormat12h + 1) % 2; - SETTINGS.saveToFile(); - } else if (action == Action::TIMEZONE) { - SETTINGS.timeZone = (SETTINGS.timeZone + 1) % CrossPointSettings::TIMEZONE_COUNT; + } else if (item.nameId == StrId::STR_TIMEZONE) { HalClock::applyTimezone(SETTINGS.timeZone); SETTINGS.saveToFile(); - } else if (action == Action::SYNC_TIME) { - auto resultHandler = [](const ActivityResult&) { SETTINGS.saveToFile(); }; - startActivityForResult(std::make_unique(renderer, mappedInput), resultHandler); - } else if (action == Action::DETECT_TIMEZONE) { - auto resultHandler = [](const ActivityResult&) { SETTINGS.saveToFile(); }; - startActivityForResult(std::make_unique(renderer, mappedInput), resultHandler); + } else if (item.nameId == StrId::STR_CLOCK_FORMAT) { + SETTINGS.saveToFile(); } } @@ -129,28 +82,7 @@ void ClockSettingsActivity::render(RenderLock&&) { const int contentHeight = contentRect.height - (metrics.topPadding + metrics.headerHeight + metrics.tabBarHeight + metrics.verticalSpacing * 2); - GUI.drawList( - renderer, Rect(contentRect.x, contentTop, contentRect.width, contentHeight), static_cast(menuItems.size()), - selectedIndex, [this](int index) { return menuItems[index].getTitle(); }, nullptr, nullptr, - [this](int index) { - const auto action = menuItems[index].action; - switch (action) { - case Action::USE_CLOCK: - return std::string(SETTINGS.useClock ? tr(STR_STATE_ON) : tr(STR_STATE_OFF)); - case Action::CLOCK_FORMAT: - return std::string(SETTINGS.clockFormat12h ? tr(STR_12H) : tr(STR_24H)); - case Action::TIMEZONE: { - const auto tzIndex = static_cast(SETTINGS.timeZone); - if (tzIndex < (sizeof(timeZoneNames) / sizeof(timeZoneNames[0]))) { - return std::string(I18N.get(timeZoneNames[tzIndex])); - } - return std::string(tr(STR_TZ_UTC)); - } - default: - return std::string(""); - } - }, - true); + drawMenuList(Rect{contentRect.x, contentTop, contentRect.width, contentHeight}); const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/settings/ClockSettingsActivity.h b/src/activities/settings/ClockSettingsActivity.h index 54a4196b..0486014b 100644 --- a/src/activities/settings/ClockSettingsActivity.h +++ b/src/activities/settings/ClockSettingsActivity.h @@ -1,35 +1,18 @@ #pragma once -#include -#include -#include - -#include "activities/Activity.h" -#include "util/ButtonNavigator.h" - -class ClockSettingsActivity final : public Activity { - enum class Action { USE_CLOCK, CLOCK_FORMAT, TIMEZONE, SYNC_TIME, DETECT_TIMEZONE, NONE }; - - struct MenuItem { - Action action; - StrId labelId; - bool isSeparator = false; - static MenuItem separator(StrId label) { return {Action::NONE, label, true}; } - [[nodiscard]] std::string getTitle() const; - }; - - ButtonNavigator buttonNavigator; - int selectedIndex = 0; - const std::vector menuItems; - - static std::vector buildMenuItems(); - void handleSelection(); +#include "../MenuListActivity.h" +class ClockSettingsActivity final : public MenuListActivity { public: explicit ClockSettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) - : Activity("ClockSettings", renderer, mappedInput), menuItems(buildMenuItems()) {} - void onEnter() override; - void onExit() override; - void loop() override; + : MenuListActivity("ClockSettings", renderer, mappedInput) { + buildMenuItems(); + } + void render(RenderLock&&) override; + + private: + void buildMenuItems(); + void onActionSelected(int index) override; + void onSettingToggled(int index) override; }; diff --git a/src/activities/weather/WeatherSettingsActivity.cpp b/src/activities/weather/WeatherSettingsActivity.cpp index b3b69664..32e938a4 100644 --- a/src/activities/weather/WeatherSettingsActivity.cpp +++ b/src/activities/weather/WeatherSettingsActivity.cpp @@ -13,29 +13,29 @@ #include "components/UITheme.h" #include "fontIds.h" -namespace { -const StrId menuNames[] = { - StrId::STR_WEATHER_LOCATION, // 0: Search city - StrId::STR_WEATHER_LATITUDE, // 1: Manual latitude - StrId::STR_WEATHER_LONGITUDE, // 2: Manual longitude - StrId::STR_WEATHER_TEMP_UNIT, // 3: Temperature unit - StrId::STR_WEATHER_WIND_UNIT, // 4: Wind speed unit - StrId::STR_WEATHER_PRECIP_UNIT, // 5: Precipitation unit -}; -} // namespace +void WeatherSettingsActivity::buildMenuItems() { + menuItems.push_back(SettingInfo::Separator(StrId::STR_SETTINGS_TITLE)); + menuItems.push_back(SettingInfo::Toggle(StrId::STR_USE_WEATHER, &CrossPointSettings::useWeather, "useWeather", + StrId::STR_CAT_SYSTEM)); -void WeatherSettingsActivity::onEnter() { - Activity::onEnter(); - selectedIndex = 0; - showingSearchResults = false; - requestUpdate(); + menuItems.push_back(SettingInfo::Separator(StrId::STR_WEATHER_LOCATION)); + menuItems.push_back(SettingInfo::Action(StrId::STR_WEATHER_LOCATION, SettingAction::None)); + menuItems.push_back(SettingInfo::Action(StrId::STR_WEATHER_LATITUDE, SettingAction::None)); + menuItems.push_back(SettingInfo::Action(StrId::STR_WEATHER_LONGITUDE, SettingAction::None)); + + menuItems.push_back(SettingInfo::Separator(StrId::STR_WEATHER_UNITS)); + menuItems.push_back(SettingInfo::Action(StrId::STR_WEATHER_TEMP_UNIT, SettingAction::None)); + menuItems.push_back(SettingInfo::Action(StrId::STR_WEATHER_WIND_UNIT, SettingAction::None)); + menuItems.push_back(SettingInfo::Action(StrId::STR_WEATHER_PRECIP_UNIT, SettingAction::None)); } -void WeatherSettingsActivity::onExit() { Activity::onExit(); } +void WeatherSettingsActivity::onEnter() { + MenuListActivity::onEnter(); + showingSearchResults = false; +} void WeatherSettingsActivity::loop() { if (showingSearchResults) { - // Handle search results navigation if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { showingSearchResults = false; requestUpdate(); @@ -43,7 +43,7 @@ void WeatherSettingsActivity::loop() { } if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { - if (!searchResults.empty() && selectedIndex < searchResults.size()) { + if (!searchResults.empty() && selectedIndex < static_cast(searchResults.size())) { const auto& result = searchResults[selectedIndex]; WEATHER_SETTINGS.setLocation(result.latitude, result.longitude, result.name + ", " + result.country); WEATHER_SETTINGS.saveToFile(); @@ -69,50 +69,89 @@ void WeatherSettingsActivity::loop() { return; } - if (mappedInput.wasPressed(MappedInputManager::Button::Back)) { - finish(); - return; - } - - if (mappedInput.wasPressed(MappedInputManager::Button::Confirm)) { - handleSelection(); - return; - } - - buttonNavigator.onNext([this] { - selectedIndex = (selectedIndex + 1) % MENU_ITEMS; - requestUpdate(); - }); - - buttonNavigator.onPrevious([this] { - selectedIndex = (selectedIndex + MENU_ITEMS - 1) % MENU_ITEMS; - requestUpdate(); - }); + MenuListActivity::loop(); } -void WeatherSettingsActivity::handleSelection() { - switch (selectedIndex) { - case 0: - launchCitySearch(); - break; - case 1: - launchLatitudeEntry(); - break; - case 2: - launchLongitudeEntry(); - break; - case 3: - toggleTempUnit(); - break; - case 4: - toggleWindUnit(); - break; - case 5: - togglePrecipUnit(); - break; +std::string WeatherSettingsActivity::getItemValueString(int index) const { + const auto& item = menuItems[index]; + switch (item.nameId) { + case StrId::STR_WEATHER_LOCATION: { + auto name = WEATHER_SETTINGS.getLocationName(); + return name.empty() ? std::string(tr(STR_NOT_SET)) : name; + } + case StrId::STR_WEATHER_LATITUDE: { + char buf[16]; + snprintf(buf, sizeof(buf), "%.4f", WEATHER_SETTINGS.getLatitude()); + return std::string(buf); + } + case StrId::STR_WEATHER_LONGITUDE: { + char buf[16]; + snprintf(buf, sizeof(buf), "%.4f", WEATHER_SETTINGS.getLongitude()); + return std::string(buf); + } + case StrId::STR_WEATHER_TEMP_UNIT: + return WEATHER_SETTINGS.getTempUnit() == WeatherTempUnit::CELSIUS ? "C" : "F"; + case StrId::STR_WEATHER_WIND_UNIT: + switch (WEATHER_SETTINGS.getWindUnit()) { + case WeatherWindUnit::KMH: + return "km/h"; + case WeatherWindUnit::MS: + return "m/s"; + case WeatherWindUnit::MPH: + return "mph"; + case WeatherWindUnit::KNOTS: + return "kn"; + } + return "km/h"; + case StrId::STR_WEATHER_PRECIP_UNIT: + return WEATHER_SETTINGS.getPrecipUnit() == WeatherPrecipUnit::MM ? "mm" : "in"; + default: + return MenuListActivity::getItemValueString(index); } } +void WeatherSettingsActivity::onActionSelected(int index) { + const auto& item = menuItems[index]; + if (item.nameId == StrId::STR_WEATHER_LOCATION) { + launchCitySearch(); + } else if (item.nameId == StrId::STR_WEATHER_LATITUDE) { + launchLatitudeEntry(); + } else if (item.nameId == StrId::STR_WEATHER_LONGITUDE) { + launchLongitudeEntry(); + } else if (item.nameId == StrId::STR_WEATHER_TEMP_UNIT) { + auto current = WEATHER_SETTINGS.getTempUnit(); + WEATHER_SETTINGS.setTempUnit(current == WeatherTempUnit::CELSIUS ? WeatherTempUnit::FAHRENHEIT + : WeatherTempUnit::CELSIUS); + WEATHER_SETTINGS.saveToFile(); + requestUpdate(); + } else if (item.nameId == StrId::STR_WEATHER_WIND_UNIT) { + auto current = static_cast(WEATHER_SETTINGS.getWindUnit()); + WEATHER_SETTINGS.setWindUnit(static_cast((current + 1) % 4)); + WEATHER_SETTINGS.saveToFile(); + requestUpdate(); + } else if (item.nameId == StrId::STR_WEATHER_PRECIP_UNIT) { + auto current = WEATHER_SETTINGS.getPrecipUnit(); + WEATHER_SETTINGS.setPrecipUnit(current == WeatherPrecipUnit::MM ? WeatherPrecipUnit::INCH : WeatherPrecipUnit::MM); + WEATHER_SETTINGS.saveToFile(); + requestUpdate(); + } +} + +void WeatherSettingsActivity::onSettingToggled(int index) { + if (menuItems[index].nameId == StrId::STR_USE_WEATHER) { + SETTINGS.saveToFile(); + } +} + +void WeatherSettingsActivity::onBackPressed() { + if (showingSearchResults) { + showingSearchResults = false; + requestUpdate(); + return; + } + finish(); +} + void WeatherSettingsActivity::launchCitySearch() { startActivityForResult(std::make_unique(renderer, mappedInput, tr(STR_WEATHER_SEARCH_CITY), "", 64, InputType::Text), @@ -122,7 +161,6 @@ void WeatherSettingsActivity::launchCitySearch() { const auto& kb = std::get(result.data); if (kb.text.empty()) return; - // Need WiFi for geocoding if (WiFi.status() != WL_CONNECTED || WiFi.localIP() == IPAddress(0, 0, 0, 0)) { startActivityForResult(std::make_unique(renderer, mappedInput), [this, query = kb.text](const ActivityResult& wifiResult) { @@ -181,28 +219,6 @@ void WeatherSettingsActivity::launchLongitudeEntry() { }); } -void WeatherSettingsActivity::toggleTempUnit() { - auto current = WEATHER_SETTINGS.getTempUnit(); - WEATHER_SETTINGS.setTempUnit(current == WeatherTempUnit::CELSIUS ? WeatherTempUnit::FAHRENHEIT - : WeatherTempUnit::CELSIUS); - WEATHER_SETTINGS.saveToFile(); - requestUpdate(); -} - -void WeatherSettingsActivity::toggleWindUnit() { - auto current = static_cast(WEATHER_SETTINGS.getWindUnit()); - WEATHER_SETTINGS.setWindUnit(static_cast((current + 1) % 4)); - WEATHER_SETTINGS.saveToFile(); - requestUpdate(); -} - -void WeatherSettingsActivity::togglePrecipUnit() { - auto current = WEATHER_SETTINGS.getPrecipUnit(); - WEATHER_SETTINGS.setPrecipUnit(current == WeatherPrecipUnit::MM ? WeatherPrecipUnit::INCH : WeatherPrecipUnit::MM); - WEATHER_SETTINGS.saveToFile(); - requestUpdate(); -} - void WeatherSettingsActivity::render(RenderLock&&) { renderer.clearScreen(); @@ -210,7 +226,6 @@ void WeatherSettingsActivity::render(RenderLock&&) { const Rect contentRect = UITheme::getContentRect(renderer, true, false); if (showingSearchResults) { - // Display search results GUI.drawHeader(renderer, Rect(contentRect.x, contentRect.y + metrics.topPadding, contentRect.width, metrics.headerHeight), tr(STR_WEATHER_SEARCH_RESULTS)); @@ -241,7 +256,6 @@ void WeatherSettingsActivity::render(RenderLock&&) { return; } - // Main settings menu GUI.drawHeader(renderer, Rect(contentRect.x, contentRect.y + metrics.topPadding, contentRect.width, metrics.headerHeight), tr(STR_WEATHER_SETTINGS)); @@ -250,46 +264,7 @@ void WeatherSettingsActivity::render(RenderLock&&) { const int contentHeight = contentRect.height - (metrics.topPadding + metrics.headerHeight + metrics.verticalSpacing * 2); - GUI.drawList( - renderer, Rect(contentRect.x, contentTop, contentRect.width, contentHeight), MENU_ITEMS, - static_cast(selectedIndex), [](int index) { return std::string(I18N.get(menuNames[index])); }, nullptr, - nullptr, - [this](int index) -> std::string { - switch (index) { - case 0: { - auto name = WEATHER_SETTINGS.getLocationName(); - return name.empty() ? std::string(tr(STR_NOT_SET)) : name; - } - case 1: { - char buf[16]; - snprintf(buf, sizeof(buf), "%.4f", WEATHER_SETTINGS.getLatitude()); - return std::string(buf); - } - case 2: { - char buf[16]; - snprintf(buf, sizeof(buf), "%.4f", WEATHER_SETTINGS.getLongitude()); - return std::string(buf); - } - case 3: - return WEATHER_SETTINGS.getTempUnit() == WeatherTempUnit::CELSIUS ? "C" : "F"; - case 4: - switch (WEATHER_SETTINGS.getWindUnit()) { - case WeatherWindUnit::KMH: - return "km/h"; - case WeatherWindUnit::MS: - return "m/s"; - case WeatherWindUnit::MPH: - return "mph"; - case WeatherWindUnit::KNOTS: - return "kn"; - } - return "km/h"; - case 5: - return WEATHER_SETTINGS.getPrecipUnit() == WeatherPrecipUnit::MM ? "mm" : "in"; - } - return ""; - }, - true); + drawMenuList(Rect{contentRect.x, contentTop, contentRect.width, contentHeight}); const auto labels = mappedInput.mapLabels(tr(STR_BACK), tr(STR_SELECT), tr(STR_DIR_UP), tr(STR_DIR_DOWN)); GUI.drawButtonHints(renderer, labels.btn1, labels.btn2, labels.btn3, labels.btn4); diff --git a/src/activities/weather/WeatherSettingsActivity.h b/src/activities/weather/WeatherSettingsActivity.h index b112c315..b83fd22e 100644 --- a/src/activities/weather/WeatherSettingsActivity.h +++ b/src/activities/weather/WeatherSettingsActivity.h @@ -5,42 +5,35 @@ #include #include -#include "../Activity.h" -#include "util/ButtonNavigator.h" +#include "../MenuListActivity.h" /** * Settings submenu for weather configuration. * Supports city search via geocoding, manual lat/lon entry, and unit selection. */ -class WeatherSettingsActivity final : public Activity { +class WeatherSettingsActivity final : public MenuListActivity { public: explicit WeatherSettingsActivity(GfxRenderer& renderer, MappedInputManager& mappedInput) - : Activity("WeatherSettings", renderer, mappedInput) {} + : MenuListActivity("WeatherSettings", renderer, mappedInput) { + buildMenuItems(); + } void onEnter() override; - void onExit() override; void loop() override; void render(RenderLock&&) override; private: - ButtonNavigator buttonNavigator; - int selectedIndex = 0; - - // City search results (populated when user searches) std::vector searchResults; bool showingSearchResults = false; - bool searchInProgress = false; std::string searchQuery; - static constexpr int MENU_ITEMS = 6; // Location, Lat, Lon, TempUnit, WindUnit, PrecipUnit + void buildMenuItems(); + void onActionSelected(int index) override; + std::string getItemValueString(int index) const override; + void onBackPressed() override; + void onSettingToggled(int index) override; - void handleSelection(); void launchCitySearch(); void launchLatitudeEntry(); void launchLongitudeEntry(); - void toggleTempUnit(); - void toggleWindUnit(); - void togglePrecipUnit(); - - bool preventAutoSleep() override { return true; } };