Skip to content

Add decky-time-changer plugin - #1144

Closed
nanwangjkl wants to merge 8 commits into
SteamDeckHomebrew:mainfrom
nanwangjkl:add/decky-time-changer
Closed

nanwangjkl wants to merge 8 commits into
SteamDeckHomebrew:mainfrom
nanwangjkl:add/decky-time-changer

Conversation

@nanwangjkl

@nanwangjkl nanwangjkl commented Oct 9, 2026 •

Copy link
Copy Markdown

Add Time Changer to Plugin Store

Summary

Time Changer lets users change the Steam Deck's system time directly from Game Mode — quick time offsets (±30 min / ±1 hour), a custom date & time picker, and one-click restore to real time via NTP.

The backend wraps timedatectl: it disables NTP before setting the clock (required by systemd-timedated), sets time as timezone-independent UTC epochs, and re-enables NTP sync on restore. If a time change fails midway, NTP is rolled back to its prior state.

Use cases: games with date-triggered content (daily events, date-dependent achievements such as DDLC Plus), emulator titles with real-clock mechanics, and testing time-dependent behavior. There is currently no plugin on the store that changes the system time — the existing manual workflow requires switching to Desktop Mode and editing KDE settings.

UI is localized in English and Simplified Chinese. Screenshots and details: https://github.com/nanwangjkl/decky-time-changer

Task Checklist

Developer

  • I am the original author or an authorized maintainer of this plugin.
  • I have abided by the licenses of the libraries I am utilizing, including attaching license notices where appropriate.
  • Generative AI was NOT used to write a majority of the code I am submitting.
    Regarding AI use: the majority of the code was generated by Claude Code under my direction. I defined the product requirements, reviewed and approved the implementation plan, tested every build on my Steam Deck across 9 iterations, and diagnosed bugs from device logs (including a PyInstaller runtime environment issue). The repo ships with CI-based releases and 24 regression tests. I intend to maintain it and respond to issues on GitHub.

Plugin

  • I have verified that my plugin works properly on the Stable and Beta update channels of SteamOS.
  • I have verified my plugin is unique or provides more/alternative functionality to a plugin already on the store.

Backend

  • No: I am using a custom backend other than Python.
  • No: I am using a tool or software from a 3rd party FOSS project that does not have it's dependencies statically linked.
  • No: I am using a custom binary that has all of it's dependencies statically linked.

Community

  • I have tested and left feedback on two other pull requests for new or updating plugins.
  • I have commented links to my testing report in this PR.

Testing

  • Tested by a third party on SteamOS Stable or Beta update channel.

@nanwangjkl
nanwangjkl requested a review from a team as a code owner October 9, 2026 21:15
@github-actions github-actions Bot added the not-plugin Not related to plugins themselves label Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown

Issues Found

  • Neither testing box is present in your description. Please include one of them per the Markdown comment above the testing section.

Next Steps

  1. If we found any issues above, please edit your pull request description to resolve them and leave a comment saying you've done so.
  2. For the quickest review, please see the Community section of the pull request template for how you can help other developers.
  3. Once your description is correct, a maintainer will review your pull request as soon as possible.

Thank you for your contribution! If you need any help, please reach out on our Discord server. ❤️

@github-actions github-actions Bot added the plugin-addition Adding a plugin to the Plugin Store label Oct 9, 2026
@nanwangjkl

Copy link
Copy Markdown
Author

Description updated

@Jaccident

Jaccident commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Plugin Testing Report

Installed Plugins

  • ProtonDB Badges - 1.3.4
  • Wine Cellar - 0.1.7
  • MagicPods - 2.0.17
  • SteamGridDB - 1.8.1
  • EmuDecky - 1.0.10
  • HLTB for Deck - 2.0.10

Specifications

  • SteamOS 3.8.16_20260716.1(Stable)
  • Steam 1791918634 (Stable)
  • Decky 3.2.10 (Stable)

Issues

Has the following major blocking issue(s): 1
Has the following minor non-blocking issue(s): 3

Summary

Tested by pushing to Deck and manipulating UI, I ran a number of date and time tests, and ran through install, reinstall, disable and uninstall tests.

Major Blocking Issues

  1. I have concerns that the plugin doesn't restore NTP in the _main, _unload, _uninstall functions. A device that suffers critical issues (stemming or not from Device Time being manipulated) could be left in a unstable state. It's also not unreasonable for a user uninstalling the plugin, or the entire Loader, to expect that the Device Time be returned to normal.
    I have tested this by activating a manual time and then disabling the plugin, NTP remains disabled. I think this poses a significant risk.

Minor Non-Blocking Issues

  1. There are insufficient warning that NTP manipulation could lead to unexpected behaviour.
  2. There is a significant stutter when moving from dropdown pickers back to the side panel UI.
  3. Toasts stack up when using the Quick offset buttons, it might be worth not sending each button press as made, but implementing a wait and send, to allow someone to send +2h 30m without receiving multiple toasts.

Tester Note

I just wrote a similar Plugin, where I implemented these safeguards, so feel free to take a look at my implementation for how I did it and pull over into your plugin, I don't mind who goes to production, only that the production solution is safe and trustful for the average user :)
(You committed this the day after I started on my own, great minds think alike!!)

@Jaccident Jaccident mentioned this pull request Oct 17, 2026
6 of 8 tasks
@nanwangjkl

Copy link
Copy Markdown
Author

Plugin Testing Report

Installed Plugins

  • ProtonDB Badges - 1.3.4
  • Wine Cellar - 0.1.7
  • MagicPods - 2.0.17
  • SteamGridDB - 1.8.1
  • EmuDecky - 1.0.10
  • HLTB for Deck - 2.0.10

Specifications

  • SteamOS 3.8.16_20260716.1(Stable)
  • Steam 1791918634 (Stable)
  • Decky 3.2.10 (Stable)

Issues

Has the following major blocking issue(s): 1 Has the following minor non-blocking issue(s): 3

Summary

Tested by pushing to Deck and manipulating UI, I ran a number of date and time tests, and ran through install, reinstall, disable and uninstall tests.

Major Blocking Issues

  1. I have concerns that the plugin doesn't restore NTP in the _main, _unload, _uninstall functions. A device that suffers critical issues (stemming or not from Device Time being manipulated) could be left in a unstable state. It's also not unreasonable for a user uninstalling the plugin, or the entire Loader, to expect that the Device Time be returned to normal.
    I have tested this by activating a manual time and then disabling the plugin, NTP remains disabled. I think this poses a significant risk.

###Minor Non-Blocking Issues

  1. There are insufficient warning that NTP manipulation could lead to unexpected behaviour.
  2. There is a significant stutter when moving from dropdown pickers back to the side panel UI.
  3. Toasts stack up when using the Quick offset buttons, it might be worth not sending each button press as made, but implementing a wait and send, to allow someone to send +2h 30m without receiving multiple toasts.

Tester Note

I just wrote a similar Plugin, where I implemented these safeguards, so feel free to take a look at my implementation for how I did it and pull over into your plugin, I don't mind who goes to production, only that the production solution is safe and trustful for the average user :) (You committed this the day after I started on my own, great minds think alike!!)

Thank you for the thorough report — and for open-sourcing DeckyClocker as
a reference. All actionable findings are addressed in v0.1.12:

Major (NTP not restored): Fixed by restoring NTP from all three
lifecycle hooks (_main, _unload, _uninstall), following the same
pattern as your implementation. Reboots, disabling, uninstalling and
loader restarts now all return the system to a synchronized state, and
_main retries on the next load if a restore ever fails. I also adopted
your _ORIG-preserving variant of the PyInstaller LD_LIBRARY_PATH
cleanup.

Minor 1 (warnings): success toasts now state that NTP stays off
until restored, and the README leads its warnings with a purpose &
disclaimer section.

Minor 3 (toast stacking): rapid consecutive offsets now merge into a
single toast after a 1.5s window, showing the accumulated offset
(e.g. "+2h 30m → 21:45"); other operations flush it immediately.

Minor 2 (dropdown stutter): after investigation this appears to be
inherent to Steam's native Dropdown component (menu teardown + focus
transfer) rather than anything the plugin controls — leaving as-is
unless a mitigation surfaces upstream.

The submodule now points at v0.1.12 if you'd like to re-test. Thanks
again — and great minds indeed! 🙂

@Jaccident

Jaccident commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Plugin Testing Report

Installed Plugins

  • ProtonDB Badges - 1.3.4
  • Wine Cellar - 0.1.7
  • MagicPods - 2.0.17
  • SteamGridDB - 1.8.1
  • EmuDecky - 1.0.10
  • HLTB for Deck - 2.0.10

Specifications

  • SteamOS 3.8.16_20260716.1(Stable)
  • Steam 1791918634 (Stable)
  • Decky 3.2.10 (Stable)

Issues

Has the following major blocking issue(s): 1
Has the following minor non-blocking issue(s): 3

Summary

Tested by pushing to Deck and manipulating UI, I ran a number of date and time tests, and ran through install, reinstall, disable and uninstall tests.

Major Blocking Issues

  1. I have concerns that the plugin doesn't restore NTP in the _main, _unload, _uninstall functions. A device that suffers critical issues (stemming or not from Device Time being manipulated) could be left in a unstable state. It's also not unreasonable for a user uninstalling the plugin, or the entire Loader, to expect that the Device Time be returned to normal.
    I have tested this by activating a manual time and then disabling the plugin, NTP remains disabled. I think this poses a significant risk.

Minor Non-Blocking Issues

  1. There are insufficient warning that NTP manipulation could lead to unexpected behaviour.
  2. There is a significant stutter when moving from dropdown pickers back to the side panel UI.
  3. Toasts stack up when using the Quick offset buttons, it might be worth not sending each button press as made, but implementing a wait and send, to allow someone to send +2h 30m without receiving multiple toasts.

Tester Note

I just wrote a similar Plugin, where I implemented these safeguards, so feel free to take a look at my implementation for how I did it and pull over into your plugin, I don't mind who goes to production, only that the production solution is safe and trustful for the average user :) (You committed this the day after I started on my own, great minds think alike!!)

Thank you for the thorough report — and for open-sourcing DeckyClocker as a reference. All actionable findings are addressed in v0.1.12:

Major (NTP not restored): Fixed by restoring NTP from all three lifecycle hooks (_main, _unload, _uninstall), following the same pattern as your implementation. Reboots, disabling, uninstalling and loader restarts now all return the system to a synchronized state, and _main retries on the next load if a restore ever fails. I also adopted your _ORIG-preserving variant of the PyInstaller LD_LIBRARY_PATH cleanup.

Minor 1 (warnings): success toasts now state that NTP stays off until restored, and the README leads its warnings with a purpose & disclaimer section.

Minor 3 (toast stacking): rapid consecutive offsets now merge into a single toast after a 1.5s window, showing the accumulated offset (e.g. "+2h 30m → 21:45"); other operations flush it immediately.

Minor 2 (dropdown stutter): after investigation this appears to be inherent to Steam's native Dropdown component (menu teardown + focus transfer) rather than anything the plugin controls — leaving as-is unless a mitigation surfaces upstream.

The submodule now points at v0.1.12 if you'd like to re-test. Thanks again — and great minds indeed! 🙂

Regression tested all original issues and can confirm they are all handled gracefully and I couldn't get the Deck to stick in a poor state. Test report updated below. Added a Suggestions/Feedback section (I think it's better to put small things there as they aren't Issues, and I don't want them to seem like unfixed bugs in the long run).

Test Overview

Has the following major blocking issue(s): 0 (1 Fixed)
Has the following minor non-blocking issue(s): 0 (3 Fixed)

Major Blocking Issues

  1. I have concerns that the plugin doesn't restore NTP in the _main, _unload, _uninstall functions. A device that suffers critical issues (stemming or not from Device Time being manipulated) could be left in an unstable state. It's also not unreasonable for a user uninstalling the plugin, or the entire Loader, to expect that the Device Time be returned to normal.
    I have tested this by activating a manual time and then disabling the plugin, NTP remains disabled. I think this poses a significant risk. (fixed)

Minor Non-Blocking Issues

  1. There are insufficient warning that NTP manipulation could lead to unexpected behaviour. (fixed)
  2. There is a significant stutter when moving from dropdown pickers back to the side panel UI. (fixed)
  3. Toasts stack up when using the Quick offset buttons, it might be worth not sending each button press as made, but implementing a wait and send, to allow someone to send +2h 30m without receiving multiple toasts. (fixed)

Suggestions/Feedback

  1. Date range only runs to 2021. There are users online trying to play MLB2K12. which locks content behind the year. I handled this by putting the lowest date at 2003, to cover all the years that Steam has been about, but I don't know if this would have an impact on your architecture:)

Re: dropdown stutter, it's rather unfortunate but understandable (I couldn't make it feel not stutter-y so I avoided it myself, I wish the dropdown loaded in the side panel not over the centre of the screen).

@nanwangjkl

Copy link
Copy Markdown
Author

Plugin Testing Report

Installed Plugins

  • ProtonDB Badges - 1.3.4
  • Wine Cellar - 0.1.7
  • MagicPods - 2.0.17
  • SteamGridDB - 1.8.1
  • EmuDecky - 1.0.10
  • HLTB for Deck - 2.0.10

Specifications

  • SteamOS 3.8.16_20260716.1(Stable)
  • Steam 1791918634 (Stable)
  • Decky 3.2.10 (Stable)

Issues

Has the following major blocking issue(s): 1
Has the following minor non-blocking issue(s): 3

Summary

Tested by pushing to Deck and manipulating UI, I ran a number of date and time tests, and ran through install, reinstall, disable and uninstall tests.

Major Blocking Issues

  1. I have concerns that the plugin doesn't restore NTP in the _main, _unload, _uninstall functions. A device that suffers critical issues (stemming or not from Device Time being manipulated) could be left in a unstable state. It's also not unreasonable for a user uninstalling the plugin, or the entire Loader, to expect that the Device Time be returned to normal.
    I have tested this by activating a manual time and then disabling the plugin, NTP remains disabled. I think this poses a significant risk.

Minor Non-Blocking Issues

  1. There are insufficient warning that NTP manipulation could lead to unexpected behaviour.
  2. There is a significant stutter when moving from dropdown pickers back to the side panel UI.
  3. Toasts stack up when using the Quick offset buttons, it might be worth not sending each button press as made, but implementing a wait and send, to allow someone to send +2h 30m without receiving multiple toasts.

Tester Note

I just wrote a similar Plugin, where I implemented these safeguards, so feel free to take a look at my implementation for how I did it and pull over into your plugin, I don't mind who goes to production, only that the production solution is safe and trustful for the average user :) (You committed this the day after I started on my own, great minds think alike!!)

Thank you for the thorough report — and for open-sourcing DeckyClocker as a reference. All actionable findings are addressed in v0.1.12:
Major (NTP not restored): Fixed by restoring NTP from all three lifecycle hooks (_main, _unload, _uninstall), following the same pattern as your implementation. Reboots, disabling, uninstalling and loader restarts now all return the system to a synchronized state, and _main retries on the next load if a restore ever fails. I also adopted your _ORIG-preserving variant of the PyInstaller LD_LIBRARY_PATH cleanup.
Minor 1 (warnings): success toasts now state that NTP stays off until restored, and the README leads its warnings with a purpose & disclaimer section.
Minor 3 (toast stacking): rapid consecutive offsets now merge into a single toast after a 1.5s window, showing the accumulated offset (e.g. "+2h 30m → 21:45"); other operations flush it immediately.
Minor 2 (dropdown stutter): after investigation this appears to be inherent to Steam's native Dropdown component (menu teardown + focus transfer) rather than anything the plugin controls — leaving as-is unless a mitigation surfaces upstream.
The submodule now points at v0.1.12 if you'd like to re-test. Thanks again — and great minds indeed! 🙂

Regression tested all original issues and can confirm they are all handled gracefully and I couldn't get the Deck to stick in a poor state. Test report updated below. Added a Suggestions/Feedback section (I think it's better to put small things there as they aren't Issues, and I don't want them to seem like unfixed bugs in the long run).

Test Overview

Has the following major blocking issue(s): 0 (1 Fixed) Has the following minor non-blocking issue(s): 0 (3 Fixed)

Major Blocking Issues

  1. I have concerns that the plugin doesn't restore NTP in the _main, _unload, _uninstall functions. A device that suffers critical issues (stemming or not from Device Time being manipulated) could be left in an unstable state. It's also not unreasonable for a user uninstalling the plugin, or the entire Loader, to expect that the Device Time be returned to normal.
    I have tested this by activating a manual time and then disabling the plugin, NTP remains disabled. I think this poses a significant risk. (fixed)

Minor Non-Blocking Issues

  1. There are insufficient warning that NTP manipulation could lead to unexpected behaviour. (fixed)
  2. There is a significant stutter when moving from dropdown pickers back to the side panel UI. (fixed)
  3. Toasts stack up when using the Quick offset buttons, it might be worth not sending each button press as made, but implementing a wait and send, to allow someone to send +2h 30m without receiving multiple toasts. (fixed)

Suggestions/Feedback

  1. Date range only runs to 2021. There are users online trying to play MLB2K12. which locks content behind the year. I handled this by putting the lowest date at 2003, to cover all the years that Steam has been about, but I don't know if this would have an impact on your architecture:)

Re: dropdown stutter, it's rather unfortunate but understandable (I couldn't make it feel not stutter-y so I avoided it myself, I wish the dropdown loaded in the side panel not over the centre of the screen).

Hey, quick follow-up on your report — your feedback prompted a rework of
the custom time picker in v0.1.13, and it goes your way:

1. Year range widened. The picker now covers 2003–2034. I took the
cue from your slider comments — older titles with date-based content need
more room than my original ±5-year window.

2. I switched to your interaction model. After shipping both and
comparing them on real hardware, I came around to the slider layout:
dropdowns are lovely on the touchscreen, but your five-slider approach
is simply better in the hand — and the finger-drag precision issue I was
worried about turned out to be far less of a problem in practice than I
expected. So the dropdowns are gone; it's five full-width sliders now,
with the day clamping into the month length like yours.

Bonus: this also makes your Minor #2 (the stutter when closing a
dropdown) disappear entirely — no dropdowns, no stutter. That one was
never really fixable from the plugin side.

Thanks for the thorough report and for open-sourcing your implementation
as a reference — it made the store version of this plugin measurably
better.

@Jaccident

Jaccident commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Hey, quick follow-up on your report — your feedback prompted a rework of the custom time picker in v0.1.13, and it goes your way:

1. Year range widened. The picker now covers 2003–2034. I took the cue from your slider comments — older titles with date-based content need more room than my original ±5-year window.

2. I switched to your interaction model. After shipping both and comparing them on real hardware, I came around to the slider layout: dropdowns are lovely on the touchscreen, but your five-slider approach is simply better in the hand — and the finger-drag precision issue I was worried about turned out to be far less of a problem in practice than I expected. So the dropdowns are gone; it's five full-width sliders now, with the day clamping into the month length like yours.

Bonus: this also makes your Minor #2 (the stutter when closing a dropdown) disappear entirely — no dropdowns, no stutter. That one was never really fixable from the plugin side.

Thanks for the thorough report and for open-sourcing your implementation as a reference — it made the store version of this plugin measurably better.

Test Overview

Has the following major blocking issue(s): 0
Has the following minor non-blocking issue(s): 1 new

Major Blocking Issues

None

Minor Non-Blocking Issues

  1. There is a small fade on the right edge of the Back button at the top of the screen. (See screenshot)
decky-time-changer_0 1 14_fade

Suggestions/Feedback

  1. Date range only runs to 2021. There are users online trying to play MLB2K12. which locks content behind the year. I handled this by putting the lowest date at 2003, to cover all the years that Steam has been about, but I don't know if this would have an impact on your architecture :) (addressed)
  2. I have a note based on your slider implementation (it was likely there in the dropdown implementation, but I didn't spot it). When you Restore Real Time, the sliders stay in their last set custom positions. This makes some sense but since the slider positions can't persist in the plugin losing focus, it leads to a somewhat inconsistent user experience. You might consider resetting sliders to represent the current time on successful Restore. That way the user never expects that sliders stay in a state beyond that custom time session.
  3. Something else to consider might be the relocation of the Restore Real Time button to be on screen when the plugin opens. I also started with the button at the bottom but it's often UX best practice to put the safety button high in the user's vision, and easily available to the user.

@Jaccident

Jaccident commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Test Overview

Has the following major blocking issue(s): 0 Has the following minor non-blocking issue(s): 1 new

Major Blocking Issues

None

Minor Non-Blocking Issues

  1. There is a small fade on the right edge of the Back button at the top of the screen. (See screenshot)
decky-time-changer_0 1 14_fade

Suggestions/Feedback

  1. Date range only runs to 2021. There are users online trying to play MLB2K12. which locks content behind the year. I handled this by putting the lowest date at 2003, to cover all the years that Steam has been about, but I don't know if this would have an impact on your architecture :) (addressed)
  2. I have a note based on your slider implementation (it was likely there in the dropdown implementation, but I didn't spot it). When you Restore Real Time, the sliders stay in their last set custom positions. This makes some sense but since the slider positions can't persist in the plugin losing focus, it leads to a somewhat inconsistent user experience. You might consider resetting sliders to represent the current time on successful Restore. That way the user never expects that sliders stay in a state beyond that custom time session.
  3. Something else to consider might be the relocation of the Restore Real Time button to be on screen when the plugin opens. I also started with the button at the bottom but it's often UX best practice to put the safety button high in the user's vision, and easily available to the user.

Found the cause of the Minor Issue

Here's my definePlugin:

export default definePlugin(() => ({
name: "DeckyClocker",
content: ,
icon: ,

Here's your definePlugin:

export default definePlugin(() => {
return {
name: "Time Changer",
titleView:

Time Changer
,
content: ,
// Steam menus can temporarily hide the QAM. Keep picker state mounted so
// their selection callbacks do not target an already unmounted Content.
alwaysRender: true,
icon: ,
onDismount() {},
};
});

It's unnecessary to insert :

titleView: <div className={staticClasses.Title}>Time Changer</div>,

This is causing a manual draw of the title rather than leaving it to Decky, that also leads to the title being in an inconsistent position compared to other plugins, and I think pushes down your current time content block.

Suggest removing this line if you agree.

@nanwangjkl

nanwangjkl commented Oct 19, 2026 •

Copy link
Copy Markdown
Author

Test Overview

Has the following major blocking issue(s): 0 Has the following minor non-blocking issue(s): 1 new

Major Blocking Issues

None

Minor Non-Blocking Issues

  1. There is a small fade on the right edge of the Back button at the top of the screen. (See screenshot)
decky-time-changer_0 1 14_fade ### Suggestions/Feedback
  1. Date range only runs to 2021. There are users online trying to play MLB2K12. which locks content behind the year. I handled this by putting the lowest date at 2003, to cover all the years that Steam has been about, but I don't know if this would have an impact on your architecture :) (addressed)
  2. I have a note based on your slider implementation (it was likely there in the dropdown implementation, but I didn't spot it). When you Restore Real Time, the sliders stay in their last set custom positions. This makes some sense but since the slider positions can't persist in the plugin losing focus, it leads to a somewhat inconsistent user experience. You might consider resetting sliders to represent the current time on successful Restore. That way the user never expects that sliders stay in a state beyond that custom time session.
  3. Something else to consider might be the relocation of the Restore Real Time button to be on screen when the plugin opens. I also started with the button at the bottom but it's often UX best practice to put the safety button high in the user's vision, and easily available to the user.

Found the cause of the Minor Issue

Here's my definePlugin:

export default definePlugin(() => ({
name: "DeckyClocker",
content: ,
icon: ,

Here's your definePlugin:

export default definePlugin(() => {
return {
name: "Time Changer",
titleView: Time Changer,
content: ,
// Steam menus can temporarily hide the QAM. Keep picker state mounted so
// their selection callbacks do not target an already unmounted Content.
alwaysRender: true,
icon: ,
onDismount() {},
};
});

It's unnecessary to insert :

titleView: <div className={staticClasses.Title}>Time Changer</div>,

This is causing a manual draw of the title rather than leaving it to Decky, that also leads to the title being in an inconsistent position compared to other plugins, and I think pushes down your current time content block.

Suggest removing this line if you agree.

Thanks for the re-test and the follow-up notes — v0.2.0 addresses both
of your latest findings, and I want to walk through the slider one because
your comment sent me down an interesting path.

The slider reset

A successful Restore now resets the sliders to the system time at that
moment
, ending the custom-time session cleanly — exactly your suggestion.
The picker is now explicitly "a draft for the current session": it
initializes to the current time, restore clears it back to the current
time, and nothing else ever writes to it.

The part I deliberately did not do

My first instinct was to also reset the sliders again once the NTP resync
actually landed (the clock only becomes real time seconds after Restore
returns). I'm glad I stopped to think it through, because it's a trap:

  • The resync timing is unbounded. The sliders would jump back at an
    unpredictable moment — quite possibly while the user is already dragging
    them toward a new custom time. An async mutation racing user input is
    precisely the bug class this plugin had to fix twice before.
  • Offline, the resync never comes. There is no "real time" to converge
    to, so the "eventual consistency" story collapses entirely.

So the rule in v0.2.0 is: the sliders are written by the user, by
initialization, and by a successful Restore — by nothing asynchronous,
ever
. The sticky clock keeps tracking the actual system time (and now
turns amber while it is not NTP-synced, so "still skewed" stays visible
without the sliders getting involved).

The Back-button fade

Also fixed in v0.2.0 — and credit where due, your diagnosis pointed
straight at it: the custom titleView I was shipping was the culprit.
Removing it in favor of Decky's default header cleared the fade on the
Back button's right edge; verified on my device as well.


On your reports generally: the attentiveness is genuinely remarkable.
You've now caught a lifecycle safety gap, a state-consistency issue that
only shows up across focus loss, a rendering artifact traced to a single
line of plugin markup, and you backed each one with reproduction steps or
screenshots. Reports at this level don't just get issues fixed — they
shape how the maintainer writes code afterwards. Much appreciated.

@Jaccident

Copy link
Copy Markdown
Contributor

On your reports generally: the attentiveness is genuinely remarkable. You've now caught a lifecycle safety gap, a state-consistency issue that only shows up across focus loss, a rendering artifact traced to a single line of plugin markup, and you backed each one with reproduction steps or screenshots. Reports at this level don't just get issues fixed — they shape how the maintainer writes code afterwards. Much appreciated.

You're very welcome! I've really enjoyed this parallel journey we've been on the last few days.

Test Overview

Has the following major blocking issue(s): 0
Has the following minor non-blocking issue(s): 0 (1 fixed)

Major Blocking Issues

None

Minor Non-Blocking Issues

  1. There is a small fade on the right edge of the Back button at the top of the screen. (See screenshot) (fixed)

Suggestions/Feedback

  1. You probably don't need the title={t("panel.restore")} in your new PanelSection, there's only one button in there and it's pretty explicit, removing it would tighten up the UI.
  2. Your floating time panel and amber status are a really nice flourish, and work really well!

@AAGaming00

Copy link
Copy Markdown
Member

Closing in favor of DeckyClocker, I prefer their implementation

@AAGaming00 AAGaming00 closed this Oct 19, 2026

This branch is waiting to be deployed

1 waiting deployment
testing_env — 3853cc0f Waiting Oct 19, 2026 by nanwangjkl via Build plugin (decky-time-changer, true) #4088
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

not-plugin Not related to plugins themselves plugin-addition Adding a plugin to the Plugin Store

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants