GitHub30 / win11toast

Toast notifications for Windows 10 and 11 based on WinRT
https://pypi.org/project/win11toast/
MIT License
227 stars 15 forks source link

Is it possible for the `on_click` lambda function to fire even when the notification has timed out #20

Closed ZhangTianrong closed 1 year ago

ZhangTianrong commented 1 year ago

I am trying to create a REST api, such that a request can trigger a toast and clicking the toast copies the content of the request to the clipboard. Something like:

from win11toast import toast_async
from flask import Flask, request

app = Flask(__name__)

@app.route("/toast", methods=['POST'])
async def get_data():
    content = request.form["content"]
    await toast_async(content, "click to copy", on_click=lambda _:pyclip.copy(content))
    return 'OK'

It works fine when the notification first show up but doesn't work when it times out and gets stored in the notification center. Is it possible not to mark the dismissed_future as done when the dismissed reason is TIMED_OUT?

I am not familiar enough with asyncio, so I just made the following modifications to line 355 in win11toast.py:

dismissed_token = notification.add_dismissed(
    lambda _, event_args: None if ToastDismissedEventArgs._from(event_args).reason == 2 else loop.call_soon_threadsafe(
    dismissed_future.set_result, on_dismissed(result_wrapper(ToastDismissedEventArgs._from(event_args).reason)))
)

It seems to be working, but I am not sure.

GitHub30 commented 1 year ago

Thank you for your comment. You can solve it by generating a python file.

https://user-images.githubusercontent.com/12811398/224033287-8eae0221-a33e-4475-96ae-52bdaf9ac7cf.mp4

import tempfile
from flask import Flask, request
from win11toast import notify

app = Flask(__name__)

@app.route('/toast', methods=['POST'])
def hello_world():
    content = request.form['content']
    fp = tempfile.NamedTemporaryFile(suffix='.pyw', delete=False)
    fp.write(f'import pyclip;pyclip.copy("{content}")'.encode())
    notify(content, 'click to copy', on_click=fp.name)
    return 'OK'
jaydeepjondhale commented 1 year ago

@GitHub30 is there any way to do this same without using tempfile?

ZhangTianrong commented 1 year ago

@GitHub30 is there any way to do this same without using tempfile?

As I mentioned before, you can achieve the same result by modifying the on_dismissed handler. In this way, the thread for the notification is not terminated even if it times out and sits in the notification center until you click on it or delete it. It is not a very graceful solution because potentially there can be too many threads running if you keep a lot of notifications in the notification center. One walkaround I have thought of is to pass the content of the notification in an url by registering a specific url protocol like mynotify:// and configuring the corresponding open command to be a pyw file which parses the arguments and do whatever stuff you want.