Add disable for given time
This commit is contained in:
parent
74e48de67c
commit
ef156bfb0c
|
@ -16,22 +16,19 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import gi
|
||||
import locale
|
||||
import logging
|
||||
import gi, logging, threading, datetime, Utility
|
||||
gi.require_version('Gtk', '3.0')
|
||||
gi.require_version('AppIndicator3', '0.1')
|
||||
from gi.repository import Gtk, Gdk, GLib, GdkX11
|
||||
from gi.repository import AppIndicator3 as appindicator
|
||||
|
||||
# Global variables
|
||||
active = True
|
||||
APPINDICATOR_ID = 'safeeyes'
|
||||
|
||||
|
||||
class TrayIcon:
|
||||
|
||||
def __init__(self, language, on_show_settings, on_show_about, on_enable, on_disable, on_quite):
|
||||
def __init__(self, config, language, on_show_settings, on_show_about, on_enable, on_disable, on_quite):
|
||||
logging.info("Initialize the tray icon")
|
||||
self.on_show_settings = on_show_settings
|
||||
self.on_show_about = on_show_about
|
||||
|
@ -40,6 +37,9 @@ class TrayIcon:
|
|||
self.on_disable = on_disable
|
||||
self.language = language
|
||||
self.dateTime = None
|
||||
self.active = True
|
||||
self.idle_condition = threading.Condition()
|
||||
self.lock = threading.Lock()
|
||||
|
||||
# Construct the tray icon
|
||||
self.indicator = appindicator.Indicator.new(
|
||||
|
@ -57,11 +57,46 @@ class TrayIcon:
|
|||
|
||||
self.item_separator = Gtk.SeparatorMenuItem()
|
||||
|
||||
# Enable menu item with check box
|
||||
self.item_enable = Gtk.CheckMenuItem()
|
||||
self.item_enable.set_active(True)
|
||||
# Enable/Disable menu item
|
||||
self.item_enable = Gtk.MenuItem()
|
||||
self.item_enable.connect('activate', self.on_toogle_enable)
|
||||
|
||||
self.sub_menu_disable = Gtk.Menu()
|
||||
|
||||
# Read disable options and build the sub menu
|
||||
for disable_option in config['disable_options']:
|
||||
time_in_minutes = disable_option['time']
|
||||
# Validate time value
|
||||
if not isinstance(time_in_minutes, int) or time_in_minutes <= 0:
|
||||
logging.error('Invalid time in disable option: ' + str(time_in_minutes))
|
||||
continue
|
||||
time_unit = disable_option['unit'].lower()
|
||||
if time_unit == 'seconds' or time_unit == 'second':
|
||||
time_in_minutes = int(time_in_minutes / 60)
|
||||
elif time_unit == 'minutes' or time_unit == 'minute':
|
||||
time_in_minutes = int(time_in_minutes * 1)
|
||||
elif time_unit == 'hours' or time_unit == 'hour':
|
||||
time_in_minutes = int(time_in_minutes * 60)
|
||||
else:
|
||||
# Invalid unit
|
||||
logging.error('Invalid unit in disable option: ' + str(disable_option))
|
||||
continue
|
||||
|
||||
# Create submenu
|
||||
sub_menu_item = Gtk.MenuItem()
|
||||
sub_menu_item.connect('activate', self.on_toogle_enable, time_in_minutes)
|
||||
sub_menu_item.set_label(self.language['ui_controls'][disable_option['label']].format(disable_option['time']))
|
||||
self.sub_menu_disable.append(sub_menu_item)
|
||||
|
||||
# Disable until restart submenu
|
||||
sub_menu_item = Gtk.MenuItem()
|
||||
sub_menu_item.connect('activate', self.on_toogle_enable, -1)
|
||||
sub_menu_item.set_label(self.language['ui_controls']['until_restart'])
|
||||
self.sub_menu_disable.append(sub_menu_item)
|
||||
|
||||
# Add the sub menu to the enable/disable menu
|
||||
self.item_enable.set_submenu(self.sub_menu_disable)
|
||||
|
||||
# Settings menu item
|
||||
self.item_settings = Gtk.MenuItem()
|
||||
self.item_settings.connect('activate', self.show_settings)
|
||||
|
@ -74,12 +109,17 @@ class TrayIcon:
|
|||
self.item_quit = Gtk.MenuItem()
|
||||
self.item_quit.connect('activate', self.quit_safe_eyes)
|
||||
|
||||
self.set_labels(language)
|
||||
self.item_info.set_label(self.language['messages']['disabled_until_restart'])
|
||||
self.item_enable.set_label(self.language['ui_controls']['disable'])
|
||||
self.item_settings.set_label(self.language['ui_controls']['settings'])
|
||||
self.item_about.set_label(self.language['ui_controls']['about'])
|
||||
self.item_quit.set_label(self.language['ui_controls']['quit'])
|
||||
|
||||
# Append all menu items and show the menu
|
||||
self.menu.append(self.item_info)
|
||||
self.menu.append(self.item_separator)
|
||||
self.menu.append(self.item_enable)
|
||||
# self.menu.append(self.item_disable)
|
||||
self.menu.append(self.item_settings)
|
||||
self.menu.append(self.item_about)
|
||||
self.menu.append(self.item_quit)
|
||||
|
@ -87,30 +127,21 @@ class TrayIcon:
|
|||
|
||||
self.indicator.set_menu(self.menu)
|
||||
|
||||
def set_labels(self, language):
|
||||
self.language = language
|
||||
active = self.item_enable.get_active()
|
||||
if active:
|
||||
if self.dateTime:
|
||||
self.set_next_break_info(self.dateTime)
|
||||
else:
|
||||
self.item_info.set_label(self.language['messages'][
|
||||
'safe_eyes_is_disabled'])
|
||||
self.item_enable.set_label(self.language['ui_controls']['enable'])
|
||||
self.item_settings.set_label(self.language['ui_controls']['settings'])
|
||||
self.item_about.set_label(self.language['ui_controls']['about'])
|
||||
self.item_quit.set_label(self.language['ui_controls']['quit'])
|
||||
|
||||
def show_icon(self):
|
||||
GLib.idle_add(lambda: self.indicator.set_status(
|
||||
appindicator.IndicatorStatus.ACTIVE))
|
||||
Utility.execute_main_thread(self.indicator.set_status, appindicator.IndicatorStatus.ACTIVE)
|
||||
|
||||
def hide_icon(self):
|
||||
GLib.idle_add(lambda: self.indicator.set_status(
|
||||
appindicator.IndicatorStatus.PASSIVE))
|
||||
Utility.execute_main_thread(self.indicator.set_status, appindicator.IndicatorStatus.PASSIVE)
|
||||
|
||||
def quit_safe_eyes(self, *args):
|
||||
self.on_quite()
|
||||
with self.lock:
|
||||
self.active = True
|
||||
# Notify all schedulers
|
||||
self.idle_condition.acquire()
|
||||
self.idle_condition.notify_all()
|
||||
self.idle_condition.release()
|
||||
|
||||
def show_settings(self, *args):
|
||||
self.on_show_settings()
|
||||
|
@ -124,23 +155,50 @@ class TrayIcon:
|
|||
self.set_next_break_info(self.dateTime)
|
||||
|
||||
def set_next_break_info(self, dateTime):
|
||||
formatted_time = dateTime.strftime(locale.nl_langinfo(locale.T_FMT))
|
||||
formatted_time = Utility.format_time(dateTime)
|
||||
message = self.language['messages'][
|
||||
'next_break_at'].format(formatted_time)
|
||||
|
||||
GLib.idle_add(lambda: self.item_info.set_label(message))
|
||||
Utility.execute_main_thread(self.item_info.set_label, message)
|
||||
|
||||
def on_toogle_enable(self, *args):
|
||||
active = self.item_enable.get_active()
|
||||
if active:
|
||||
logging.info("Enable Safe Eyes")
|
||||
# active = self.item_enable.get_active()
|
||||
if args[0] == self.item_enable and not self.active:
|
||||
with self.lock:
|
||||
logging.info('Enable Safe Eyes')
|
||||
self.active = True
|
||||
self.indicator.set_icon("safeeyes_enabled")
|
||||
self.item_info.set_sensitive(True)
|
||||
self.on_enable()
|
||||
else:
|
||||
logging.info("Disable Safe Eyes")
|
||||
self.item_enable.set_label(self.language['ui_controls']['disable'])
|
||||
self.item_enable.set_submenu(self.sub_menu_disable)
|
||||
# Notify all schedulers
|
||||
self.idle_condition.acquire()
|
||||
self.idle_condition.notify_all()
|
||||
self.idle_condition.release()
|
||||
elif args[0] != self.item_enable and self.active:
|
||||
logging.info('Disable Safe Eyes')
|
||||
self.active = False
|
||||
self.indicator.set_icon("safeeyes_disabled")
|
||||
self.item_info.set_label(self.language['messages'][
|
||||
'safe_eyes_is_disabled'])
|
||||
self.item_info.set_sensitive(False)
|
||||
self.on_disable()
|
||||
self.item_enable.set_label(self.language['ui_controls']['enable'])
|
||||
self.item_enable.set_submenu(None)
|
||||
|
||||
time_to_wait = args[1]
|
||||
if time_to_wait <= 0:
|
||||
self.item_info.set_label(self.language['messages']['disabled_until_restart'])
|
||||
else:
|
||||
wakeup_time = datetime.datetime.now() + datetime.timedelta(minutes=time_to_wait)
|
||||
Utility.start_thread(self.__schedule_resume, args={'time_minutes': time_to_wait})
|
||||
self.item_info.set_label(self.language['messages']['disabled_until_x'].format(Utility.format_time(wakeup_time)))
|
||||
|
||||
|
||||
def __schedule_resume(self, time_minutes):
|
||||
self.idle_condition.acquire()
|
||||
self.idle_condition.wait(time_minutes * 60) # Convert to seconds
|
||||
self.idle_condition.release()
|
||||
|
||||
with self.lock:
|
||||
if not self.active:
|
||||
Utility.execute_main_thread(self.item_enable.activate)
|
||||
|
|
|
@ -53,7 +53,10 @@ def start_thread(target_function, args=None):
|
|||
"""
|
||||
Execute the given function in main thread.
|
||||
"""
|
||||
def execute_main_thread(target_function):
|
||||
def execute_main_thread(target_function, args=None):
|
||||
if args:
|
||||
GLib.idle_add(lambda: target_function(args))
|
||||
else:
|
||||
GLib.idle_add(lambda: target_function())
|
||||
|
||||
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Připravte se na přestávku za {} sekund",
|
||||
"safe_eyes_is_disabled": "Safe Eyes je zakázáno",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Příští přestávka v {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -35,6 +36,11 @@
|
|||
"audible_alert": "Zvukové upozornění na konec přestávky",
|
||||
"language": "Jazyk",
|
||||
"enable": "Povolit Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Nastavení",
|
||||
"about": "O programu",
|
||||
"quit": "Ukončit",
|
||||
|
|
|
@ -20,10 +20,9 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Nächste Pause in {} Sekunden",
|
||||
"safe_eyes_is_disabled": "Safe Eyes ist deaktiviert",
|
||||
"next_break_at_noon": "Nächste Pause um {}",
|
||||
"next_break_at_am": "Nächste Pause um {} AM",
|
||||
"next_break_at_pm": "Nächste Pause um {} PM"
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Nächste Pause um {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
"skip": "Überspringen",
|
||||
|
@ -37,6 +36,11 @@
|
|||
"audible_alert": "Akustisches Signal am Ende der Pause",
|
||||
"language": "Sprache",
|
||||
"enable": "Safe Eyes Aktivieren",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Einstellungen",
|
||||
"about": "About",
|
||||
"quit": "Schließen",
|
||||
|
|
|
@ -20,14 +20,15 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Ready for a break in {} seconds",
|
||||
"safe_eyes_is_disabled": "Safe Eyes is disabled",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Next break at {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
"skip": "Skip",
|
||||
"short_break_duration": "Short break duration (in seconds)",
|
||||
"long_break_duration": "Long break duration (in seconds)",
|
||||
"interval_between_two_breaks": "Interval between two breaks",
|
||||
"interval_between_two_breaks": "Interval between two breaks (in minutes)",
|
||||
"no_of_short_breaks_between_two_long_breaks": "Number of short breaks between two long breaks",
|
||||
"time_to_prepare_for_break": "Time to prepare for break (in seconds)",
|
||||
"idle_time": "Minimum idle time to pause (in minutes)",
|
||||
|
@ -35,6 +36,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Language",
|
||||
"enable": "Enable Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Settings",
|
||||
"about": "About",
|
||||
"quit": "Quit",
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Listo para una pausa en {} segundos",
|
||||
"safe_eyes_is_disabled": "Safe Eyes está desactivado",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Próxima pausa a las {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -35,6 +36,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Idioma",
|
||||
"enable": "Activar Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Preferencias",
|
||||
"about": "Acerca de",
|
||||
"quit": "Salir",
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Prêt pour une pause dans {} secondes",
|
||||
"safe_eyes_is_disabled": "Safe Eyes est désactivé",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Prochaine pause à {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -34,6 +35,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "La language",
|
||||
"enable": "Activer Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Réglages",
|
||||
"about": "À propos",
|
||||
"quit": "Quitter",
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Tervezett szünet {} másodperc múlva!",
|
||||
"safe_eyes_is_disabled": "Safe Eyes kikapcsolva",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "A következő szünet {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -33,6 +34,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Nyelv",
|
||||
"enable": "Safe Eyes Bekapcsolása",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Beállítások",
|
||||
"about": "Ról ről",
|
||||
"quit": "Kilépés",
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Pronto para uma pausa em {} segundos",
|
||||
"safe_eyes_is_disabled": "Safe Eyes está desabilitado",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Próxima pausa em {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -35,6 +36,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Língua",
|
||||
"enable": "Habilitar Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Configuração",
|
||||
"about": "Sobre",
|
||||
"quit": "Sair",
|
||||
|
|
|
@ -20,7 +20,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Приготовьтесь к перерыву через {} секунд",
|
||||
"safe_eyes_is_disabled": "Safe Eyes отключен",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Следующий перерыв в {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -35,6 +36,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Язык",
|
||||
"enable": "Активировать Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Настройки",
|
||||
"about": "О программе",
|
||||
"quit": "Выйти",
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "Priprav sa na prestávku o {} sekúnd",
|
||||
"safe_eyes_is_disabled": "Safe Eyes sú zablokované",
|
||||
"disabled_until_restart": "Disabled until restart",
|
||||
"disabled_until_x": "Disabled until {}",
|
||||
"next_break_at": "Ďalšia prestávka o {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
|
@ -34,6 +35,11 @@
|
|||
"audible_alert": "Audible alert at the end of break",
|
||||
"language": "Jazyk",
|
||||
"enable": "Povoliť Safe Eyes",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"settings": "Nastavenia",
|
||||
"about": "Ohľadom",
|
||||
"quit": "Koniec",
|
||||
|
|
|
@ -20,12 +20,18 @@
|
|||
},
|
||||
"messages": {
|
||||
"ready_for_a_break": "{} விநாடிகளில் இடைவேளைக்கு தயாராகுங்கள்",
|
||||
"safe_eyes_is_disabled": "Safe Eyes நிறுத்தி வைக்கப்பட்டுள்ளது",
|
||||
"disabled_until_restart": "மறுதுவக்கம் வரை நிறுத்தி வைக்கப்பட்டுள்ளது",
|
||||
"disabled_until_x": "{} வரை நிறுத்தி வைக்கப்பட்டுள்ளது",
|
||||
"next_break_at": "அடுத்த இடைவேளை {}"
|
||||
},
|
||||
"ui_controls": {
|
||||
"cancel": "ரத்து",
|
||||
"enable": "Safe Eyes செயல்படுகிறது",
|
||||
"disable": "Disable Safe Eyes",
|
||||
"for_x_minutes": "For {} Minutes",
|
||||
"for_x_hour": "For {} Hour",
|
||||
"for_x_hours": "For {} Hours",
|
||||
"until_restart": "Until restart",
|
||||
"interval_between_two_breaks": "இரண்டு இடைவேளைகளுக்கிடையிலான இடைவெளி (விநாடிகளில்)",
|
||||
"long_break_duration": "நீண்ட கால இடைவேளை (விநாடிகளில்)",
|
||||
"idle_time": "இடைநிறுத்துவதற்கான குறைந்தபட்ச செயலற்ற நேரம் (நிமிடங்களில்)",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"meta": {
|
||||
"config_version": 2
|
||||
"config_version": 3
|
||||
},
|
||||
"break_interval": 15,
|
||||
"long_break_duration": 60,
|
||||
|
@ -10,5 +10,27 @@
|
|||
"idle_time": 5,
|
||||
"strict_break": false,
|
||||
"audible_alert": false,
|
||||
"language": "en"
|
||||
"language": "en",
|
||||
"disable_options": [
|
||||
{
|
||||
"label": "for_x_minutes",
|
||||
"time": 30,
|
||||
"unit": "minute"
|
||||
},
|
||||
{
|
||||
"label": "for_x_hour",
|
||||
"time": 1,
|
||||
"unit": "hour"
|
||||
},
|
||||
{
|
||||
"label": "for_x_hours",
|
||||
"time": 2,
|
||||
"unit": "hour"
|
||||
},
|
||||
{
|
||||
"label": "for_x_hours",
|
||||
"time": 3,
|
||||
"unit": "hour"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ system_style_sheet_path = os.path.join(bin_directory, "config/style/safeeyes_sty
|
|||
system_language_directory = os.path.join(bin_directory, "config/lang")
|
||||
|
||||
is_active = True
|
||||
CONFIGURATION_VERSION = 2
|
||||
CONFIGURATION_VERSION = 3
|
||||
SAFE_EYES_VERSION = "1.1.4"
|
||||
|
||||
"""
|
||||
|
@ -285,7 +285,7 @@ def main():
|
|||
with open(language_file_path) as language_file:
|
||||
language = json.load(language_file)
|
||||
|
||||
tray_icon = TrayIcon(language, show_settings, show_about, enable_safeeyes, disable_safeeyes, on_quit)
|
||||
tray_icon = TrayIcon(config, language, show_settings, show_about, enable_safeeyes, disable_safeeyes, on_quit)
|
||||
break_screen = BreakScreen(on_skipped, break_screen_glade, style_sheet_path)
|
||||
break_screen.initialize(config, language)
|
||||
core = SafeEyesCore(show_notification, show_alert, close_alert, on_countdown, tray_icon.next_break_time)
|
||||
|
|
Loading…
Reference in New Issue