Initial commit
This commit is contained in:
parent
4cb1aa28a3
commit
2513fa6f9a
1
.gitignore
vendored
1
.gitignore
vendored
@ -9,6 +9,7 @@ __pycache__/
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
venv/
|
||||
env/
|
||||
build/
|
||||
develop-eggs/
|
||||
|
14
README.md
14
README.md
@ -1,3 +1,17 @@
|
||||
# py-reminder
|
||||
|
||||
Simple application to set reminders in python
|
||||
|
||||
## Dependencies
|
||||
|
||||
For development, we use the [black code formatter](https://black.readthedocs.io/en/stable/), and pylint as a linter
|
||||
|
||||
```
|
||||
pip install black pylint
|
||||
```
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
pip install pywin32
|
||||
```
|
||||
|
11
notify.py
Normal file
11
notify.py
Normal file
@ -0,0 +1,11 @@
|
||||
import os
|
||||
|
||||
def show_notification(title, msg):
|
||||
if os.name == 'nt':
|
||||
from notify_win import show_toast
|
||||
show_toast(title, msg)
|
||||
else:
|
||||
from gi.repository import Notify
|
||||
Notify.init(title)
|
||||
Notify.Notification.new(msg).show()
|
||||
Notify.uninit()
|
90
notify_win.py
Normal file
90
notify_win.py
Normal file
@ -0,0 +1,90 @@
|
||||
import os
|
||||
import logging
|
||||
import win32con
|
||||
import win32gui
|
||||
|
||||
from time import sleep
|
||||
|
||||
|
||||
class ToastNotifier:
|
||||
def show_toast(self, title, msg, icon_path=None, duration=5):
|
||||
message_map = {win32con.WM_DESTROY: self.on_destroy}
|
||||
# Register the Window class.
|
||||
wc = win32gui.WNDCLASS()
|
||||
wc.lpszClassName = "PythonTaskbar"
|
||||
wc.lpfnWndProc = message_map # could also specify a wndproc.
|
||||
|
||||
classAtom = win32gui.RegisterClass(wc)
|
||||
self.hinst = wc.hInstance = win32gui.GetModuleHandle(None)
|
||||
|
||||
# Create the Window.
|
||||
style = win32con.WS_OVERLAPPED | win32con.WS_SYSMENU
|
||||
self.hwnd = win32gui.CreateWindow(
|
||||
classAtom,
|
||||
"Taskbar",
|
||||
style,
|
||||
0,
|
||||
0,
|
||||
win32con.CW_USEDEFAULT,
|
||||
win32con.CW_USEDEFAULT,
|
||||
0,
|
||||
0,
|
||||
self.hinst,
|
||||
None,
|
||||
)
|
||||
win32gui.UpdateWindow(self.hwnd)
|
||||
|
||||
self.hicon = self._set_icon(icon_path)
|
||||
|
||||
flags = win32gui.NIF_ICON | win32gui.NIF_MESSAGE | win32gui.NIF_TIP
|
||||
nid = (self.hwnd, 0, flags, win32con.WM_USER + 20, self.hicon, "Tooltip")
|
||||
# Add a new notification icon
|
||||
win32gui.Shell_NotifyIcon(win32gui.NIM_ADD, nid)
|
||||
win32gui.Shell_NotifyIcon(
|
||||
win32gui.NIM_MODIFY,
|
||||
(
|
||||
self.hwnd,
|
||||
0,
|
||||
win32gui.NIF_INFO,
|
||||
win32con.WM_USER + 20,
|
||||
self.hicon,
|
||||
"Balloon Tooltip",
|
||||
msg,
|
||||
200,
|
||||
title,
|
||||
),
|
||||
)
|
||||
|
||||
sleep(duration)
|
||||
win32gui.DestroyWindow(self.hwnd)
|
||||
win32gui.UnregisterClass(wc.lpszClassName, None)
|
||||
|
||||
def _set_icon(self, icon_path):
|
||||
# icon
|
||||
if icon_path is not None:
|
||||
icon_path = os.path.realpath(icon_path)
|
||||
else:
|
||||
return None
|
||||
icon_flags = win32con.LR_LOADFROMFILE | win32con.LR_DEFAULTSIZE
|
||||
try:
|
||||
hicon = win32gui.LoadImage(
|
||||
self.hinst, icon_path, win32con.IMAGE_ICON, 0, 0, icon_flags
|
||||
)
|
||||
except Exception as e:
|
||||
logging.error("Some trouble with the icon ({}): {}".format(icon_path, e))
|
||||
hicon = win32gui.LoadIcon(0, win32con.IDI_APPLICATION)
|
||||
return hicon
|
||||
|
||||
def on_destroy(self, hwnd, msg, wparam, lparam):
|
||||
nid = (hwnd, 0)
|
||||
win32gui.Shell_NotifyIcon(win32gui.NIM_DELETE, nid)
|
||||
win32gui.PostQuitMessage(0)
|
||||
|
||||
|
||||
_notifier = ToastNotifier()
|
||||
def show_toast(title, msg, icon_path=None, duration=5):
|
||||
_notifier.show_toast(title, msg, icon_path=None, duration=5)
|
||||
|
||||
if __name__ == "__main__":
|
||||
toaster = ToastNotifier()
|
||||
toaster.show_toast("Hello world", "Test")
|
21
run.py
Normal file
21
run.py
Normal file
@ -0,0 +1,21 @@
|
||||
from schedule import Scheduler
|
||||
from notify import show_notification
|
||||
import datetime
|
||||
import time
|
||||
|
||||
|
||||
def notify_hello():
|
||||
show_notification("Hello world", "test")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
_scheduler = Scheduler()
|
||||
|
||||
# _scheduler.every(datetime.timedelta(seconds=3), lambda: print("Hello"))
|
||||
# _scheduler.at(datetime.timedelta(seconds=5), lambda: print("Should run only once"))
|
||||
|
||||
_scheduler.at(datetime.datetime(2019, 7, 1, 12, 4), notify_hello)
|
||||
|
||||
while True:
|
||||
_scheduler.run()
|
||||
time.sleep(1)
|
50
schedule.py
Normal file
50
schedule.py
Normal file
@ -0,0 +1,50 @@
|
||||
import time
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.DEBUG, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
|
||||
|
||||
class Job:
|
||||
def __init__(self, target, interval, times: int):
|
||||
self.target = target
|
||||
self.interval = interval
|
||||
self.next_run = datetime.datetime.now() + interval
|
||||
self.times = times
|
||||
self.last_run = None
|
||||
|
||||
@property
|
||||
def should_run(self):
|
||||
if self.times == 0:
|
||||
return False
|
||||
return datetime.datetime.now() >= self.next_run
|
||||
|
||||
def run(self):
|
||||
logging.info(f"Running job {self}")
|
||||
self.last_run = datetime.datetime.now()
|
||||
self.target()
|
||||
self.times -= 1
|
||||
self.next_run = self.last_run + self.interval
|
||||
logging.debug(f"Last run {self.last_run}")
|
||||
logging.debug(f"Next run {self.next_run}")
|
||||
logging.debug(f"Should run {self.should_run}")
|
||||
|
||||
|
||||
class Scheduler:
|
||||
jobs: [Job] = []
|
||||
|
||||
def every(self, interval: datetime.timedelta, target, times=-1):
|
||||
self.jobs.append(Job(target, interval, times))
|
||||
|
||||
def at(self, time, target):
|
||||
interval = time - datetime.datetime.now()
|
||||
self.jobs.append(Job(target, interval, 1))
|
||||
|
||||
def run(self):
|
||||
for job in self.jobs:
|
||||
if job.should_run:
|
||||
job.run()
|
||||
# else:
|
||||
# logging.info("No jobs to run…")
|
Loading…
Reference in New Issue
Block a user