-
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Custom sounds, app IDs and more (#1)
- Loading branch information
Showing
17 changed files
with
2,156 additions
and
901 deletions.
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
requirements*.lock | ||
|
||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,104 @@ | ||
# toasted | ||
|
||
Toast notifications library for Windows. Unlike other Windows toast libraries, Toasted is the one of the most comprehensive toast libraries. Because it supports all elements (images, progresses, texts, inputs, buttons...) that you probably never seen on a toast. Not only that, it also includes useful features found in the Notifications API. | ||
Yet another notifications library for Windows, written in Python, built using Windows Runtime APIs (WinRT). | ||
|
||
> Struggling with making a GUI for your script? Say no more. | ||
Compared to other toast libraries, Toasted supports all notification elements provided by Windows, such as; inputs, selects, buttons, images, different text styles... so you are not just limited to single line of text. | ||
|
||
Since Windows **restricts use of some features of toast notifications in unpackaged non-UWP apps**, Toasted also handles this cases _in the best way possible_ to mimic the behaviour of UWP apps, for example; HTTP(S) URIs are first downloaded to a temporary directory and then used as a local file, Windows URIs like `ms-appx` and `ms-appdata` are set relative to special directories [and so on.](#special-behaviours) | ||
|
||
![](.github/assets/preview.png) | ||
|
||
It works on Windows 10 and up, though outdated/initial builds of Windows 10 may not work as it doesn't include all Notification APIs used in the library. | ||
|
||
> I'm using Linux in my daily life, and the reason why I created this library even I use Linux is that I started working on this library before my switch to Linux. So I currently use a separate Windows device to develop Toasted on, which may affect my development time. Therefore, while I'm trying to do my best and keep the library updated, do not expect regular updates. | ||
If other systems would provide APIs and features to create rich libraries as on Windows, I would have love to add support for other systems, but as the library is focusing/relying on Windows APIs more in each update, it is not possible to make it cross-platform at the moment. | ||
|
||
Toast notifications can also be preferred to develop rapid GUIs for your Windows-only Python projects. | ||
|
||
## Install | ||
|
||
``` | ||
python -m pip install toasted | ||
``` | ||
|
||
## Example | ||
## Usage | ||
|
||
See [`showcase.py`](./examples/showcase.py) for an introduction to the library with detailed example toast notification configurations. | ||
|
||
## Special behaviours | ||
|
||
Windows API restricts use of some features of toast notifications for non-UWP/non-packaged apps, Toasted contains bunch of conveinence features to mimic the behaviour of UWP apps and get the most of the toast features of Windows. | ||
|
||
### Remote images (HTTP URIs as image sources) | ||
|
||
Normally, Windows restricts the use of HTTP images and only allows local file paths on non-UWP applications. But to overcome the limitation, Toasted downloads HTTP images to `%TEMP%` and replaces the link with downloaded local file before showing the toast. Downloaded files **are deleted** once toast has dismissed/clicked to not leave traces on the system. | ||
|
||
Also, to comply with Windows API, you can enable sending system theme information (such as `ms-lang`, `ms-theme`, `ms-contrast`) to given URLs as query parameters by setting `add_query_params` property, so if you are serving files from your web server, you can serve different images based on the system theme. | ||
|
||
### Application icon and name (app IDs) | ||
|
||
Notifications in Windows must be bound to an **application registered in system.** So, when you tell Windows that you are sending notifications from Python executable, it will send the toast **on behalf of the given application,** thus the application's own name and icon will appear in the toast title. | ||
|
||
If you don't set a custom `app_id`, it will use the path where Python has installed. (`sys.executable`) But note that this won't work with virtual environments as there won't be a Python that registered on the system. | ||
|
||
However Toasted provides a `register_app_id()` method to register a new "App ID" (or AUMID) in `Foo.Bar.Example` format to the Windows Registry, so you can use your own app ID in your toasts and Windows will show on behalf of your app ID, so you can set the application icon and name as you wish. | ||
|
||
Registering an app ID doesn't require a reboot on the system, so you can register an app ID just before sending a toast, however, **you need to make sure that all notifications sent by Toasted are cleared from Action Center** to make Windows to use the updated application icon and name. | ||
|
||
```py | ||
import asyncio | ||
from typing import Dict | ||
from toasted import Toast, Text | ||
|
||
# Create Toast with Toast(), | ||
# see docstring for all available parameters. | ||
mytoast = Toast() | ||
|
||
# Add elements. | ||
mytoast += Text("Hello world!") # Using += operator. | ||
mytoast.data.append(Text("Hello world!")) # Or access the inner list with Toast.data. | ||
|
||
# Set up a handler. | ||
# This handler will be executed when toasted has clicked or dismissed. | ||
@mytoast.handler | ||
def myhandler(arguments : str, user_input : Dict[str, str], dismiss_reason : int): | ||
# dismiss_reason will set to a value higher than or equals to 0 when dismissed, | ||
# -1 means a toast or button click. | ||
if dismiss_reason == -1: | ||
print("Got arguments:", arguments) | ||
else: | ||
print("Toast has dismissed:", dismiss_reason) | ||
|
||
# Run show() async function. | ||
asyncio.run(mytoast.show()) | ||
# Applications can be registered outside of Python since it just adds registry keys to Windows. | ||
# This is just a shortcut method to do that. | ||
# https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/send-local-toast-other-apps | ||
app_id = Toast.register_app_id("MyOrg.MyDomain.MyPhone", "My Phone App") | ||
|
||
# Setting app_id property causes Python to tell Windows that the currently running process is running | ||
# under the specified application ID (MyOrg.MyDomain.MyPhone) instead of Python executable. | ||
# If an app_id has not set, the default app_id is used which is sys.executable. | ||
mytoast = Toast(app_id = app_id) | ||
|
||
# Or you can change app_id later instead of constructor. | ||
mytoast.app_id = app_id | ||
``` | ||
|
||
## Highlights | ||
> [!WARNING] | ||
> Since these app ID registrations are made in Windows Registry, this will leave traces in system even after your Python program is no longer running. You can unregister the application by `unregister_app_id()` method. | ||
### Custom sounds | ||
|
||
If an custom sound has provided, toast's own sound will be muted and Python's `winsound` module will be used instead. Also, sounds from HTTP sources are supported too instead of just file paths. | ||
|
||
### Use images of Windows system icons | ||
|
||
Toasted can create images of Unicode characters in Windows icon fonts ([Segoe Fluent](https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-fluent-icons-font) and [Segoe MDL2](https://learn.microsoft.com/en-us/windows/apps/design/style/segoe-ui-symbol-font)) with `get_icon_from_font()` utility method. | ||
|
||
A custom URI has also been added for convenience, for example if you set `icon://E706` as a source in image element, it will show a screen brightness icon (`U+E706`) from "Segoe MDL2" (pre-installed on Windows 10 and up) or "Segoe Fluent" (pre-installed on Windows 11 and up) font. Toasted will prefer using MDL2 font if it is running on Windows 10, or Fluent, if running on Windows 11. | ||
|
||
## Advanced | ||
|
||
### Update toast content (Data binding) | ||
|
||
* **Remote (HTTP) images support** | ||
<br>Normally, Windows restricts the use of HTTP images and only allows local file paths on non-UWP applications. But to overcome the limitation, Toasted downloads HTTP images to %TEMP%, so you can now use images from web without any configuration! Downloaded images are deleted once toast has dismissed / clicked. Also, to comply with Windows API, you can enable sending system information (such as `ms-lang`, `ms-theme`, `ms-contrast`) to remote sources as query parameters by setting `add_query_params` property. | ||
Properties in toast elements can have a binding value, which is done by simply putting a key surrounded with curly braces like, `{myProgress}`. Then, you can set a new value for `myProgress` key with `show()` to set its initial value and with `update()` to update toast in-place without showing a new toast. | ||
|
||
This is useful for updating toast progress bars without displaying a new toast for each step. Since data binding is a feature provided by Windows API itself, not all elements may support this feature, so Toasted has no control over this. | ||
|
||
## Unimplemented features | ||
|
||
My initial goal was to bring most if not all toast features to Python, but unfortunately there are some notification features that are not supported/implemented on this library. Below is a non extensive list of these: | ||
|
||
* [Collections](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-collections) | ||
* [Pending updates & background events](https://learn.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-pending-update?tabs=builder-syntax), seems to require a COM server. | ||
|
||
## Building | ||
|
||
``` | ||
python -m pip wheel . | ||
``` | ||
|
||
* **Update toast content (Data binding)** | ||
<br>Properties in toast elements can have a binding/dynamic/reference value, which is done by simply putting a key surrounded with curly braces like, `{myProgress}`. Then, you can set a new value for `myProgress` key before showing toast with `show()`, and with `update()` to update toast in-place without showing a new toast. | ||
Or if you use [rye](https://rye-up.com/), `rye build`. | ||
|
||
* **Import from JSON** | ||
<br>Notification elements and their properties can be imported with dictionaries (JSON-accepted types) with `Toast.from_json()`, so you can add more than one element by calling a single method. See example JSON configurations [here.](examples) | ||
|
||
## Notes | ||
## License | ||
|
||
* As you can see from screenshot, it is not possible to change "Python" title in normal ways, since Windows requires a "source application" to show notifications from. However, [Toast collections](https://docs.microsoft.com/en-us/windows/apps/design/shell/tiles-and-notifications/toast-collections) allows to override app icon, but I'm not sure how I can implement this (or even, is it possible for a non-UWP app?), so still working on it. | ||
Source code is licensed under MIT license. You must include the license notice in all copies or substantial uses of the work. |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.