diff --git a/server_addon/timers_manager/client/ayon_timers_manager/__init__.py b/server_addon/timers_manager/client/ayon_timers_manager/__init__.py deleted file mode 100644 index 1ec0d9b74b..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from .version import __version__ -from .timers_manager import ( - TimersManager -) - -__all__ = ( - "__version__", - - "TimersManager", -) diff --git a/server_addon/timers_manager/client/ayon_timers_manager/exceptions.py b/server_addon/timers_manager/client/ayon_timers_manager/exceptions.py deleted file mode 100644 index 5a9e00765d..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/exceptions.py +++ /dev/null @@ -1,3 +0,0 @@ -class InvalidContextError(ValueError): - """Context for which the timer should be started is invalid.""" - pass diff --git a/server_addon/timers_manager/client/ayon_timers_manager/idle_threads.py b/server_addon/timers_manager/client/ayon_timers_manager/idle_threads.py deleted file mode 100644 index d70f7790c4..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/idle_threads.py +++ /dev/null @@ -1,160 +0,0 @@ -import time -from qtpy import QtCore -from pynput import mouse, keyboard - -from ayon_core.lib import Logger - - -class IdleItem: - """Python object holds information if state of idle changed. - - This item is used to be independent from Qt objects. - """ - def __init__(self): - self.changed = False - - def reset(self): - self.changed = False - - def set_changed(self, changed=True): - self.changed = changed - - -class IdleManager(QtCore.QThread): - """ Measure user's idle time in seconds. - Idle time resets on keyboard/mouse input. - Is able to emit signals at specific time idle. - """ - time_signals = {} - idle_time = 0 - signal_reset_timer = QtCore.Signal() - - def __init__(self): - super(IdleManager, self).__init__() - self.log = Logger.get_logger(self.__class__.__name__) - self.signal_reset_timer.connect(self._reset_time) - - self.idle_item = IdleItem() - - self._is_running = False - self._mouse_thread = None - self._keyboard_thread = None - - def add_time_signal(self, emit_time, signal): - """ If any module want to use IdleManager, need to use add_time_signal - - Args: - emit_time(int): Time when signal will be emitted. - signal(QtCore.Signal): Signal that will be emitted - (without objects). - """ - if emit_time not in self.time_signals: - self.time_signals[emit_time] = [] - self.time_signals[emit_time].append(signal) - - @property - def is_running(self): - return self._is_running - - def _reset_time(self): - self.idle_time = 0 - - def stop(self): - self._is_running = False - - def _on_mouse_destroy(self): - self._mouse_thread = None - - def _on_keyboard_destroy(self): - self._keyboard_thread = None - - def run(self): - self.log.info('IdleManager has started') - self._is_running = True - - thread_mouse = MouseThread(self.idle_item) - thread_keyboard = KeyboardThread(self.idle_item) - - thread_mouse.destroyed.connect(self._on_mouse_destroy) - thread_keyboard.destroyed.connect(self._on_keyboard_destroy) - - self._mouse_thread = thread_mouse - self._keyboard_thread = thread_keyboard - - thread_mouse.start() - thread_keyboard.start() - - # Main loop here is each second checked if idle item changed state - while self._is_running: - if self.idle_item.changed: - self.idle_item.reset() - self.signal_reset_timer.emit() - else: - self.idle_time += 1 - - if self.idle_time in self.time_signals: - for signal in self.time_signals[self.idle_time]: - signal.emit() - time.sleep(1) - - self._post_run() - self.log.info('IdleManager has stopped') - - def _post_run(self): - # Stop threads if still exist - if self._mouse_thread is not None: - self._mouse_thread.signal_stop.emit() - self._mouse_thread.terminate() - self._mouse_thread.wait() - - if self._keyboard_thread is not None: - self._keyboard_thread.signal_stop.emit() - self._keyboard_thread.terminate() - self._keyboard_thread.wait() - - -class MouseThread(QtCore.QThread): - """Listens user's mouse movement.""" - signal_stop = QtCore.Signal() - - def __init__(self, idle_item): - super(MouseThread, self).__init__() - self.signal_stop.connect(self.stop) - self.m_listener = None - self.idle_item = idle_item - - def stop(self): - if self.m_listener is not None: - self.m_listener.stop() - - def on_move(self, *args, **kwargs): - self.idle_item.set_changed() - - def run(self): - self.m_listener = mouse.Listener(on_move=self.on_move) - self.m_listener.start() - - -class KeyboardThread(QtCore.QThread): - """Listens user's keyboard input - """ - signal_stop = QtCore.Signal() - - def __init__(self, idle_item): - super(KeyboardThread, self).__init__() - self.signal_stop.connect(self.stop) - self.k_listener = None - self.idle_item = idle_item - - def stop(self): - if self.k_listener is not None: - listener = self.k_listener - self.k_listener = None - listener.stop() - - def on_press(self, *args, **kwargs): - self.idle_item.set_changed() - - def run(self): - self.k_listener = keyboard.Listener(on_press=self.on_press) - self.k_listener.start() diff --git a/server_addon/timers_manager/client/ayon_timers_manager/launch_hooks/post_start_timer.py b/server_addon/timers_manager/client/ayon_timers_manager/launch_hooks/post_start_timer.py deleted file mode 100644 index b402d4034a..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/launch_hooks/post_start_timer.py +++ /dev/null @@ -1,44 +0,0 @@ -from ayon_applications import PostLaunchHook, LaunchTypes - - -class PostStartTimerHook(PostLaunchHook): - """Start timer with TimersManager module. - - This module requires enabled TimerManager module. - """ - order = None - launch_types = {LaunchTypes.local} - - def execute(self): - project_name = self.data.get("project_name") - folder_path = self.data.get("folder_path") - task_name = self.data.get("task_name") - - missing_context_keys = set() - if not project_name: - missing_context_keys.add("project_name") - if not folder_path: - missing_context_keys.add("folder_path") - if not task_name: - missing_context_keys.add("task_name") - - if missing_context_keys: - missing_keys_str = ", ".join([ - "\"{}\"".format(key) for key in missing_context_keys - ]) - self.log.debug("Hook {} skipped. Missing data keys: {}".format( - self.__class__.__name__, missing_keys_str - )) - return - - timers_manager = self.addons_manager.get("timers_manager") - if not timers_manager or not timers_manager.enabled: - self.log.info(( - "Skipping starting timer because" - " TimersManager is not available." - )) - return - - timers_manager.start_timer_with_webserver( - project_name, folder_path, task_name, logger=self.log - ) diff --git a/server_addon/timers_manager/client/ayon_timers_manager/plugins/publish/start_timer.py b/server_addon/timers_manager/client/ayon_timers_manager/plugins/publish/start_timer.py deleted file mode 100644 index 620cdb6e65..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/plugins/publish/start_timer.py +++ /dev/null @@ -1,37 +0,0 @@ -""" -Requires: - context -> project_settings - context -> ayonAddonsManager -""" - -import pyblish.api - - -class StartTimer(pyblish.api.ContextPlugin): - label = "Start Timer" - order = pyblish.api.IntegratorOrder + 1 - hosts = ["*"] - - def process(self, context): - timers_manager = context.data["ayonAddonsManager"]["timers_manager"] - if not timers_manager.enabled: - self.log.debug("TimersManager is disabled") - return - - project_settings = context.data["project_settings"] - if not project_settings["timers_manager"]["disregard_publishing"]: - self.log.debug("Publish is not affecting running timers.") - return - - project_name = context.data["projectName"] - folder_path = context.data.get("folderPath") - task_name = context.data.get("task") - if not project_name or not folder_path or not task_name: - self.log.info(( - "Current context does not contain all" - " required information to start a timer." - )) - return - timers_manager.start_timer_with_webserver( - project_name, folder_path, task_name, self.log - ) diff --git a/server_addon/timers_manager/client/ayon_timers_manager/plugins/publish/stop_timer.py b/server_addon/timers_manager/client/ayon_timers_manager/plugins/publish/stop_timer.py deleted file mode 100644 index eafd8cb450..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/plugins/publish/stop_timer.py +++ /dev/null @@ -1,27 +0,0 @@ -""" -Requires: - context -> project_settings - context -> ayonAddonsManager -""" - - -import pyblish.api - - -class StopTimer(pyblish.api.ContextPlugin): - label = "Stop Timer" - order = pyblish.api.ExtractorOrder - 0.49 - hosts = ["*"] - - def process(self, context): - timers_manager = context.data["ayonAddonsManager"]["timers_manager"] - if not timers_manager.enabled: - self.log.debug("TimersManager is disabled") - return - - project_settings = context.data["project_settings"] - if not project_settings["timers_manager"]["disregard_publishing"]: - self.log.debug("Publish is not affecting running timers.") - return - - timers_manager.stop_timer_with_webserver(self.log) diff --git a/server_addon/timers_manager/client/ayon_timers_manager/rest_api.py b/server_addon/timers_manager/client/ayon_timers_manager/rest_api.py deleted file mode 100644 index 88a6539510..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/rest_api.py +++ /dev/null @@ -1,85 +0,0 @@ -import json - -from aiohttp.web_response import Response -from ayon_core.lib import Logger - - -class TimersManagerModuleRestApi: - """ - REST API endpoint used for calling from hosts when context change - happens in Workfile app. - """ - def __init__(self, user_module, server_manager): - self._log = None - self.module = user_module - self.server_manager = server_manager - - self.prefix = "/timers_manager" - - self.register() - - @property - def log(self): - if self._log is None: - self._log = Logger.get_logger(self.__class__.__name__) - return self._log - - def register(self): - self.server_manager.add_route( - "POST", - self.prefix + "/start_timer", - self.start_timer - ) - self.server_manager.add_route( - "POST", - self.prefix + "/stop_timer", - self.stop_timer - ) - self.server_manager.add_route( - "GET", - self.prefix + "/get_task_time", - self.get_task_time - ) - - async def start_timer(self, request): - data = await request.json() - try: - project_name = data["project_name"] - folder_path = data["folder_path"] - task_name = data["task_name"] - except KeyError: - msg = ( - "Payload must contain fields 'project_name," - " 'folder_path' and 'task_name'" - ) - self.log.error(msg) - return Response(status=400, message=msg) - - self.module.stop_timers() - try: - self.module.start_timer(project_name, folder_path, task_name) - except Exception as exc: - return Response(status=404, message=str(exc)) - - return Response(status=200) - - async def stop_timer(self, request): - self.module.stop_timers() - return Response(status=200) - - async def get_task_time(self, request): - data = await request.json() - try: - project_name = data["project_name"] - folder_path = data["folder_path"] - task_name = data["task_name"] - except KeyError: - message = ( - "Payload must contain fields 'project_name, 'folder_path'," - " 'task_name'" - ) - self.log.warning(message) - return Response(text=message, status=404) - - time = self.module.get_task_time(project_name, folder_path, task_name) - return Response(text=json.dumps(time)) diff --git a/server_addon/timers_manager/client/ayon_timers_manager/timers_manager.py b/server_addon/timers_manager/client/ayon_timers_manager/timers_manager.py deleted file mode 100644 index 2aac7b2a49..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/timers_manager.py +++ /dev/null @@ -1,488 +0,0 @@ -import os -import platform - -import ayon_api - -from ayon_core.addon import ( - AYONAddon, - ITrayService, - IPluginPaths -) -from ayon_core.lib.events import register_event_callback - -from .version import __version__ -from .exceptions import InvalidContextError - -TIMER_MODULE_DIR = os.path.dirname(os.path.abspath(__file__)) - - -class ExampleTimersManagerConnector: - """Timers manager can handle timers of multiple modules/addons. - - Module must have object under `timers_manager_connector` attribute with - few methods. This is example class of the object that could be stored under - module. - - Required methods are 'stop_timer' and 'start_timer'. - - Example of `data` that are passed during changing timer: - ``` - data = { - "project_name": project_name, - "folder_id": folder_id, - "folder_path": folder_entity["path"], - "task_name": task_name, - "task_type": task_type, - # Deprecated - "asset_id": folder_id, - "asset_name": folder_entity["name"], - "hierarchy": hierarchy_items, - } - ``` - """ - - # Not needed at all - def __init__(self, module): - # Store timer manager module to be able call it's methods when needed - self._timers_manager_module = None - - # Store module which want to use timers manager to have access - self._module = module - - # Required - def stop_timer(self): - """Called by timers manager when module should stop timer.""" - self._module.stop_timer() - - # Required - def start_timer(self, data): - """Method called by timers manager when should start timer.""" - self._module.start_timer(data) - - # Optional - def register_timers_manager(self, timer_manager_module): - """Method called by timers manager where it's object is passed. - - This is moment when timers manager module can be store to be able - call it's callbacks (e.g. timer started). - """ - self._timers_manager_module = timer_manager_module - - # Custom implementation - def timer_started(self, data): - """This is example of possibility to trigger callbacks on manager.""" - if self._timers_manager_module is not None: - self._timers_manager_module.timer_started(self._module.id, data) - - # Custom implementation - def timer_stopped(self): - if self._timers_manager_module is not None: - self._timers_manager_module.timer_stopped(self._module.id) - - -class TimersManager( - AYONAddon, - ITrayService, - IPluginPaths -): - """ Handles about Timers. - - Should be able to start/stop all timers at once. - - To be able use this advantage module has to have attribute with name - `timers_manager_connector` which has two methods 'stop_timer' - and 'start_timer'. Optionally may have `register_timers_manager` where - object of TimersManager module is passed to be able call it's callbacks. - - See `ExampleTimersManagerConnector`. - """ - name = "timers_manager" - version = __version__ - label = "Timers Service" - - _required_methods = ( - "stop_timer", - "start_timer" - ) - - def initialize(self, studio_settings): - timers_settings = studio_settings.get(self.name) - enabled = timers_settings is not None - - auto_stop = False - full_time = 0 - message_time = 0 - if enabled: - # When timer will stop if idle manager is running (minutes) - full_time = int(timers_settings["full_time"] * 60) - # How many minutes before the timer is stopped will popup the message - message_time = int(timers_settings["message_time"] * 60) - - auto_stop = timers_settings["auto_stop"] - platform_name = platform.system().lower() - # Turn of auto stop on MacOs because pynput requires root permissions - # and on linux can cause thread locks on application close - if full_time <= 0 or platform_name in ("darwin", "linux"): - auto_stop = False - - self.enabled = enabled - self.auto_stop = auto_stop - self.time_show_message = full_time - message_time - self.time_stop_timer = full_time - - self.is_running = False - self.last_task = None - - # Tray attributes - self._signal_handler = None - self._widget_user_idle = None - self._idle_manager = None - - self._connectors_by_module_id = {} - self._modules_by_id = {} - - def tray_init(self): - if not self.auto_stop: - return - - from .idle_threads import IdleManager - from .widget_user_idle import WidgetUserIdle, SignalHandler - - signal_handler = SignalHandler(self) - idle_manager = IdleManager() - widget_user_idle = WidgetUserIdle(self) - widget_user_idle.set_countdown_start( - self.time_stop_timer - self.time_show_message - ) - - idle_manager.signal_reset_timer.connect( - widget_user_idle.reset_countdown - ) - idle_manager.add_time_signal( - self.time_show_message, signal_handler.signal_show_message - ) - idle_manager.add_time_signal( - self.time_stop_timer, signal_handler.signal_stop_timers - ) - - self._signal_handler = signal_handler - self._widget_user_idle = widget_user_idle - self._idle_manager = idle_manager - - def tray_start(self, *_a, **_kw): - if self._idle_manager: - self._idle_manager.start() - - def tray_exit(self): - if self._idle_manager: - self._idle_manager.stop() - self._idle_manager.wait() - - def get_timer_data_for_path(self, task_path): - """Convert string path to a timer data. - - It is expected that first item is project name, last item is task name - and folder path in the middle. - """ - path_items = task_path.split("/") - task_name = path_items.pop(-1) - project_name = path_items.pop(0) - folder_path = "/" + "/".join(path_items) - return self.get_timer_data_for_context( - project_name, folder_path, task_name, self.log - ) - - def get_launch_hook_paths(self): - """Implementation for applications launch hooks.""" - - return [ - os.path.join(TIMER_MODULE_DIR, "launch_hooks") - ] - - def get_plugin_paths(self): - """Implementation of `IPluginPaths`.""" - - return { - "publish": [os.path.join(TIMER_MODULE_DIR, "plugins", "publish")] - } - - @staticmethod - def get_timer_data_for_context( - project_name, folder_path, task_name, logger=None - ): - """Prepare data for timer related callbacks.""" - if not project_name or not folder_path or not task_name: - raise InvalidContextError(( - "Missing context information got" - " Project: \"{}\" Folder: \"{}\" Task: \"{}\"" - ).format(str(project_name), str(folder_path), str(task_name))) - - folder_entity = ayon_api.get_folder_by_path( - project_name, - folder_path, - fields={"id", "name", "path"} - ) - - if not folder_entity: - raise InvalidContextError(( - "Folder \"{}\" not found in project \"{}\"" - ).format(folder_path, project_name)) - - folder_id = folder_entity["id"] - task_entity = ayon_api.get_task_by_name( - project_name, folder_id, task_name - ) - if not task_entity: - raise InvalidContextError(( - "Task \"{}\" not found on folder \"{}\" in project \"{}\"" - ).format(task_name, folder_path, project_name)) - - task_type = "" - try: - task_type = task_entity["taskType"] - except KeyError: - msg = "Couldn't find task_type for {}".format(task_name) - if logger is not None: - logger.warning(msg) - else: - print(msg) - - hierarchy_items = folder_entity["path"].split("/") - hierarchy_items.pop(0) - - return { - "project_name": project_name, - "folder_id": folder_id, - "folder_path": folder_entity["path"], - "task_name": task_name, - "task_type": task_type, - "asset_id": folder_id, - "asset_name": folder_entity["name"], - "hierarchy": hierarchy_items, - } - - def start_timer(self, project_name, folder_path, task_name): - """Start timer for passed context. - - Args: - project_name (str): Project name. - folder_path (str): Folder path. - task_name (str): Task name. - """ - data = self.get_timer_data_for_context( - project_name, folder_path, task_name, self.log - ) - self.timer_started(None, data) - - def get_task_time(self, project_name, folder_path, task_name): - """Get total time for passed context. - - TODO: - - convert context to timer data - """ - times = {} - for module_id, connector in self._connectors_by_module_id.items(): - if hasattr(connector, "get_task_time"): - module = self._modules_by_id[module_id] - times[module.name] = connector.get_task_time( - project_name, folder_path, task_name - ) - return times - - def timer_started(self, source_id, data): - """Connector triggered that timer has started. - - New timer has started for context in data. - """ - for module_id, connector in self._connectors_by_module_id.items(): - if module_id == source_id: - continue - - try: - connector.start_timer(data) - except Exception: - self.log.info( - "Failed to start timer on connector {}".format( - str(connector) - ) - ) - - self.last_task = data - self.is_running = True - - def timer_stopped(self, source_id): - """Connector triggered that hist timer has stopped. - - Should stop all other timers. - - TODO: - - pass context for which timer has stopped to validate if timers are - same and valid - """ - for module_id, connector in self._connectors_by_module_id.items(): - if module_id == source_id: - continue - - try: - connector.stop_timer() - except Exception: - self.log.info( - "Failed to stop timer on connector {}".format( - str(connector) - ) - ) - - def restart_timers(self): - if self.last_task is not None: - self.timer_started(None, self.last_task) - - def stop_timers(self): - """Stop all timers.""" - if self.is_running is False: - return - - if self._widget_user_idle is not None: - self._widget_user_idle.set_timer_stopped() - self.is_running = False - - self.timer_stopped(None) - - def connect_with_addons(self, enabled_modules): - for module in enabled_modules: - connector = getattr(module, "timers_manager_connector", None) - if connector is None: - continue - - missing_methods = set() - for method_name in self._required_methods: - if not hasattr(connector, method_name): - missing_methods.add(method_name) - - if missing_methods: - joined = ", ".join( - ['"{}"'.format(name for name in missing_methods)] - ) - self.log.info(( - "Module \"{}\" has missing required methods {}." - ).format(module.name, joined)) - continue - - self._connectors_by_module_id[module.id] = connector - self._modules_by_id[module.id] = module - - # Optional method - if hasattr(connector, "register_timers_manager"): - try: - connector.register_timers_manager(self) - except Exception: - self.log.info(( - "Failed to register timers manager" - " for connector of module \"{}\"." - ).format(module.name)) - - def show_message(self): - if self.is_running is False: - return - if not self._widget_user_idle.is_showed(): - self._widget_user_idle.reset_countdown() - self._widget_user_idle.show() - - # Webserver module implementation - def webserver_initialization(self, server_manager): - """Add routes for timers to be able start/stop with rest api.""" - if self.tray_initialized: - from .rest_api import TimersManagerModuleRestApi - self.rest_api_obj = TimersManagerModuleRestApi( - self, server_manager - ) - - @staticmethod - def start_timer_with_webserver( - project_name, folder_path, task_name, logger=None - ): - """Prepared method for calling change timers on REST api. - - Webserver must be active. At the moment is Webserver running only when - OpenPype Tray is used. - - Args: - project_name (str): Project name. - folder_path (str): Folder path. - task_name (str): Task name. - logger (logging.Logger): Logger object. Using 'print' if not - passed. - """ - - webserver_url = os.environ.get("AYON_WEBSERVER_URL") - if not webserver_url: - msg = "Couldn't find webserver url" - if logger is not None: - logger.warning(msg) - else: - print(msg) - return - - rest_api_url = "{}/timers_manager/start_timer".format(webserver_url) - try: - import requests - except Exception: - msg = "Couldn't start timer ('requests' is not available)" - if logger is not None: - logger.warning(msg) - else: - print(msg) - return - data = { - "project_name": project_name, - "folder_path": folder_path, - "task_name": task_name - } - - return requests.post(rest_api_url, json=data) - - @staticmethod - def stop_timer_with_webserver(logger=None): - """Prepared method for calling stop timers on REST api. - - Args: - logger (logging.Logger): Logger used for logging messages. - """ - - webserver_url = os.environ.get("AYON_WEBSERVER_URL") - if not webserver_url: - msg = "Couldn't find webserver url" - if logger is not None: - logger.warning(msg) - else: - print(msg) - return - - rest_api_url = "{}/timers_manager/stop_timer".format(webserver_url) - try: - import requests - except Exception: - msg = "Couldn't start timer ('requests' is not available)" - if logger is not None: - logger.warning(msg) - else: - print(msg) - return - - return requests.post(rest_api_url) - - def on_host_install(self, host, host_name, project_name): - self.log.debug("Installing task changed callback") - register_event_callback("taskChanged", self._on_host_task_change) - - def _on_host_task_change(self, event): - project_name = event["project_name"] - folder_path = event["folder_path"] - task_name = event["task_name"] - self.log.debug(( - "Sending message that timer should change to" - " Project: {} Folder: {} Task: {}" - ).format(project_name, folder_path, task_name)) - - self.start_timer_with_webserver( - project_name, folder_path, task_name, self.log - ) diff --git a/server_addon/timers_manager/client/ayon_timers_manager/version.py b/server_addon/timers_manager/client/ayon_timers_manager/version.py deleted file mode 100644 index 95e413aaac..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/version.py +++ /dev/null @@ -1,3 +0,0 @@ -# -*- coding: utf-8 -*- -"""Package declaring AYON addon 'timers_manager' version.""" -__version__ = "0.2.0" diff --git a/server_addon/timers_manager/client/ayon_timers_manager/widget_user_idle.py b/server_addon/timers_manager/client/ayon_timers_manager/widget_user_idle.py deleted file mode 100644 index c59ab15b38..0000000000 --- a/server_addon/timers_manager/client/ayon_timers_manager/widget_user_idle.py +++ /dev/null @@ -1,196 +0,0 @@ -from qtpy import QtCore, QtGui, QtWidgets -from ayon_core import resources, style - - -class WidgetUserIdle(QtWidgets.QWidget): - SIZE_W = 300 - SIZE_H = 160 - - def __init__(self, module): - super(WidgetUserIdle, self).__init__() - - self.setWindowTitle("AYON - Stop timers") - - icon = QtGui.QIcon(resources.get_ayon_icon_filepath()) - self.setWindowIcon(icon) - - self.setWindowFlags( - QtCore.Qt.WindowCloseButtonHint - | QtCore.Qt.WindowMinimizeButtonHint - | QtCore.Qt.WindowStaysOnTopHint - ) - - self._is_showed = False - self._timer_stopped = False - self._countdown = 0 - self._countdown_start = 0 - - self.module = module - - msg_info = "You didn't work for a long time." - msg_question = "Would you like to stop Timers?" - msg_stopped = ( - "Your Timers were stopped. Do you want to start them again?" - ) - - lbl_info = QtWidgets.QLabel(msg_info, self) - lbl_info.setTextFormat(QtCore.Qt.RichText) - lbl_info.setWordWrap(True) - - lbl_question = QtWidgets.QLabel(msg_question, self) - lbl_question.setTextFormat(QtCore.Qt.RichText) - lbl_question.setWordWrap(True) - - lbl_stopped = QtWidgets.QLabel(msg_stopped, self) - lbl_stopped.setTextFormat(QtCore.Qt.RichText) - lbl_stopped.setWordWrap(True) - - lbl_rest_time = QtWidgets.QLabel(self) - lbl_rest_time.setTextFormat(QtCore.Qt.RichText) - lbl_rest_time.setWordWrap(True) - lbl_rest_time.setAlignment(QtCore.Qt.AlignCenter) - - form = QtWidgets.QFormLayout() - form.setContentsMargins(10, 15, 10, 5) - - form.addRow(lbl_info) - form.addRow(lbl_question) - form.addRow(lbl_stopped) - form.addRow(lbl_rest_time) - - btn_stop = QtWidgets.QPushButton("Stop timer", self) - btn_stop.setToolTip("Stop's All timers") - - btn_continue = QtWidgets.QPushButton("Continue", self) - btn_continue.setToolTip("Timer won't stop") - - btn_close = QtWidgets.QPushButton("Close", self) - btn_close.setToolTip("Close window") - - btn_restart = QtWidgets.QPushButton("Start timers", self) - btn_restart.setToolTip("Timer will be started again") - - group_layout = QtWidgets.QHBoxLayout() - group_layout.addStretch(1) - group_layout.addWidget(btn_continue) - group_layout.addWidget(btn_stop) - group_layout.addWidget(btn_restart) - group_layout.addWidget(btn_close) - - layout = QtWidgets.QVBoxLayout(self) - layout.addLayout(form) - layout.addLayout(group_layout) - - count_timer = QtCore.QTimer() - count_timer.setInterval(1000) - - btn_stop.clicked.connect(self._on_stop_clicked) - btn_continue.clicked.connect(self._on_continue_clicked) - btn_close.clicked.connect(self._close_widget) - btn_restart.clicked.connect(self._on_restart_clicked) - count_timer.timeout.connect(self._on_count_timeout) - - self.lbl_info = lbl_info - self.lbl_question = lbl_question - self.lbl_stopped = lbl_stopped - self.lbl_rest_time = lbl_rest_time - - self.btn_stop = btn_stop - self.btn_continue = btn_continue - self.btn_close = btn_close - self.btn_restart = btn_restart - - self._count_timer = count_timer - - self.resize(self.SIZE_W, self.SIZE_H) - self.setMinimumSize(QtCore.QSize(self.SIZE_W, self.SIZE_H)) - self.setMaximumSize(QtCore.QSize(self.SIZE_W+100, self.SIZE_H+100)) - self.setStyleSheet(style.load_stylesheet()) - - def set_countdown_start(self, countdown): - self._countdown_start = countdown - if not self.is_showed(): - self.reset_countdown() - - def reset_countdown(self): - self._countdown = self._countdown_start - self._update_countdown_label() - - def is_showed(self): - return self._is_showed - - def set_timer_stopped(self): - self._timer_stopped = True - self._refresh_context() - - def _update_countdown_label(self): - self.lbl_rest_time.setText(str(self._countdown)) - - def _on_count_timeout(self): - if self._timer_stopped or not self._is_showed: - self._count_timer.stop() - return - - if self._countdown <= 0: - self._stop_timers() - self.set_timer_stopped() - else: - self._countdown -= 1 - self._update_countdown_label() - - def _refresh_context(self): - self.lbl_question.setVisible(not self._timer_stopped) - self.lbl_rest_time.setVisible(not self._timer_stopped) - self.lbl_stopped.setVisible(self._timer_stopped) - - self.btn_continue.setVisible(not self._timer_stopped) - self.btn_stop.setVisible(not self._timer_stopped) - self.btn_restart.setVisible(self._timer_stopped) - self.btn_close.setVisible(self._timer_stopped) - - def _stop_timers(self): - self.module.stop_timers() - - def _on_stop_clicked(self): - self._stop_timers() - self._close_widget() - - def _on_restart_clicked(self): - self.module.restart_timers() - self._close_widget() - - def _on_continue_clicked(self): - self._close_widget() - - def _close_widget(self): - self._is_showed = False - self._timer_stopped = False - self._refresh_context() - self.hide() - - def showEvent(self, event): - if not self._is_showed: - self._is_showed = True - self._refresh_context() - - if not self._count_timer.isActive(): - self._count_timer.start() - super(WidgetUserIdle, self).showEvent(event) - - def closeEvent(self, event): - event.ignore() - if self._timer_stopped: - self._close_widget() - else: - self._on_continue_clicked() - - -class SignalHandler(QtCore.QObject): - signal_show_message = QtCore.Signal() - signal_stop_timers = QtCore.Signal() - - def __init__(self, module): - super(SignalHandler, self).__init__() - self.module = module - self.signal_show_message.connect(module.show_message) - self.signal_stop_timers.connect(module.stop_timers) diff --git a/server_addon/timers_manager/client/pyproject.toml b/server_addon/timers_manager/client/pyproject.toml deleted file mode 100644 index 364fb33712..0000000000 --- a/server_addon/timers_manager/client/pyproject.toml +++ /dev/null @@ -1,6 +0,0 @@ -[project] -name="timers_manager" -description="AYON TimersManager addon." - -[ayon.runtimeDependencies] -pynput = "^1.7.2" \ No newline at end of file diff --git a/server_addon/timers_manager/package.py b/server_addon/timers_manager/package.py deleted file mode 100644 index 32dc7cfbf4..0000000000 --- a/server_addon/timers_manager/package.py +++ /dev/null @@ -1,10 +0,0 @@ -name = "timers_manager" -title = "Timers Manager" -version = "0.2.0" - -client_dir = "ayon_timers_manager" - -ayon_required_addons = { - "core": ">0.3.2", -} -ayon_compatible_addons = {} diff --git a/server_addon/timers_manager/server/__init__.py b/server_addon/timers_manager/server/__init__.py deleted file mode 100644 index 32e83d295c..0000000000 --- a/server_addon/timers_manager/server/__init__.py +++ /dev/null @@ -1,9 +0,0 @@ -from typing import Type - -from ayon_server.addons import BaseServerAddon - -from .settings import TimersManagerSettings - - -class TimersManagerAddon(BaseServerAddon): - settings_model: Type[TimersManagerSettings] = TimersManagerSettings diff --git a/server_addon/timers_manager/server/settings.py b/server_addon/timers_manager/server/settings.py deleted file mode 100644 index 774940730c..0000000000 --- a/server_addon/timers_manager/server/settings.py +++ /dev/null @@ -1,24 +0,0 @@ -from ayon_server.settings import BaseSettingsModel, SettingsField - - -class TimersManagerSettings(BaseSettingsModel): - auto_stop: bool = SettingsField( - True, - title="Auto stop timer", - scope=["studio"], - ) - full_time: int = SettingsField( - 15, - title="Max idle time", - scope=["studio"], - ) - message_time: float = SettingsField( - 0.5, - title="When dialog will show", - scope=["studio"], - ) - disregard_publishing: bool = SettingsField( - False, - title="Disregard publishing", - scope=["studio"], - )