diff --git a/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po b/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po index 6224f76f..6c9011ce 100644 --- a/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po +++ b/safeeyes/config/locale/en_US/LC_MESSAGES/safeeyes.po @@ -512,3 +512,19 @@ msgstr "Pause media" # plugin/healthstats #~ msgid "Interval to reset statistics (in hours)" #~ msgstr "Interval to reset statistics (in hours)" + +# plugin/limitconsecutiveskipping +msgid "Limit Consecutive Skipping" +msgstr "Limit Consecutive Skipping" + +# plugin/limitconsecutiveskipping +msgid "How many skips or postpones are allowed in a row" +msgstr "How many skips or postpones are allowed in a row" + +# plugin/limitconsecutiveskipping +msgid "Limit how many breaks can be skipped or postponed in a row" +msgstr "Limit how many breaks can be skipped or postponed in a row" + +# plugin/limitconsecutiveskipping +msgid "Skipped or postponed %d/%d breaks in a row" +msgstr "Skipped or postponed %d/%d breaks in a row" \ No newline at end of file diff --git a/safeeyes/core.py b/safeeyes/core.py index 582277e6..e0fcbee5 100644 --- a/safeeyes/core.py +++ b/safeeyes/core.py @@ -67,6 +67,8 @@ def __init__(self, context): self.context = context self.context['skipped'] = False self.context['postponed'] = False + self.context['skip_button_disabled'] = False + self.context['postpone_button_disabled'] = False self.context['state'] = State.WAITING def initialize(self, config): @@ -299,6 +301,8 @@ def __fire_stop_break(self): # Reset the skipped flag self.context['skipped'] = False + self.context['skip_button_disabled'] = False + self.context['postpone_button_disabled'] = False self.__start_next_break() def __wait_for(self, duration): diff --git a/safeeyes/plugins/limitconsecutiveskipping/config.json b/safeeyes/plugins/limitconsecutiveskipping/config.json new file mode 100644 index 00000000..fc775b40 --- /dev/null +++ b/safeeyes/plugins/limitconsecutiveskipping/config.json @@ -0,0 +1,23 @@ +{ + "meta": { + "name": "Limit Consecutive Skipping", + "description": "Limit how many breaks can be skipped or postponed in a row", + "version": "0.0.1" + }, + "dependencies": { + "python_modules": [], + "shell_commands": [], + "operating_systems": [], + "desktop_environments": [], + "resources": [] + }, + "settings": [{ + "id": "number_of_allowed_skips_in_a_row", + "label": "How many skips or postpones are allowed in a row", + "type": "INT", + "default": 2, + "min": 1, + "max": 100 + }], + "break_override_allowed": true +} \ No newline at end of file diff --git a/safeeyes/plugins/limitconsecutiveskipping/icon.png b/safeeyes/plugins/limitconsecutiveskipping/icon.png new file mode 100644 index 00000000..c104d9d2 Binary files /dev/null and b/safeeyes/plugins/limitconsecutiveskipping/icon.png differ diff --git a/safeeyes/plugins/limitconsecutiveskipping/plugin.py b/safeeyes/plugins/limitconsecutiveskipping/plugin.py new file mode 100644 index 00000000..864333f3 --- /dev/null +++ b/safeeyes/plugins/limitconsecutiveskipping/plugin.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# Safe Eyes is a utility to remind you to take break frequently +# to protect your eyes from eye strain. + +# Copyright (C) 2024 Leo (@undefiened), based on the code written by Gobinath + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +""" +Limit how many breaks can be skipped or postponed in a row. +""" + +import logging + +context = None +no_of_skipped_breaks = 0 +session = None +enabled = True + +def init(ctx, safeeyes_config, plugin_config): + """ + Initialize the plugin. + """ + global enabled + global context + global session + global no_of_skipped_breaks + global no_allowed_skips + + logging.debug('Initialize Limit consecutive skipping plugin') + context = ctx + + no_allowed_skips = plugin_config.get('number_of_allowed_skips_in_a_row', 2) + + if session is None: + # Read the session + session = context['session']['plugin'].get('limitconsecutiveskipping', None) + if session is None: + session = {'no_of_skipped_breaks': 0} + context['session']['plugin']['limitconsecutiveskipping'] = session + no_of_skipped_breaks = session.get('no_of_skipped_breaks', 0) + + +def on_stop_break(): + """ + After the break, check if it is skipped. + """ + # Check if the plugin is enabled + if not enabled: + return + + global no_of_skipped_breaks + if context['skipped'] or context['postponed']: + no_of_skipped_breaks += 1 + session['no_of_skipped_breaks'] = no_of_skipped_breaks + else: + no_of_skipped_breaks = 0 + session['no_of_skipped_breaks'] = no_of_skipped_breaks + + +def on_start_break(break_obj): + logging.debug('Skipped / allowed = {} / {}'.format(no_of_skipped_breaks, no_allowed_skips)) + + if no_of_skipped_breaks >= no_allowed_skips: + context['postpone_button_disabled'] = True + context['skip_button_disabled'] = True + + +def get_widget_title(break_obj): + """ + Return the widget title. + """ + # Check if the plugin is enabled + if not enabled: + return "" + + return _('Limit Consecutive Skipping') + + +def get_widget_content(break_obj): + """ + Return the statistics. + """ + # Check if the plugin is enabled + if not enabled: + return "" + + return _('Skipped or postponed %d/%d breaks in a row') % (no_of_skipped_breaks, no_allowed_skips) + diff --git a/safeeyes/ui/break_screen.py b/safeeyes/ui/break_screen.py index cce06740..7546fd83 100644 --- a/safeeyes/ui/break_screen.py +++ b/safeeyes/ui/break_screen.py @@ -156,6 +156,9 @@ def __show_break_screen(self, message, image_path, widget, tray_actions): no_of_monitors = display.get_n_monitors() logging.info("Show break screens in %d display(s)", no_of_monitors) + skip_button_disabled = self.context.get('skip_button_disabled', False) + postpone_button_disabled = self.context.get('postpone_button_disabled', False) + for monitor_num in range(no_of_monitors): monitor = display.get_monitor(monitor_num) monitor_gemoetry = monitor.get_geometry() @@ -188,7 +191,7 @@ def __show_break_screen(self, message, image_path, widget, tray_actions): toolbar_button.show() # Add the buttons - if self.enable_postpone: + if self.enable_postpone and not postpone_button_disabled: # Add postpone button btn_postpone = Gtk.Button.new_with_label(_('Postpone')) btn_postpone.get_style_context().add_class('btn_postpone') @@ -196,7 +199,7 @@ def __show_break_screen(self, message, image_path, widget, tray_actions): btn_postpone.set_visible(True) box_buttons.pack_start(btn_postpone, True, True, 0) - if not self.strict_break: + if not self.strict_break and not skip_button_disabled: # Add the skip button btn_skip = Gtk.Button.new_with_label(_('Skip')) btn_skip.get_style_context().add_class('btn_skip')