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

Add extension for Do Not Disturb Mode (and underlay User Preference extension) #1706

Closed
wants to merge 4 commits into from

Conversation

waynezhang
Copy link
Contributor

@waynezhang waynezhang commented Mar 15, 2018

Add a new extension to control Do Not Disturb Mode

-- Get current value
local status = hs.donotdisturb.status()

-- Turn on  Do Not Disturb Mode
hs.donotdisturb.on()

-- Turn off  Do Not Disturb Mode
hs.donotdisturb.off()

And because it's depended on user preference, I also isolated it as a standalone extension

-- Set preference
hs.userpreferences.set("key", value, "application id")

-- Get preference
hs.userpreferences.get("key", "application id")

-- Synchronize preferences
hs.userpreferences.sync("application id")

@@ -0,0 +1,17 @@
hs.notdisturbmode = require("hs.notdisturbmode")

function testNotDisturbMode()

Choose a reason for hiding this comment

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

(W111) setting non-standard global variable 'testNotDisturbMode'

local isOn = hs.notdisturbmode.status()

hs.notdisturbmode.off()
assertIsEqual(false, hs.notdisturbmode.status())

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'assertIsEqual'

assertIsEqual(false, hs.notdisturbmode.status())

hs.notdisturbmode.on()
assertIsEqual(true, hs.notdisturbmode.status())

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'assertIsEqual'

hs.notdisturbmode.off()
end

return success()

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'success'

@@ -0,0 +1,25 @@
hs.userpreference = require("hs.userpreference")

function testUserPreference()

Choose a reason for hiding this comment

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

(W111) setting non-standard global variable 'testUserPreference'


hs.userpreference.set("test_user_preference", false, "com.hammerspoon.hammerspoon")
val = hs.userpreference.get("test_user_preference", "com.hammerspoon.hammerspoon")
assertIsEqual(val, false)

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'assertIsEqual'


hs.userpreference.set("test_user_preference", "aaa", "com.hammerspoon.hammerspoon")
val = hs.userpreference.get("test_user_preference", "com.hammerspoon.hammerspoon")
assertIsEqual(val, "aaa")

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'assertIsEqual'

hs.userpreference.set("test_user_preference", "aaa", "com.hammerspoon.hammerspoon")
val = hs.userpreference.get("test_user_preference", "com.hammerspoon.hammerspoon")
assertIsEqual(val, "aaa")

Choose a reason for hiding this comment

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

(W611) line contains only whitespace


hs.userpreference.set("test_user_preference", nil, "com.hammerspoon.hammerspoon")
val = hs.userpreference.get("test_user_preference", "com.hammerspoon.hammerspoon")
assertIsEqual(val, nil)

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'assertIsEqual'


hs.userpreference.sync("com.hammerspoon.hammerspoon")

return success()

Choose a reason for hiding this comment

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

(W113) accessing undefined variable 'success'

@latenitefilms
Copy link
Contributor

Amazing work @waynezhang!

My only question is, how does hs.userpreference fit in with @cmsj's hs.plist and @asmagill's WIP hs.preferences?

See issues:

Thoughts @asmagill & @cmsj ?

@cmsj
Copy link
Member

cmsj commented Mar 15, 2018

(will report some thoughts later, just wanted to quickly drop in to say ignore the sticker CI comments, it doesn't know what it's talking about)

@latenitefilms
Copy link
Contributor

@cmsj - I've just made a tweak in #1707 which I think will solve the @stickler-ci errors.

Copy link
Member

@cmsj cmsj left a comment

Choose a reason for hiding this comment

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

This is great stuff, but I think I'd like to change the names - notdisturbmode doesn't match up with the English name for the macOS feature, so maybe it should be hs.donotdisturb?

Also I think hs.userpreference would be better as hs.userpreferences

kCFPreferencesCurrentUser,
kCFPreferencesCurrentHost);
if (ref != nil) {
[skin pushNSObject:(__bridge NSObject *)ref];
Copy link
Member

Choose a reason for hiding this comment

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

Small thing, but we tend to use __bridge_transfer rather than __bridge and CFAutorelease().

Copy link
Contributor Author

@waynezhang waynezhang Jun 20, 2020

Choose a reason for hiding this comment

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

Fixed at c043e28

@dbalatero
Copy link

@waynezhang Would love to see this merged so I can control DND from the keyboard. Anything I can do to help?

@waynezhang
Copy link
Contributor Author

@dbalatero Sorry for late reply. I'm gonna fix this recently when I have time. The tasks left will be:

  • Rename some variable according to @cmsj's comment
  • To see if user preference related stuff can be replaced by the PR mentioned by @latenitefilms
    I'd be very appreciated if you can lend me some help :)

@megalithic
Copy link

@waynezhang any updates/thoughts around resolving these items so @cmsj can merge?

@latenitefilms
Copy link
Contributor

I'd love to get @asmagill's thoughts in regards to hs.userpreferences, and how that fits in with the other Preferences/Settings extensions?

@kopinions
Copy link

when will this merged?

@latenitefilms
Copy link
Contributor

@sjkyspa - The big question here is how to deal with the preferences handling.

What do you think @cmsj & @asmagill ?

Related:

#1498 - hs.preferences - Property List Editor with NSKeyedArchiver support
#1441 - CFPreferences

@latenitefilms latenitefilms mentioned this pull request Dec 23, 2019
8 tasks
@latenitefilms
Copy link
Contributor

@cmsj & @asmagill - In the interest of merging in the code to solve the original issue in this pull request, I wonder if it's worth just removing hs.userpreference for now, and hardcoding in the preferences stuff directly in hs.donotdisturb so this can be merged, and we can work out what to do with plists in another issue/pull request?

@asmagill
Copy link
Member

Sorry I didn't look at this earlier... @latenitefilms since you are the only one I know has used hs._asm.cfpreferences much beyond my initial tests, what are your thoughts on it? What does it need/lack before being submitted for inclusion?

It looks like userpreferences here is a subset, so we could create a wrapper (or even rename mine) if the name seems to make more sense... and since I do note in cfpreferences's limitations that it can't access the "AnyUser" key for writing, renaming mine might actually be worthwhile... the label "cfpreferences" is just a nod to the underlying foundation library being used and wouldn't make sense to someone not somewhat familiar with macOS programming...

@latenitefilms
Copy link
Contributor

Currently I'm using a mixture of hs._asm.cfpreferences, hs.plist and our own Lua-based cp.plist (which internally uses plutil and openssl base64) to achieve everything we need. I'll need to go back through our code to work out the pro's and con's of each extension.

From memory, the reason we're using cp.plist in a lot of cases is that we're also using cp.plist.archiver, which supports 'defrosting' a table which is made up from an NSKeyArchiver record. We can't use hs.pasteboard.readArchiverDataForUTI() because we're dealing with classes that Hammerspoon doesn't support.

There were also cases where hs._asm.cfpreferences was giving different results than cp.plist. I can't remember the specifics off the top of my head.

Ideally, I'd love to drop cp.plist and use faster Objective-C implementations.

I think renaming hs._asm.cfpreferences to hs.userpreferences makes sense?

Note to self - these plugins use cp.plist:

  • plugins.finalcutpro.notifications.manager
  • plugins.finalcutpro.pasteboard.manager
  • plugins.finalcutpro.timeline.commandsetactions
  • cp.apple.finalcutpro.export.destinations
  • cp.apple.finalcutpro.plugins
  • cp.disk

These plugins use cp.plist.archiver:

  • cp.app.menu
  • cp.apple.finalcutpro.export.destinations
  • cp.apple.finalcutpro.plugins
  • plugins.finalcutpro.pasteboard.manager

Also, note to self, that cp.apple.finalcutpro.export.destinations says:

----------------------------------------------------------------------------------
-- TODO: This code currently doesn't work with hs.plist, which is why we're still
--       using cp.plist. Will re-investigate once we have hs.plist.readString()
----------------------------------------------------------------------------------

Will do some experimenting over the coming days to work out what use-cases hs._asm.cfpreferences is currently failing for us.

@latenitefilms
Copy link
Contributor

@asmagill - Re-looking at this issue, the hs.userpreference extension added in this pull request can be easily replaced with hs._asm.cfpreferences.

For example:

> cfpreferences = require("hs._asm.cfpreferences")


> cfpreferences.getValue("doNotDisturb", "com.apple.notificationcenterui")
false

> cfpreferences.getValue("doNotDisturb", "com.apple.notificationcenterui")
true

Given that, I'd suggest we try and merge hs._asm.cfpreferences into Hammerspoon at some point when you get time (obviously there's a fair amount of work to do, as hs._asm.cfpreferences is currently undocumented, etc. - I'm happy to help where I can!), then once that's done this pull request just requires a few minor tweaks before it can be merged in. This could either be done by @waynezhang, or I'm happy to help make the necessary changes, once hs._asm.cfpreferences is merged in.

As discussed above, I think renaming hs._asm.cfpreferences to hs.userpreferences also makes sense.

@waynezhang
Copy link
Contributor Author

Sorry for leaving this issue untouched for so long a time.
I'll make some fix soon.

@latenitefilms Thanks for the advice. I'm happy to do the migration to _asm.cfpreferences after it's merged to Hammerspoon.

@@ -0,0 +1,17 @@
hs.donotdisturb = require("hs.donotdisturb")

Choose a reason for hiding this comment

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

(W122) setting read-only field 'donotdisturb' of global 'hs'

@@ -0,0 +1,25 @@
hs.userpreferences = require("hs.userpreferences")

Choose a reason for hiding this comment

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

(W122) setting read-only field 'userpreferences' of global 'hs'

hs.userpreferences = require("hs.userpreferences")

function testUserPreferences()
local val = 0

Choose a reason for hiding this comment

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

(W311) value assigned to variable 'val' is overwritten on line 7 before use

hs.userpreferences.set("test_user_preferences", "aaa", "com.hammerspoon.hammerspoon")
val = hs.userpreferences.get("test_user_preferences", "com.hammerspoon.hammerspoon")
assertIsEqual(val, "aaa")

Choose a reason for hiding this comment

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

(W611) line contains only whitespace

@waynezhang
Copy link
Contributor Author

I've renamed it to hs.donotdisturb (and hs.userpreference to hs.userpreferences). PTAL.

@evantravers
Copy link

Nothing to add here but excited to see this 👍

@asmagill
Copy link
Member

asmagill commented Sep 9, 2020

I want to leave this for 0.9.80 -- I plan to work on the merging of cfpreferences, preferences, settings, etc. after getting 0.9.79 out the door and this would be a perfect fit at that time.

@asmagill asmagill mentioned this pull request Sep 26, 2020
@kassi
Copy link

kassi commented Oct 26, 2021

I'm very interested in this feature. Do you have a rough timeline?
Anything someone could help with?

@latenitefilms
Copy link
Contributor

@cmsj & @asmagill - I've said this before, but just to suggest again... in the interest of merging in the code to solve the original issue in this pull request, I wonder if it's worth just removing hs.userpreference for now, and hardcoding in the preferences stuff directly in hs.donotdisturb so this can be merged, and we can work out what to do with plists in another issue/pull request?

@dbalatero
Copy link

dbalatero commented Oct 27, 2021

I think in Mojave/Catalina, DND was turned on via user preferences:

https://github.com/dbalatero/dotfiles/blob/master/hammerspoon/pairing-mode.lua#L32-L44

However, the only way I was able to enable it on Big Sur is via UI automation + AppleScript:

https://github.com/dbalatero/dotfiles/blob/master/hammerspoon/pairing-mode.lua#L9-L30

Apple seems to have dropped the user preferences way in favor of something more custom and opaque. Just a heads up that maintaining a DND module might be a moving target in the future!

(I wish Apple would just ship a CLI program to toggle DND, honestly)

@Nezteb
Copy link

Nezteb commented Feb 3, 2022

I'd love this feature; for the time being I'm using this method: https://spinscale.de/posts/2020-10-30-using-hammerspoon-do-not-disturb-screen-sharing-zoom.html

@evantravers
Copy link

For anyone else thinking about this in the meantime: if you are on Big Sur you can trigger a shortcut using hs.shortcuts.run to enable Focus Modes or DND. You just have to create the corresponding Shortcuts.

https://github.com/evantravers/hammerspoon-config/blob/219c0fa903ca2c0bafbad2a6564f1c4feb7427f6/spaces/deep.lua#L14

For now… this works really well for me, and I'm ok.

@waynezhang waynezhang closed this Feb 4, 2022
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.