mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-16 03:37:59 +01:00
<!-- Enter a brief description/summary of your PR here. What does it fix/what does it change/how was it tested (even manually, if necessary)? --> ## Summary of the Pull Request This PR introduces new UI to allow the users to manually enter their lat/long. <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [x] Closes: #42429 - [x] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [x] **Localization:** All end-user-facing strings can be localized - [x] **Documentation updated:** If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys) and link it here: #[5979](https://github.com/MicrosoftDocs/windows-dev-docs-pr/pull/5979) --------- Co-authored-by: Niels Laute <niels.laute@live.nl>
250 lines
6.9 KiB
C++
250 lines
6.9 KiB
C++
#include "LightSwitchSettings.h"
|
|
#include <common/utils/json.h>
|
|
#include <common/SettingsAPI/settings_helpers.h>
|
|
#include "SettingsObserver.h"
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <logger.h>
|
|
|
|
using namespace std;
|
|
|
|
LightSwitchSettings& LightSwitchSettings::instance()
|
|
{
|
|
static LightSwitchSettings inst;
|
|
return inst;
|
|
}
|
|
|
|
LightSwitchSettings::LightSwitchSettings()
|
|
{
|
|
LoadSettings();
|
|
}
|
|
|
|
std::wstring LightSwitchSettings::GetSettingsFileName()
|
|
{
|
|
return PTSettingsHelper::get_module_save_file_location(L"LightSwitch");
|
|
}
|
|
|
|
void LightSwitchSettings::InitFileWatcher()
|
|
{
|
|
if (!m_settingsChangedEvent)
|
|
{
|
|
m_settingsChangedEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr);
|
|
}
|
|
|
|
if (!m_settingsFileWatcher)
|
|
{
|
|
m_settingsFileWatcher = std::make_unique<FileWatcher>(
|
|
GetSettingsFileName(),
|
|
[this]() {
|
|
using namespace std::chrono;
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_debounceMutex);
|
|
m_lastChangeTime = steady_clock::now();
|
|
if (m_debouncePending)
|
|
return;
|
|
m_debouncePending = true;
|
|
}
|
|
|
|
m_debounceThread = std::jthread([this](std::stop_token stop) {
|
|
using namespace std::chrono;
|
|
while (!stop.stop_requested())
|
|
{
|
|
std::this_thread::sleep_for(seconds(3));
|
|
|
|
auto elapsed = steady_clock::now() - m_lastChangeTime;
|
|
if (elapsed >= seconds(1))
|
|
break;
|
|
}
|
|
|
|
{
|
|
std::lock_guard<std::mutex> lock(m_debounceMutex);
|
|
m_debouncePending = false;
|
|
}
|
|
|
|
Logger::info(L"[LightSwitchSettings] Settings file stabilized, reloading.");
|
|
|
|
try
|
|
{
|
|
LoadSettings();
|
|
SetEvent(m_settingsChangedEvent);
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::wstring wmsg;
|
|
wmsg.assign(e.what(), e.what() + strlen(e.what()));
|
|
Logger::error(L"[LightSwitchSettings] Exception during debounced reload: {}", wmsg);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
LightSwitchSettings::~LightSwitchSettings()
|
|
{
|
|
Logger::info(L"[LightSwitchSettings] Cleaning up settings resources...");
|
|
|
|
// Stop and join the debounce thread (std::jthread auto-joins, but we can signal stop too)
|
|
if (m_debounceThread.joinable())
|
|
{
|
|
m_debounceThread.request_stop();
|
|
}
|
|
|
|
// Release the file watcher so it closes file handles and background threads
|
|
if (m_settingsFileWatcher)
|
|
{
|
|
m_settingsFileWatcher.reset();
|
|
Logger::info(L"[LightSwitchSettings] File watcher stopped.");
|
|
}
|
|
|
|
// Close the Windows event handle
|
|
if (m_settingsChangedEvent)
|
|
{
|
|
CloseHandle(m_settingsChangedEvent);
|
|
m_settingsChangedEvent = nullptr;
|
|
Logger::info(L"[LightSwitchSettings] Settings changed event closed.");
|
|
}
|
|
|
|
Logger::info(L"[LightSwitchSettings] Cleanup complete.");
|
|
}
|
|
|
|
|
|
void LightSwitchSettings::AddObserver(SettingsObserver& observer)
|
|
{
|
|
m_observers.insert(&observer);
|
|
}
|
|
|
|
void LightSwitchSettings::RemoveObserver(SettingsObserver& observer)
|
|
{
|
|
m_observers.erase(&observer);
|
|
}
|
|
|
|
void LightSwitchSettings::NotifyObservers(SettingId id) const
|
|
{
|
|
for (auto observer : m_observers)
|
|
{
|
|
if (observer->WantsToBeNotified(id))
|
|
{
|
|
observer->SettingsUpdate(id);
|
|
}
|
|
}
|
|
}
|
|
|
|
HANDLE LightSwitchSettings::GetSettingsChangedEvent() const
|
|
{
|
|
return m_settingsChangedEvent;
|
|
}
|
|
|
|
void LightSwitchSettings::LoadSettings()
|
|
{
|
|
std::lock_guard<std::mutex> guard(m_settingsMutex);
|
|
try
|
|
{
|
|
PowerToysSettings::PowerToyValues values =
|
|
PowerToysSettings::PowerToyValues::load_from_settings_file(L"LightSwitch");
|
|
|
|
|
|
if (const auto jsonVal = values.get_string_value(L"scheduleMode"))
|
|
{
|
|
auto val = *jsonVal;
|
|
auto newMode = FromString(val);
|
|
if (m_settings.scheduleMode != newMode)
|
|
{
|
|
m_settings.scheduleMode = newMode;
|
|
NotifyObservers(SettingId::ScheduleMode);
|
|
}
|
|
}
|
|
|
|
// Latitude
|
|
if (const auto jsonVal = values.get_string_value(L"latitude"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.latitude != val)
|
|
{
|
|
m_settings.latitude = val;
|
|
NotifyObservers(SettingId::Latitude);
|
|
}
|
|
}
|
|
|
|
// Longitude
|
|
if (const auto jsonVal = values.get_string_value(L"longitude"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.longitude != val)
|
|
{
|
|
m_settings.longitude = val;
|
|
NotifyObservers(SettingId::Longitude);
|
|
}
|
|
}
|
|
|
|
// LightTime
|
|
if (const auto jsonVal = values.get_int_value(L"lightTime"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.lightTime != val)
|
|
{
|
|
m_settings.lightTime = val;
|
|
NotifyObservers(SettingId::LightTime);
|
|
}
|
|
}
|
|
|
|
// DarkTime
|
|
if (const auto jsonVal = values.get_int_value(L"darkTime"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.darkTime != val)
|
|
{
|
|
m_settings.darkTime = val;
|
|
NotifyObservers(SettingId::DarkTime);
|
|
}
|
|
}
|
|
|
|
// Offset
|
|
if (const auto jsonVal = values.get_int_value(L"sunrise_offset"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.sunrise_offset != val)
|
|
{
|
|
m_settings.sunrise_offset = val;
|
|
NotifyObservers(SettingId::Sunrise_Offset);
|
|
}
|
|
}
|
|
|
|
if (const auto jsonVal = values.get_int_value(L"sunset_offset"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.sunset_offset != val)
|
|
{
|
|
m_settings.sunset_offset = val;
|
|
NotifyObservers(SettingId::Sunset_Offset);
|
|
}
|
|
}
|
|
|
|
// ChangeSystem
|
|
if (const auto jsonVal = values.get_bool_value(L"changeSystem"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.changeSystem != val)
|
|
{
|
|
m_settings.changeSystem = val;
|
|
NotifyObservers(SettingId::ChangeSystem);
|
|
}
|
|
}
|
|
|
|
// ChangeApps
|
|
if (const auto jsonVal = values.get_bool_value(L"changeApps"))
|
|
{
|
|
auto val = *jsonVal;
|
|
if (m_settings.changeApps != val)
|
|
{
|
|
m_settings.changeApps = val;
|
|
NotifyObservers(SettingId::ChangeApps);
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
// Keeps defaults if load fails
|
|
}
|
|
}
|