Skip to content

Commit

Permalink
changed stuff for the better
Browse files Browse the repository at this point in the history
  • Loading branch information
gornostal committed Apr 17, 2017
1 parent a40d620 commit 9776680
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 63 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.cache
*.pyc
__pycache__
Binary file added images/timer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
51 changes: 2 additions & 49 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,51 +1,4 @@
from ulauncher.extension.client.Extension import Extension
from ulauncher.extension.client.EventListener import EventListener
from ulauncher.extension.shared.event import KeywordQueryEvent, ItemEnterEvent
from ulauncher.extension.shared.result_item.ExtensionResultItem import ExtensionResultItem
from ulauncher.result_list.item_action.RenderResultListAction import RenderResultListAction


class FileFindExtension(Extension):

def __init__(self, *args, **kw):
super(FileFindExtension, self).__init__(*args, **kw)
self.file_db = FileDb()
dirs = '\n'.split(config.prefs.get('watch_dirs'))
watcher = FileWatcher(self.file_db)
watcher.watch(dirs)
self.subscribe(KeywordQueryEvent, ExtensionKeywordListener(self.file_db, config))
self.subscribe(ItemEnterEvent, ItemEnterEventListener(self.file_db, config))


class ExtensionKeywordListener(EventListener):

def __init__(self, file_db, config):
self.file_db = file_db
super(ExtensionKeywordListener, self).__init__()

def on_event(self, event):
query = event.get_query()
files = self.file_db.find(query, limit=9)
result_list = []
for file in files:
result_list.append(ExtensionResultItem(name=file.get_name(),
icon=file.get_icon(),
description=file.get_path(),
enter_action=ExtensionCustomAction(file, True)))

return RenderResultListAction(result_list)


class ItemEnterEventListener(EventListener):

def __init__(self, file_db, config):
self.file_db = file_db
super(ItemEnterEventListener, self).__init__()

def on_event(self, event):
file = event.get_data()
OpenAction(file.get_path()).run() # or return action?

from timer.TimerExtension import TimerExtension

if __name__ == '__main__':
Extension().run()
TimerExtension().run()
16 changes: 2 additions & 14 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,14 @@
"description": "Countdown timer with notifications",
"developer_name": "Aleksandr Gornostal",
"icon": "images/timer.png",
"screenshot": "images/screenshot.png",
"options": {
"query_debounce": 0.05
},
"preferences": [
{
"id": "main_kw",
"id": "keyword",
"type": "keyword",
"default_value": "ti",
},
{
"id": "name",
"type": "input",
"default_value": "?",
"description": "..."
},
{
"id": "description",
"type": "text",
"description": "About you"
"default_value": "ti"
}
]
}
3 changes: 3 additions & 0 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[tool:pytest]
pep8maxlinelength = 120
pep8ignore = E402
3 changes: 3 additions & 0 deletions test
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/bash

eval "PYTHONPATH=`pwd` py.test --pep8 $@"
19 changes: 19 additions & 0 deletions tests/timer/test_query_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import pytest
from timer.query_parser import parse_query, ParseQueryError


def test_parse_query__5m_hello_world__correct_result_returned():
assert parse_query('5m hello world') == (5 * 60, '5 minutes', 'hello world')


def test_parse_query__5h_hello_world__correct_result_returned():
assert parse_query('5h hello world') == (5 * 60 * 60, '5 hours', 'hello world')


def test_parse_query__5__is_correct_query():
assert parse_query('5') == (5 * 60, '5 minutes', 'Time is up!')


def test_parse_query__incorrect_query__ParseQueryError():
with pytest.raises(ParseQueryError):
assert parse_query('wfa')
36 changes: 36 additions & 0 deletions timer/ExtensionKeywordListener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from ulauncher.extension.client.EventListener import EventListener
from ulauncher.extension.shared.result_item.ExtensionResultItem import ExtensionResultItem
from ulauncher.result_list.item_action.RenderResultListAction import RenderResultListAction
from ulauncher.result_list.item_action.CloseAppAction import CloseAppAction
from ulauncher.result_list.item_action.DoNothingAction import DoNothingAction
from ulauncher.result_list.item_action.ExtensionCustomAction import ExtensionCustomAction
from .query_parser import parse_query, ParseQueryError


class ExtensionKeywordListener(EventListener):

def __init__(self, icon_file):
self.icon_file = icon_file

def get_action_to_render(self, name, description, on_enter=None):
item = ExtensionResultItem(name=name,
description=description,
icon=self.icon_file,
on_enter=on_enter or DoNothingAction())

return RenderResultListAction([item])

def on_event(self, event, extension):
query = event.get_argument()
if query:
try:
time_sec, delta, message = parse_query(query)
return self.get_action_to_render(name="Set timer for %s" % delta,
description="Message: %s" % message,
on_enter=ExtensionCustomAction((time_sec, message)))
except ParseQueryError:
return self.get_action_to_render(name="Incorrect request",
description="Example: ti 10m Eggs are ready!")
else:
return self.get_action_to_render(name="Type in your query",
description="Example: ti 10m Eggs are ready!")
13 changes: 13 additions & 0 deletions timer/ItemEnterEventListener.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import logging
from ulauncher.extension.client.EventListener import EventListener

logger = logging.getLogger(__name__)


class ItemEnterEventListener(EventListener):

def on_event(self, event, extension):
delay, message = event.get_data()
extension.set_timer(delay, message)
extension.show_notification('Timer is set', make_sound=False)
logger.debug('Timer is set. Delay %s' % delay)
48 changes: 48 additions & 0 deletions timer/TimerExtension.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import os
import subprocess
import gi
import logging

gi.require_version('Gtk', '3.0')
gi.require_version('Notify', '0.7')

from gi.repository import Notify
from threading import Timer

from ulauncher.extension.shared.event import KeywordQueryEvent, ItemEnterEvent
from ulauncher.extension.client.Extension import Extension
from .ExtensionKeywordListener import ExtensionKeywordListener
from .ItemEnterEventListener import ItemEnterEventListener

logger = logging.getLogger(__name__)


class TimerExtension(Extension):

SOUND_FILE = "/usr/share/sounds/freedesktop/stereo/complete.oga"
ICON_FILE = 'images/timer.png'

timer = None

def __init__(self):
super(TimerExtension, self).__init__()
self.icon_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), self.ICON_FILE)
self.subscribe(KeywordQueryEvent, ExtensionKeywordListener(self.ICON_FILE))
self.subscribe(ItemEnterEvent, ItemEnterEventListener())

def set_timer(self, delay, text):
self.timer = Timer(delay, self.show_notification, args=[text])
self.timer.setDaemon(True)
self.timer.start()

def stop_timer(self):
if self.timer:
self.timer.stop()
self.timer = None

def show_notification(self, text, make_sound=True):
logger.debug('Show notification: %s' % text)
Notify.init("TimerExtension")
Notify.Notification.new("Timer", text, self.icon_path).show()
if make_sound:
subprocess.call(("paplay", self.SOUND_FILE))
Empty file added timer/__init__.py
Empty file.
47 changes: 47 additions & 0 deletions timer/query_parser.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import re
from dateutil.relativedelta import relativedelta


TIME_MULT = {
'h': 60 * 60,
'm': 60,
's': 1
}
ATTRS = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']


def parse_query(query, default_text='Time is up!'):
"""
>>> '5m hello world'
<<< (300, '5 minutes', 'hello world')
>>> '3h Go'
<<< (3*60*60, '3 hours', 'Go')
>>> '5'
<<< (300, '5 minutes', 'Time is up!')
"""
try:
time_arg = query.split(' ')[0]
assert time_arg, "Incorrect time"
m = re.match(r'^(?P<time>\d+)(?P<measure>[mhs])?$', time_arg, re.I)
time_sec = int(m.group('time')) * TIME_MULT[(m.group('measure') or 'm').lower()]

message = ' '.join(query.split(' ')[1:]).strip()
message = message or default_text

return (time_sec, ' '.join(human_readable(time_sec)), message)
except Exception as e:
raise ParseQueryError(e.message)


def human_readable(seconds):
"""
>>> 125
<<< ['2 hours', '5 minutes']
"""
delta = relativedelta(seconds=seconds)
return ['%d %s' % (getattr(delta, attr), getattr(delta, attr) > 1 and attr or attr[:-1])
for attr in ATTRS if getattr(delta, attr)]


class ParseQueryError(Exception):
pass

0 comments on commit 9776680

Please sign in to comment.