Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved CountDown timer #300

Merged
merged 2 commits into from
Aug 9, 2024
Merged

Conversation

dmgerman
Copy link
Contributor

@dmgerman dmgerman commented Jun 5, 2023

  • Improved configuration of the notification area (size and transparency)
  • Added optional icons in the menubar to start, pause and end the time, and notify of remaining time
  • It is now able to deal with suspending the laptop during the timer i.e. time runs in "user" time, not "computer running" time
  • added hotkeys
    • able to call timer again with last period
    • or set new period

@dmgerman
Copy link
Contributor Author

Is there anything else I can do to have this pull request merged? thank you.

@asmagill
Copy link
Member

I apologize, I told @cmsj I'd take over for him re spoons, but had some unexpected interruptions occur. I'm hoping I can get back to this in the next day or so and run through a dry run to make sure I don't screw anything up and then start testing/merging this weekend.

@dmgerman
Copy link
Contributor Author

dmgerman commented Aug 30, 2023 via email

@cmsj cmsj closed this Aug 7, 2024
@cmsj cmsj reopened this Aug 7, 2024
@cmsj
Copy link
Member

cmsj commented Aug 7, 2024

@dmgerman looks like you're missing * characters on some of the Parameters: lists in your docstrings. Even the none should be * None.

Copy link
Contributor

@muescha muescha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some minor nitpicks.

end

function obj:query_time_and_start()
local button, time = hs.dialog.textPrompt("Enter time", "in minutes", string.format("%s", obj.defaultLenMin), "Ok", "Cancel")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
local button, time = hs.dialog.textPrompt("Enter time", "in minutes", string.format("%s", obj.defaultLenMin), "Ok", "Cancel")
local button, time = hs.dialog.textPrompt("Enter time", "in minutes", string.format("%s", obj.defaultLenMin), "OK", "Cancel")


function obj:query_time_and_start()
local button, time = hs.dialog.textPrompt("Enter time", "in minutes", string.format("%s", obj.defaultLenMin), "Ok", "Cancel")
if button == "Ok" then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if button == "Ok" then
if button == "OK" then

Comment on lines 36 to 38
-- default timer in minutes

obj.defaultLenMin = 25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
-- default timer in minutes
obj.defaultLenMin = 25
-- default timer in minutes
obj.defaultLenMin = 25

function obj:create_bar_timer(minutes)
local mainScreen = hs.screen.primaryScreen()
local mainRes = mainScreen:fullFrame()
obj.canvas:frame({x=mainRes.x, y=mainRes.h-obj.canvasHeight, w=mainRes.w, obj.canvasHeight})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is here h= missing?

Suggested change
obj.canvas:frame({x=mainRes.x, y=mainRes.h-obj.canvasHeight, w=mainRes.w, obj.canvasHeight})
obj.canvas:frame({x=mainRes.x, y=mainRes.h-obj.canvasHeight, w=mainRes.w, h=obj.canvasHeight})

Comment on lines 255 to 258
if obj.timer then
-- reset current timer and do nothing
obj:reset()
else
Copy link
Contributor

@muescha muescha Aug 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the minutes value is changed?

  • I think it is better to cleanup if there a timer exists and start over with setting the values to have a clean state
  • or check if minutes are change
Suggested change
if obj.timer then
-- reset current timer and do nothing
obj:reset()
else
if obj.timer then
-- reset current timer and do nothing
obj:reset()
end

Comment on lines 296 to 297
local pausedSeconds = obj:time_absolute_seconds() - obj.pausedAt
obj.startTime = obj.startTime + pausedSeconds
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would think this calculation is not valid if there are multiple pauses and resumes.

Comment on lines 177 to 178
local mainScreen = hs.screen.primaryScreen()
local mainRes = mainScreen:fullFrame()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong variable naming

Suggested change
local mainScreen = hs.screen.primaryScreen()
local mainRes = mainScreen:fullFrame()
local primaryScreen = hs.screen.primaryScreen()
local mainRes = primaryScreen:fullFrame()

Comment on lines 339 to 340
local mainScreen = hs.screen.primaryScreen()
local mainRes = mainScreen:fullFrame()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong variable naming

Suggested change
local mainScreen = hs.screen.primaryScreen()
local mainRes = mainScreen:fullFrame()
local primaryScreen = hs.screen.primaryScreen()
local mainRes = primaryScreen:fullFrame()

else
message = string.format("Illegal number [%s]", time)
end
hs.alert.show(message, nil, hs.screen.mainScreen())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The canvas is changed to primaryScreen — should the alert be as well?

withdrawAfter = 100
}):soundName(obj.sound):send()

hs.alert.show(message, nil, hs.screen.mainScreen(), obj.alertLenMin)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The canvas is changed to primaryScreen — should the alert be as well?

@dmgerman
Copy link
Contributor Author

dmgerman commented Aug 8, 2024

Thanks for the comment. There are some new features I have implemented. I'll address your comments and submit an update.

@dmgerman dmgerman force-pushed the improved-countdown-timer branch from 5b9a4ac to 72b703e Compare August 9, 2024 22:17
Lots of improvements over original timer. They can be divided into several
categories:

- Improve timer handler. The original timer counted seconds via a callback.
  If the computer was suspended, the timer would have been suspended too.
  The new timer continues to run even when the computer is suspended.

- Improved configurability of countdown timer
  Many of its properties can now be configured via object attributes

- Added menu bar:
  A menu bar item allows to start/pause/resume/cancel a timer

- Optional progress messages:
  It can optionally display messages to the screen as the timer is advancing

- Improved time-up messages.
  I found that the end of the timer notifications were too subtle to be noticed.
  It now allows several ways to configure the notifications

- A callback.
  User can specify a callback to the evaluated as the timer is
  started/paused/resumed/cancelled.

- In addition to minutes, a timer can now be set using a time of day,
@dmgerman dmgerman force-pushed the improved-countdown-timer branch from 59380ca to b03f19a Compare August 9, 2024 22:45
@dmgerman
Copy link
Contributor Author

dmgerman commented Aug 9, 2024

@cmsj @muescha

Hi everybody, I have uploaded my current improvements. I have added several features since I first uploaded these changes. I also fixed the documentation errors.

This is the complete summary:

 Improved CountDown timer

Lots of improvements over original timer. They can be divided into several
categories:

- Improve timer handler. The original timer counted seconds via a callback.
  If the computer was suspended, the timer would have been suspended too.
  The new timer continues to run even when the computer is suspended.

- Improved configurability of countdown timer
  Many of its properties can now be configured via object attributes

- Added menu bar:
  A menu bar item allows to start/pause/resume/cancel a timer

- Optional progress messages:
  It can optionally display messages to the screen as the timer is advancing

- Improved time-up messages.
  I found that the end of the timer notifications were too subtle to be noticed.
  It now allows several ways to configure the notifications

- A callback.
  User can specify a callback to the evaluated as the timer is
  started/paused/resumed/cancelled.

- In addition to minutes, a timer can now be set using a time of day,

Copy link
Contributor

@muescha muescha left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some notes

--- the minutes that were requested.
--- The callback is not called if timer is cancelled
function obj:startFor(minutes, callback)
if not minutes then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you could test minutes for type=function then minutes get the default minutes and place minutes into callback. so the minutes are optional

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean: if minutes is a function, call it and use return value as length of the timer?

currently, minutes is optional, if provided, if not provided it will use defaultLenMinutes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean that if minutes would be an optional parameter, but someone want a callback
function obj:startFor([minutes,] callback)

I have seen this on some places at hammerspoon:

if type(minutes)=='function' then
	callback = minutes
	minutes = obj.defaultLenMinutes
end

example:
https://github.com/Hammerspoon/hammerspoon/blob/ec9a8ead1fc9074b8647c5ee4c09ba96f66a719a/extensions/host/host.lua#L89-L95

if not minutes then
minutes = obj.defaultLenMinutes
end
if obj.timerRunning then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe do here a timer:cancel() and start over with a new timer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is better to issue an error. The reasons is that one might accidentally try to set another timer without noticing the current one is running. I guess a better option would be to make this optional (via a variable). What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or alternatively, ask the user.

-- configure some bindings
countDown:bindHotkeys({
startFor = {{"cmd", "ctrl", "alt"}, "P"},
startInteractive = {{"cmd", "ctrl", "alt", "shift"}, "P"},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is here this is missing:
pauseOrResume = {{"cmd", "ctrl", "alt"}, "P"},

@muescha
Copy link
Contributor

muescha commented Aug 9, 2024

your alerts are not on the same place always - is this by design?

/* 227 */ hs.alert.show(msg, obj.messageAttributes, nil, duration) -- nil
/* 291 */ hs.alert.show(message, obj.alertAttributes, screen, obj.alertLen) -- .mainScreen() / currentWin:screen()
/* 600 */ hs.alert.show(message, nil, hs.screen.mainScreen()) -- .mainScreen()
/* 630 */ hs.alert.show(message, nil, hs.screen.mainScreen()) -- .mainScreen()

I realized that I removed this function. To maintain full backwards
compatibility I have added it back. Adds a new type of event (setProgress).
@dmgerman
Copy link
Contributor Author

dmgerman commented Aug 9, 2024

your alerts are not on the same place always - is this by design?

/* 227 */ hs.alert.show(msg, obj.messageAttributes, nil, duration) -- nil
/* 291 */ hs.alert.show(message, obj.alertAttributes, screen, obj.alertLen) -- .mainScreen() / currentWin:screen()
/* 600 */ hs.alert.show(message, nil, hs.screen.mainScreen()) -- .mainScreen()
/* 630 */ hs.alert.show(message, nil, hs.screen.mainScreen()) -- .mainScreen()

Yes. We have three types of messsage: warnings (optional), messages while setting/modifying the timer, and final alert.

@cmsj
Copy link
Member

cmsj commented Aug 9, 2024

Thanks @dmgerman. I'm going to merge this now, if you want to follow up on any of @muescha 's comments, feel free to open a new PR.

@cmsj cmsj merged commit c821e5a into Hammerspoon:master Aug 9, 2024
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants