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

[Notifications] [Windows] Native interactive notifications #946

Merged
merged 21 commits into from
Mar 8, 2023

Conversation

Araxeus
Copy link
Collaborator

@Araxeus Araxeus commented Jan 7, 2023

This is a pretty big PR whose main goal is to replace SnoreToast/node-notifier with native toast notifications using XML
— along the way there were some other changes detailed below

Feel free to ask questions about code or its purpose in this PR.

Changes related only to this plugin:

  • Made config local to the plugin, which means it is synced between the menu and the other files

  • Different presets and option to hide text on buttons (screenshots below)

  • Adaptive text size in the Banner Centered toasts + Time widget in the one custom preset

  • Option to open notification on tray click, which can act as a very cool quick music control from everywhere
    (This feature is a personal favorite of mine 🤩)

Other Changes:


  • Added a Protocol Handler (can handle all song-controls actions)
    youtubemusic://pause
    
    Should maybe add to README?
    could capitalize on this for other plugins/features
    For example, users could execute the URI with custom remote control apps

  • Made Single Instance Lock enabled on app launch, can disable it on a specific session via the menu
    Multiple Instances break the Protocol Handler, (and already broke a few other features), and also resources cost is unreasonable

  • Moved the icons from taskbar-mediacontrol to a global folder (these toasts use the same icons)
    Should probably recolor them to white at some point

  • The special listeners in song-info-front are now activated on demand instead of depending on options
    (Easier to use it from plugins now, don't have to modify song-info-front logic every time, don't have to think about if other plugins requested it since it's a singleton)

  • SongInfo callback got an extra argument which is the reason for the callback (video-src-changed or playPaused)
    Not actually used anywhere for now

Won't Do


Screenshots

Click me

xml_logo_ascii

This is how it looked on v1.19.0 (using SnoreToast), I see no reason not to include

image image

xml_logo_icons_notext

The gap is unavoidable since there HAS to be a text field inside a button, looks better when not zoomed in on the toast

image image

xml_logo_icons

image image

xml_hero

Looks a bit weird because the hero appears on top of the notification (above the close button)

image image

xml_banner_bottom

similar to xml_hero but less weird, I see no reason not to include

image image

xml_banner_top_custom

this one is actually interesting, notice the special info at the right (Album name, Release year)
Cool concept but the top gap is pretty big…

image image

xml_banner_centered_bottom

Both of the centered toasts make use of special text properties (like font, position)
the text could be made a bit smaller, but the gap will remain

image image

xml_banner_centered_top

I like the idea of a bigger font and centered position, but not sure if it's worth the topgap tradeoff

image image

dev stuff

[Notifications Visualizer] --- [download appx] --- [CUSTOM PRESETS]

more on toast XML:
schema
general tutorial
toasttemplatetype

@Proton7123
Copy link

Proton7123 commented Jan 8, 2023

I love this app! That being said, I have a couple of EPIC SUGGESTIONS:

  1. The ability to create keyboard hotkey shortcuts (on desktop releases) example: I love listening to my own music while gaming online, sometimes I want to thumbs up a track, but am unable to switch apps and use the mouse, so the ability to designate whatever key, to whatever commonly used function the user wishes to define in the settings would be really nice.
  2. The ability to fastforward, or rewind by holding down, or otherwise using hotkeys from another window.

I'm virtually certain this is in the wrong place, but am unfamiliar with github and busy with something else... so here you go. Thanks!

@Zo-Bro-23
Copy link
Contributor

I'm virtually certain this is in the wrong place

Moved it to #947!

`xml_logo_ascii`
`xml_logo_icons`
`xml_logo_icons_notext`
`xml_hero`
`xml_banner_bottom`
`xml_banner_top_custom`
`xml_banner_centered_bottom`
`xml_banner_centered_top`
@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

@th-ch @Zo-Bro-23 @MiepHD @Liknox or anyone who might see this

What do you think of the presets?
Should they all be added as options or just some of them?

xml_banner_top_custom + xml_banner_centered_bottom + xml_banner_centered_top have a gap on the top part of the toast since they use an invisible character to make the top text invisible and render other text instead (not sure if those are even worth it)

@MiepHD
Copy link
Contributor

MiepHD commented Jan 8, 2023

I'd let them choose between xml_hero, xml_logo_icons and

  • xml_logo_icons_notext would be an option for me if there were no gap under the buttons.
  • xml_logo_ascii could be used instead if the gap can't get removed. There I'd recommend to add some space between the | to get a square icon.

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

I've updated the post with my thoughts on each of them, but overall is there a reason not to include any of them?

more customization might be better if there isn't a tradeoff

I think I might just have a submenu called style where you can choose any of these styles using radio buttons.
Just have to think of good informative names for each of them

@Zo-Bro-23
Copy link
Contributor

This is AWESOME! Personally, don't really like the look of the ASCII versions, but it doesn't hurt to keep them in. The others are really visually pleasing, and of course, the more options the better (particularly love the hero and big banner ones)! How are you planning to implement these options though? Only if presented with a set of images like these will the user know which one to pick. Simply showing a list of big banner, hero, etc will be hard for the user to know what each one looks like. If you figure out a way to list all the possible options (maybe have a button that brings up a pop-up showing demos for how all these options look like), then you've got yourself a perfect feature! Looking forward to seeing this implemented 🙃

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

don't really like the look of the ASCII versions

Yeah if I made the interactive-notifications plugin from scratch today I probably wouldn't include something like that
But this is how it used to look so #LegacyOption

maybe have a button that brings up a pop-up showing demos for how all these options look like

very good idea 🌟 - will require quite a bit of additional code but might be worth it

Thanks for the encouragement :D

@Zo-Bro-23
Copy link
Contributor

Thanks for the encouragement :D

Psst... (got some feature ideas in #909, #831, and #945 - would be great if you could try implementing them!). Just giving me some tips on how to implement them would also be fine, and I can try working on them myself. Keep up the great work 😄

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

I've decided for now I'll do it like so:

const pluginOptions = {
	toastStyle: 1,  // 1-7
	hideButtonText: false
}

module.exports.ToastStyles = {
	logo: 1, // logo_icons 
	hero: 2,
	banner_top_custom: 3,
	banner_bottom: 4,
	banner_centered_bottom: 5,
	banner_centered_top: 6,
	legacy: 7 //  logo_ascii
}

hideButtonText effectively doubles the number of styles from 7 to 13 😂


Psst... (got some feature ideas in #909, #831, and #945 - would be great if you could try implementing them!). Just giving me some tips on how to implement them would also be fine, and I can try working on them myself. Keep up the great work 😄

I'll look into it when I have some downtime. meanwhile you can add me on discord Araxeus#0819

@Zo-Bro-23
Copy link
Contributor

const pluginOptions = {
	toastStyle: 1,  // 1-7
	hideButtonText: false
}

module.exports.ToastStyles = {
	logo: 1, // logo_icons 
	hero: 2,
	banner_top_custom: 3,
	banner_bottom: 4,
	banner_centered_bottom: 5,
	banner_centered_top: 6,
	legacy: 7 //  logo_ascii
}

So these are the options that will show up on the menu? If I understand this correctly, the user can manually select options like show_text, show_logo, etc instead of choosing from presets. That's great, then! (No need for having demo images in that case, although it never hurts to do that - I'm personally confused by some app options sometimes, so I have to try them out to see what they do)

I'll look into it when I have some downtime.

Cool, that's great! Thanks so much 😁

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

So these are the options that will show up on the menu?

image

If I understand this correctly, the user can manually select options like show_text, show_logo, etc instead of choosing from presets

No, the only customizable option right now is Hide Button Text, other than that its one of presets

show_logo

show_logo would just means it;s preset 1

@Zo-Bro-23
Copy link
Contributor

Oh. Having the image previews might be good in that case. Also try if you can have these as options, which will allow for more customization (mix-and-match of different settings).

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

Oh. Having the image previews might be good in that case. Also try if you can have these as options, which will allow for more customization (mix-and-match of different settings).

I understand your meaning, but think about it - what can you actually mix-and-match here? Each of the presets is unique.
that's why they are preset and not options

the only thing that I can think of that could be an option is Banner Position: top/bot but:

  • it's niche since it would affect only 2/5 of presets
  • the way the toast XML works, those are built completely differently and require a different template

compare that to Hide Button Text which just changes a string to empty (and affects every preset except legacy)

@Zo-Bro-23
Copy link
Contributor

I understand your meaning, but think about it - what can you actually mix-and-match here? Each of the presets is unique.
that's why they are preset and not options

You're right - my bad! The show button text is probably the only one that can be an option, and you've already incorporated that. I thought about having choices for the other properties, but that gets confusing, because you can't have BOTH hero and banner, and you can't have BOTH text above and text below. So I've got nothing more to add - presets are the best way to do this!

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 8, 2023

This PR is actually mostly complete now with 7052217 (#946) (Been working on it all day, this PR is quite long 😰)

If you are on windows, you can clone the branch and try it out! 🤘🚀

my favorite ended up being Banner Centered Top, by a fair margin. I'm even thinking of putting a star to its name


in toasts with banners the picture format depends on the kind of video you are watching:

  • Music Video - Rectangular 2x1
  • Non Video - Square 1x1 logo

It is done this way because changing the 1x1 to a 2x1 looks pretty bad,
tho that makes the "banner" name pretty confusing... maybe they should be renamed


maybe have a button that brings up a pop-up showing demos of how all these options look like

I'm not even sure this is needed anymore, you can just select any of them and it will automatically update without needing to restart the app

which makes it easy to test each of them (tho I agree a dedicated panel for a demo would be cool, as it stands I'm not sure there is that much to gain)

@Zo-Bro-23
Copy link
Contributor

If you are on windows, you can clone the branch and try it out! 🤘 🚀

My laptop's gone in for repair, so I'm on Ubuntu right now 🥲. Looking forward to testing it out when I get my laptop back!

menu.js Show resolved Hide resolved
providers/song-controls.js Show resolved Hide resolved
Comment on lines +17 to +24
const singleton = (fn) => {
let called = false;
return (...args) => {
if (called) return;
called = true;
return fn(...args);
}
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Can extract this function so that it is available app wide

@@ -61,7 +61,8 @@ const handleData = async (responseText, win) => {
songInfo.album = data?.videoDetails?.album; // Will be undefined if video exist

const oldUrl = songInfo.imageSrc;
songInfo.imageSrc = videoDetails.thumbnail?.thumbnails?.pop()?.url.split("?")[0];
Copy link
Collaborator Author

@Araxeus Araxeus Jan 9, 2023

Choose a reason for hiding this comment

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

Shouldn't use pop if not intending to change the original array
Wanted to use `.at(-1) but it requires node 16.6+ aka electron 23+

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Well it has been released since then
https://www.electronjs.org/blog/electron-23-0

but it drops support for Windows 7/8/8.1, so I'm unsure when should we bump that

@@ -95,15 +96,15 @@ const registerProvider = (win) => {
await handleData(responseText, win);
handlingData = false;
callbacks.forEach((c) => {
c(songInfo);
c(songInfo, "video-src-changed");
Copy link
Collaborator Author

@Araxeus Araxeus Jan 9, 2023

Choose a reason for hiding this comment

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

Unused right now, but now every plugin has the option to know whats the reason for the songInfo callback

@Araxeus Araxeus marked this pull request as ready for review January 9, 2023 20:56
Comment on lines 38 to 41
switch(config.get("toastStyle")) {
case module.exports.ToastStyles.logo:
case module.exports.ToastStyles.legacy:
return this.saveImage(nativeImageToLogo(songInfo.image), tempIcon);
Copy link
Collaborator Author

@Araxeus Araxeus Jan 12, 2023

Choose a reason for hiding this comment

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

This is inconsistent stylewise, I'm not sure which one should be used here

What do you think @th-ch ?😅
Should we use module.exports. or this.?

Copy link
Owner

Choose a reason for hiding this comment

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

No strong preference, this is fine :)

@Araxeus
Copy link
Collaborator Author

Araxeus commented Jan 16, 2023

@th-ch any thoughts?

@Araxeus Araxeus changed the title Native interactive notifications [Windows] [Notifications] [Windows] Native interactive notifications Jan 19, 2023
Copy link

@Liknox Liknox left a comment

Choose a reason for hiding this comment

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

Looks great, merge is expected.

Copy link
Owner

@th-ch th-ch left a comment

Choose a reason for hiding this comment

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

I did not test Windows specific features but looks good, thanks! ✅

@@ -131,16 +131,14 @@ const mainMenuTemplate = (win) => {
],
},
{
label: "Single instance lock",
label: "Release single instance lock",
Copy link
Owner

Choose a reason for hiding this comment

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

nit: it seems the button will request the lock it it does not have it, name can be misleading

Suggested change
label: "Release single instance lock",
label: "Single instance lock",

config = { ...config, ...options };
};

module.exports.setAndMaybeRestart = (option, value) => {
Copy link
Owner

Choose a reason for hiding this comment

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

nit: should we make the name more explicit? Sthg like

Suggested change
module.exports.setAndMaybeRestart = (option, value) => {
module.exports.setInMenu = (option, value) => {

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think setAndMaybeRestart is more explicit since the function name indicates that the difference is the restart option
setInMenu doesn't tell me much tbh

Comment on lines 38 to 41
switch(config.get("toastStyle")) {
case module.exports.ToastStyles.logo:
case module.exports.ToastStyles.legacy:
return this.saveImage(nativeImageToLogo(songInfo.image), tempIcon);
Copy link
Owner

Choose a reason for hiding this comment

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

No strong preference, this is fine :)

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.

6 participants