Compare commits
23 Commits
46232c7a2f
...
3698176f00
Author | SHA1 | Date |
---|---|---|
deltragon | 3698176f00 | |
Hosted Weblate | 47be152397 | |
Andrés Martínez | 0fa7b35c26 | |
Archisman Panigrahi | 628abe298a | |
Archisman Panigrahi | 641eedafe7 | |
Archisman Panigrahi | 1a70cb6384 | |
Erik Michelson | 7986e09f05 | |
Danial Behzadi | 6186c4d4d4 | |
aceArt-GmbH | 033c56c837 | |
Barman Anonymous Please | 982c6c8181 | |
deltragon | f25f554585 | |
AircGroup | 0b80f503c9 | |
Hosted Weblate | e00fc973da | |
Oğuz Ersen | b45e59cada | |
gallegonovato | f39343790e | |
Archisman Panigrahi | 411c538506 | |
Archisman Panigrahi | d93aabf502 | |
vikdevelop | 24db938f11 | |
albanobattistella | c934d30d8f | |
Hosted Weblate | 959177e4de | |
AO Localisation Lab | d16147cd2e | |
deltragon | 6edb34344f | |
deltragon | f9dcb56677 |
|
@ -25,6 +25,8 @@ A clear and concise description of what you expected to happen.
|
|||
- Desktop Env [e.g. Gnome, KDE]
|
||||
- Version [e.g. 2.0.3]
|
||||
|
||||
**Flatpak issues**: If you experience any issue with flatpak, first please ensure that the bug is present in the [native package](https://github.com/slgobinath/SafeEyes?tab=readme-ov-file#installation-guide), and it is not a flatpak-only bug. Flatpak-only bugs should be reported at https://github.com/flathub/io.github.slgobinath.SafeEyes. (**Please erase this paragraph before creating the bug report**)
|
||||
|
||||
**Debug Log**
|
||||
Run the Safe Eyes using `safeeyes --debug` command attach the ~/safeeyes.log` file.
|
||||
|
||||
|
|
|
@ -102,7 +102,7 @@ sudo apk add safeeyes
|
|||
```
|
||||
|
||||
### Flatpak
|
||||
|
||||
**Warning**: Many plugins and features don't work well in the flatpak. We recommend that you use one of the native packages listed above. Flatpak-only bugs should be reported at https://github.com/flathub/io.github.slgobinath.SafeEyes.
|
||||
```bash
|
||||
flatpak install flathub io.github.slgobinath.SafeEyes
|
||||
```
|
||||
|
|
|
@ -6,8 +6,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2024-07-26 11:09+0000\n"
|
||||
"Last-Translator: RDWN IT <raraja701@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-09-17 01:09+0000\n"
|
||||
"Last-Translator: Barman Anonymous Please <barman-object-knee@duck.com>\n"
|
||||
"Language-Team: Arabic <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/ar/>\n"
|
||||
"Language: ar\n"
|
||||
|
@ -16,11 +16,11 @@ msgstr ""
|
|||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
|
||||
"&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
|
||||
"X-Generator: Weblate 5.7-dev\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "أغمض عينيك بلطف"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -40,7 +40,7 @@ msgstr "اغمز بعينيك"
|
|||
|
||||
# Short break
|
||||
msgid "Focus on a point in the far distance"
|
||||
msgstr "ركّز على نقطة في المدى البعيد"
|
||||
msgstr "ركّز على نقطة بعيدة"
|
||||
|
||||
# Short break
|
||||
msgid "Have some water"
|
||||
|
@ -76,7 +76,7 @@ msgstr "إظهار لوحة اﻹعدادات"
|
|||
|
||||
# Commandline arg description
|
||||
msgid "start safeeyes in debug mode"
|
||||
msgstr "ابدأ عيون سليمة في وضع التنقيح"
|
||||
msgstr "ابدأ safeeyes في وضع التنقيح (debug)"
|
||||
|
||||
# Commandline arg description
|
||||
msgid "print the status of running safeeyes instance and exit"
|
||||
|
@ -109,11 +109,11 @@ msgstr "الرخصة"
|
|||
|
||||
# About dialog
|
||||
msgid "List of Contributors"
|
||||
msgstr ""
|
||||
msgstr "قائمة المساهمين"
|
||||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "ساعدنا في ترجمة هذا التطبيق"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -539,36 +539,36 @@ msgstr "أوقِف الوسائط"
|
|||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit Consecutive Skipping"
|
||||
msgstr ""
|
||||
msgstr "تقييد التخطي المتتالي"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "How many skips or postpones are allowed in a row"
|
||||
msgstr ""
|
||||
msgstr "عدد مرات التخطي أو التأجيل المسموح بها على التوالي"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit how many breaks can be skipped or postponed in a row"
|
||||
msgstr ""
|
||||
msgstr "حدد عدد فترات الاستراحة التي يمكن تخطيها أو تأجيلها على التوالي"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
#, python-format
|
||||
msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row"
|
||||
msgstr ""
|
||||
msgstr "تم تخطي أو تأجيل %(num)d/%(allowed)d من فترات الاستراحة على التوالي"
|
||||
|
||||
# safeeyes/platform/io.github.slgobinath.SafeEyes.desktop
|
||||
msgid "RSI Prevention"
|
||||
msgstr ""
|
||||
msgstr "الوقاية من الإصابات الناتجة عن الإجهاد المتكرر للعينين"
|
||||
|
||||
msgid ""
|
||||
"Please install service providing tray icons for your desktop environment."
|
||||
msgstr ""
|
||||
msgstr "يرجى تثبيت خدمة توفر أيقونات في علبة النظام لبيئة سطح المكتب الخاصة بك."
|
||||
|
||||
#, python-format
|
||||
msgid "Next long break at %s"
|
||||
msgstr ""
|
||||
msgstr "الاستراحة الطويلة القادمة في %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Next breaks at %(short)s/%(long)s"
|
||||
msgstr ""
|
||||
msgstr "الاستراحة القادمة في %(short)s/%(long)s"
|
||||
|
||||
#, python-format
|
||||
msgid "The required plugin '%s' is missing dependencies!"
|
||||
|
|
|
@ -6,8 +6,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2022-08-08 21:25+0000\n"
|
||||
"Last-Translator: calbasi <joan@calbasi.net>\n"
|
||||
"PO-Revision-Date: 2024-09-27 12:16+0000\n"
|
||||
"Last-Translator: Andrés Martínez <sitoxplex@gmail.com>\n"
|
||||
"Language-Team: Catalan <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/ca/>\n"
|
||||
"Language: ca\n"
|
||||
|
@ -15,11 +15,11 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 4.14-dev\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "Tanqueu els ulls suaument"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -90,6 +90,8 @@ msgid ""
|
|||
"Safe Eyes is running without an RPC server. Turn it on to use command-line "
|
||||
"arguments."
|
||||
msgstr ""
|
||||
"Safe Eyes s'està executant sense un servidor RPC. Engegueu-lo per usar els "
|
||||
"arguments de la línia de comandaments."
|
||||
|
||||
# About dialog
|
||||
msgid "Close"
|
||||
|
@ -111,11 +113,11 @@ msgstr "Llicència"
|
|||
|
||||
# About dialog
|
||||
msgid "List of Contributors"
|
||||
msgstr ""
|
||||
msgstr "Llista de col·laboradors"
|
||||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Ajuda'ns a traduir aquesta aplicació"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -139,7 +141,7 @@ msgstr "Temps per preparar-se per a una pausa (en segons)"
|
|||
|
||||
# Settings dialog
|
||||
msgid "Keyboard shortcuts disabled period (in seconds)"
|
||||
msgstr ""
|
||||
msgstr "Període d'inhabilitació de les dreceres de teclat (en segons)"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Postponement duration (in minutes)"
|
||||
|
@ -159,19 +161,21 @@ msgstr "Permet posposar les pauses"
|
|||
|
||||
# Settings dialog
|
||||
msgid "Persist the internal state"
|
||||
msgstr ""
|
||||
msgstr "Persisteix l'estat intern"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Use RPC server to receive runtime commands"
|
||||
msgstr ""
|
||||
msgstr "Empra el servidor RPC per a rebre els comandaments del temps d'execució"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Without the RPC server, command-line commands may not work"
|
||||
msgstr ""
|
||||
msgstr "Sense el servidor RPC, és possible que els comandaments no funcionen"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Long break interval must be a multiple of short break interval"
|
||||
msgstr ""
|
||||
"Cal que l'interval de pauses llargues siga múltiple de l'interval de pauses "
|
||||
"curtes"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Reset"
|
||||
|
@ -196,7 +200,7 @@ msgstr "Pauses llargues"
|
|||
|
||||
# Settings dialog
|
||||
msgid "Delete"
|
||||
msgstr "Suprimeix"
|
||||
msgstr "Esborra"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Are you sure you want to delete this break?"
|
||||
|
@ -240,7 +244,7 @@ msgstr "Trieu"
|
|||
|
||||
# Settings dialog
|
||||
msgid "Please select an image"
|
||||
msgstr "Si us plau, trieu una imatge"
|
||||
msgstr "Trieu una imatge"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Duration"
|
||||
|
@ -273,26 +277,26 @@ msgstr "Preferències del complement"
|
|||
# Settings dialog
|
||||
#, python-format
|
||||
msgid "Plugin does not support %s desktop environment"
|
||||
msgstr ""
|
||||
msgstr "El complement no admet l'entorn d'escriptori %s"
|
||||
|
||||
# Settings dialog
|
||||
#, python-format
|
||||
msgid "Please install the Python module '%s'"
|
||||
msgstr ""
|
||||
msgstr "Instal·leu el mòdul de Python '%s'"
|
||||
|
||||
# Settings dialog
|
||||
#, python-format
|
||||
msgid "Please install the command-line tool '%s'"
|
||||
msgstr ""
|
||||
msgstr "Instal·leu la ferramenta de la línia de comandament '%s'"
|
||||
|
||||
# Settings dialog
|
||||
msgid "Invalid cron expression '%s'"
|
||||
msgstr ""
|
||||
msgstr "Expressió cron no vàlida '%s'"
|
||||
|
||||
# Settings dialog
|
||||
#, python-format
|
||||
msgid "Please add the resource %(resource)s to %(config_resource)s directory"
|
||||
msgstr ""
|
||||
msgstr "Afegiu el recurs %(resource)s al directori %(config_resource)s"
|
||||
|
||||
# Settings dialog
|
||||
msgid "New Break"
|
||||
|
@ -316,15 +320,15 @@ msgstr "Alerta audible"
|
|||
|
||||
# plugin/audiblealert
|
||||
msgid "Play audible alert before and after breaks"
|
||||
msgstr ""
|
||||
msgstr "Reprodueix una alerta audible abans i després de les pauses"
|
||||
|
||||
# plugin/audiblealert
|
||||
msgid "Play audible alert before breaks"
|
||||
msgstr ""
|
||||
msgstr "Reprodueix una alerta audible abans de les pauses"
|
||||
|
||||
# plugin/audiblealert
|
||||
msgid "Play audible alert after breaks"
|
||||
msgstr ""
|
||||
msgstr "Reprodueix una alerta audible després de les pauses"
|
||||
|
||||
# plugin/donotdisturb
|
||||
msgid "Do Not Disturb"
|
||||
|
@ -332,23 +336,23 @@ msgstr "No molesteu"
|
|||
|
||||
# plugin/donotdisturb
|
||||
msgid "Skip break if the active window is in fullscreen mode"
|
||||
msgstr ""
|
||||
msgstr "Omet la pausa si la finestra activa està en mode pantalla completa"
|
||||
|
||||
# plugin/donotdisturb
|
||||
msgid "Do not interrupt these windows anytime"
|
||||
msgstr ""
|
||||
msgstr "No interrompis aquestes finestres mai"
|
||||
|
||||
# plugin/donotdisturb
|
||||
msgid "Interrupt these windows regardless of their state"
|
||||
msgstr ""
|
||||
msgstr "Interromp aquestes finestres independentment del seu estat"
|
||||
|
||||
# plugin/donotdisturb
|
||||
msgid "Switch the interruptible windows to normal mode"
|
||||
msgstr ""
|
||||
msgstr "Canviar les finestres interruptibles al mode normal"
|
||||
|
||||
# plugin/donotdisturb
|
||||
msgid "Do not disturb while on battery"
|
||||
msgstr ""
|
||||
msgstr "No molestar quan s'utilitza la bateria"
|
||||
|
||||
# plugin/healthstats
|
||||
msgid "Health Statistics"
|
||||
|
@ -356,24 +360,24 @@ msgstr "Estadístiques de salut"
|
|||
|
||||
# plugin/healthstats
|
||||
msgid "Show statistics based on how you use Safe Eyes"
|
||||
msgstr ""
|
||||
msgstr "Mostra estadístiques de com useu Safe Eyes"
|
||||
|
||||
# plugin/healthstats
|
||||
msgid "Statistics reset interval (cron expression)"
|
||||
msgstr ""
|
||||
msgstr "Interval de reinici de les estadístiques (expressió cron)"
|
||||
|
||||
# plugin/notification
|
||||
msgid "Notification"
|
||||
msgstr ""
|
||||
msgstr "Notificació"
|
||||
|
||||
# plugin/notification
|
||||
msgid "Show a system notification before breaks"
|
||||
msgstr ""
|
||||
msgstr "Mostra una notificació del sistema abans de les pauses"
|
||||
|
||||
# plugin/notification
|
||||
#, python-format
|
||||
msgid "Ready for a short break in %s seconds"
|
||||
msgstr ""
|
||||
msgstr "Preparat per a una pausa breu en %s segons"
|
||||
|
||||
# plugin/notification
|
||||
#, python-format
|
||||
|
|
|
@ -6,20 +6,20 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2023-10-31 16:04+0000\n"
|
||||
"Last-Translator: Kryštof Jelínek <krystof186@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-08-27 19:09+0000\n"
|
||||
"Last-Translator: vikdevelop <super-vik1@protonmail.com>\n"
|
||||
"Language-Team: Czech <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/cs/>\n"
|
||||
"Language: cs\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.2-dev\n"
|
||||
"Plural-Forms: nplurals=3; plural=((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 5.7.1-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "Jemně zavřete své oči"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -112,11 +112,11 @@ msgstr "Licence"
|
|||
|
||||
# About dialog
|
||||
msgid "List of Contributors"
|
||||
msgstr ""
|
||||
msgstr "Seznam přispěvatelů"
|
||||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Pomozte nám přeložit tuto aplikaci"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -503,15 +503,15 @@ msgstr "Udělat si přestávku"
|
|||
|
||||
#: plugins/trayicon
|
||||
msgid "Any break"
|
||||
msgstr ""
|
||||
msgstr "Jakákoliv přestávka"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Short break"
|
||||
msgstr ""
|
||||
msgstr "Krátká přestávka"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Long break"
|
||||
msgstr ""
|
||||
msgstr "Dlouhá přestávka"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Until restart"
|
||||
|
@ -535,57 +535,61 @@ msgstr "Pozastavit média"
|
|||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit Consecutive Skipping"
|
||||
msgstr ""
|
||||
msgstr "Omezení po sobě jdoucích přeskočení"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "How many skips or postpones are allowed in a row"
|
||||
msgstr ""
|
||||
msgstr "Kolik přeskočení nebo odložení je povoleno v řadě za sebou"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit how many breaks can be skipped or postponed in a row"
|
||||
msgstr ""
|
||||
msgstr "Omezit počet přestávek, které lze vynechat nebo odložit za sebou"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
#, python-format
|
||||
msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row"
|
||||
msgstr ""
|
||||
msgstr "Vynechané nebo odložené %(num)d/%(allowed)d přestávky za sebou"
|
||||
|
||||
# safeeyes/platform/io.github.slgobinath.SafeEyes.desktop
|
||||
msgid "RSI Prevention"
|
||||
msgstr ""
|
||||
msgstr "Prevence poranění z opakovaného namáhání (RSI)"
|
||||
|
||||
msgid ""
|
||||
"Please install service providing tray icons for your desktop environment."
|
||||
msgstr ""
|
||||
"Nainstalujte prosím službu poskytující ikony na panelu pro vaše desktopové "
|
||||
"prostředí."
|
||||
|
||||
#, python-format
|
||||
msgid "Next long break at %s"
|
||||
msgstr ""
|
||||
msgstr "Další dlouhá přestávka za %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Next breaks at %(short)s/%(long)s"
|
||||
msgstr ""
|
||||
msgstr "Další přestávky za %(short)s/%(long)s"
|
||||
|
||||
#, python-format
|
||||
msgid "The required plugin '%s' is missing dependencies!"
|
||||
msgstr ""
|
||||
msgstr "Požadovanému zásuvnému modulu '%s' chybí závislosti!"
|
||||
|
||||
msgid ""
|
||||
"Please install the dependencies or disable the plugin. To hide this message, "
|
||||
"you can also deactivate the plugin in the settings."
|
||||
msgstr ""
|
||||
"Nainstalujte prosím požadované závislosti nebo zakažte tento zásuvný modul. "
|
||||
"Pro skrytí této zprávy, můžete také deaktivovat zásuvný modul v nastavení."
|
||||
|
||||
msgid "Click here for more information"
|
||||
msgstr ""
|
||||
msgstr "Klikněte zde pro více informací"
|
||||
|
||||
msgid "Disable plugin temporarily"
|
||||
msgstr ""
|
||||
msgstr "Zakázat zásuvný modul dočasně"
|
||||
|
||||
msgid "Disable permanently"
|
||||
msgstr ""
|
||||
msgstr "Zakázat permanentně"
|
||||
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
msgstr "Licence:"
|
||||
|
||||
# Short break
|
||||
#~ msgid "Tightly close your eyes"
|
||||
|
|
|
@ -6,8 +6,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2024-08-10 19:39+0000\n"
|
||||
"Last-Translator: Archisman Panigrahi <apandada1@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-09-21 15:40+0000\n"
|
||||
"Last-Translator: Erik Michelson <opensource@erik.michelson.eu>\n"
|
||||
"Language-Team: German <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/de/>\n"
|
||||
"Language: de\n"
|
||||
|
@ -15,7 +15,7 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.7-dev\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
|
@ -117,7 +117,7 @@ msgstr "Liste der Mitwirkenden"
|
|||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Hilf mit die Anwendung zu übersetzen"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2024-08-16 15:09+0000\n"
|
||||
"PO-Revision-Date: 2024-09-02 07:09+0000\n"
|
||||
"Last-Translator: gallegonovato <fran-carro@hotmail.es>\n"
|
||||
"Language-Team: Spanish <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/es/>\n"
|
||||
|
@ -15,7 +15,7 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.7\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
|
@ -116,7 +116,7 @@ msgstr "Colaboradores"
|
|||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Ayúdanos a traducir esta aplicación"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
|
|
@ -6,8 +6,8 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2024-07-28 15:09+0000\n"
|
||||
"Last-Translator: Parsa Nobahari <parsa.nobahari@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-09-20 00:40+0000\n"
|
||||
"Last-Translator: Danial Behzadi <dani.behzi@ubuntu.com>\n"
|
||||
"Language-Team: Persian <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/fa/>\n"
|
||||
"Language: fa\n"
|
||||
|
@ -15,11 +15,11 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 5.7-dev\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "چشمانتان را آرام ببندید"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -116,7 +116,7 @@ msgstr "لیست مشارکتکنندگان"
|
|||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "کمک به ترجمهٔ این کاره"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -581,7 +581,7 @@ msgid "Disable permanently"
|
|||
msgstr "غیرفعال کردن دائمی"
|
||||
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
msgstr "پروانه:"
|
||||
|
||||
# Short break
|
||||
#~ msgid "Tightly close your eyes"
|
||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2022-01-11 15:55+0000\n"
|
||||
"PO-Revision-Date: 2024-08-24 17:09+0000\n"
|
||||
"Last-Translator: AO Localisation Lab <ao@localizationlab.org>\n"
|
||||
"Language-Team: French <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/fr/>\n"
|
||||
|
@ -15,11 +15,11 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n > 1;\n"
|
||||
"X-Generator: Weblate 4.10.1\n"
|
||||
"X-Generator: Weblate 5.7.1-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "Fermez doucement les yeux"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -113,7 +113,7 @@ msgstr "Licence"
|
|||
|
||||
# About dialog
|
||||
msgid "List of Contributors"
|
||||
msgstr ""
|
||||
msgstr "Liste des contributeurs"
|
||||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
|
@ -510,15 +510,15 @@ msgstr "Prendre une pause maintenant"
|
|||
|
||||
#: plugins/trayicon
|
||||
msgid "Any break"
|
||||
msgstr ""
|
||||
msgstr "N’importe quelle pause"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Short break"
|
||||
msgstr ""
|
||||
msgstr "Pause courte"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Long break"
|
||||
msgstr ""
|
||||
msgstr "Pause longue"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Until restart"
|
||||
|
@ -542,57 +542,61 @@ msgstr "Mettre le contenu multimédia en pause"
|
|||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit Consecutive Skipping"
|
||||
msgstr ""
|
||||
msgstr "Limiter les sauts de pause consécutifs"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "How many skips or postpones are allowed in a row"
|
||||
msgstr ""
|
||||
msgstr "Nombre de sauts ou de reports autorisés d’affilée"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit how many breaks can be skipped or postponed in a row"
|
||||
msgstr ""
|
||||
msgstr "Limiter le nombre de pauses sautées ou reportées d’affilée"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
#, python-format
|
||||
msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row"
|
||||
msgstr ""
|
||||
msgstr "%(num)d/%(allowed)d pauses sautées ou reportées d’affilée"
|
||||
|
||||
# safeeyes/platform/io.github.slgobinath.SafeEyes.desktop
|
||||
msgid "RSI Prevention"
|
||||
msgstr ""
|
||||
msgstr "Prévention des lésions attribuables au travail répétitif"
|
||||
|
||||
msgid ""
|
||||
"Please install service providing tray icons for your desktop environment."
|
||||
msgstr ""
|
||||
"Installez le service qui fournit les icônes de la barre d’état pour votre "
|
||||
"environnement de bureau."
|
||||
|
||||
#, python-format
|
||||
msgid "Next long break at %s"
|
||||
msgstr ""
|
||||
msgstr "Prochaine pause longue à %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Next breaks at %(short)s/%(long)s"
|
||||
msgstr ""
|
||||
msgstr "Prochaines pauses à %(short)s/%(long)s"
|
||||
|
||||
#, python-format
|
||||
msgid "The required plugin '%s' is missing dependencies!"
|
||||
msgstr ""
|
||||
msgstr "Il manque des dépendances pour le greffon « %s » nécessaire"
|
||||
|
||||
msgid ""
|
||||
"Please install the dependencies or disable the plugin. To hide this message, "
|
||||
"you can also deactivate the plugin in the settings."
|
||||
msgstr ""
|
||||
"Installez les dépendances ou désactivez le greffon. Pour ne plus afficher ce "
|
||||
"message, vous pouvez aussi désactiver le greffon dans les paramètres."
|
||||
|
||||
msgid "Click here for more information"
|
||||
msgstr ""
|
||||
msgstr "Cliquer ici pour plus de précisions"
|
||||
|
||||
msgid "Disable plugin temporarily"
|
||||
msgstr ""
|
||||
msgstr "Désactivation temporaire du greffon"
|
||||
|
||||
msgid "Disable permanently"
|
||||
msgstr ""
|
||||
msgstr "Désactivation permanente"
|
||||
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
msgstr "Licence :"
|
||||
|
||||
# Short break
|
||||
#~ msgid "Tightly close your eyes"
|
||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2024-07-02 12:09+0000\n"
|
||||
"PO-Revision-Date: 2024-08-27 19:09+0000\n"
|
||||
"Last-Translator: albanobattistella <albano_battistella@hotmail.com>\n"
|
||||
"Language-Team: Italian <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/it/>\n"
|
||||
|
@ -15,11 +15,11 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.7-dev\n"
|
||||
"X-Generator: Weblate 5.7.1-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "Chiudi dolcemente gli occhi"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -116,7 +116,7 @@ msgstr "Elenco dei contributori"
|
|||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Aiutaci a tradurre questa app"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -591,7 +591,7 @@ msgid "Disable permanently"
|
|||
msgstr "Disattivare in modo permanente"
|
||||
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
msgstr "Licenza:"
|
||||
|
||||
# Short break
|
||||
#~ msgid "Tightly close your eyes"
|
||||
|
|
|
@ -6,21 +6,21 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2023-11-26 00:02+0000\n"
|
||||
"Last-Translator: Almaz Mannanov <AlmazWorks@gmail.com>\n"
|
||||
"PO-Revision-Date: 2024-09-06 22:09+0000\n"
|
||||
"Last-Translator: AircGroup <imartime@yandex.ru>\n"
|
||||
"Language-Team: Russian <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/ru/>\n"
|
||||
"Language: ru\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
|
||||
"X-Generator: Weblate 5.2.1-rc\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "Аккуратно закройте глаза"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -113,11 +113,11 @@ msgstr "Лицензия"
|
|||
|
||||
# About dialog
|
||||
msgid "List of Contributors"
|
||||
msgstr ""
|
||||
msgstr "Список участников проекта"
|
||||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Помоги нам перевести приложение"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -504,15 +504,15 @@ msgstr "Отдохнуть сейчас"
|
|||
|
||||
#: plugins/trayicon
|
||||
msgid "Any break"
|
||||
msgstr ""
|
||||
msgstr "Сделайте перерыв на что угодно"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Short break"
|
||||
msgstr ""
|
||||
msgstr "Небольшой перерыв"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Long break"
|
||||
msgstr ""
|
||||
msgstr "Долгий перерыв"
|
||||
|
||||
#: plugins/trayicon
|
||||
msgid "Until restart"
|
||||
|
@ -536,57 +536,61 @@ msgstr "Приостановить воспроизведение"
|
|||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit Consecutive Skipping"
|
||||
msgstr ""
|
||||
msgstr "Ограничение пропусков подряд"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "How many skips or postpones are allowed in a row"
|
||||
msgstr ""
|
||||
msgstr "Сколько пропусков или переносов разрешено подряд"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit how many breaks can be skipped or postponed in a row"
|
||||
msgstr ""
|
||||
msgstr "Какое количество перерывов можно пропустить или отложить подряд"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
#, python-format
|
||||
msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row"
|
||||
msgstr ""
|
||||
msgstr "Пропущенные или отложенные %(num)d/%(allowed)d перерывы подряд"
|
||||
|
||||
# safeeyes/platform/io.github.slgobinath.SafeEyes.desktop
|
||||
msgid "RSI Prevention"
|
||||
msgstr ""
|
||||
msgstr "Профилактика RSI"
|
||||
|
||||
msgid ""
|
||||
"Please install service providing tray icons for your desktop environment."
|
||||
msgstr ""
|
||||
"Пожалуйста, установите ПО предоставляющий иконки в трее для вашего рабочего "
|
||||
"стола."
|
||||
|
||||
#, python-format
|
||||
msgid "Next long break at %s"
|
||||
msgstr ""
|
||||
msgstr "Следующий длительный перерыв в %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Next breaks at %(short)s/%(long)s"
|
||||
msgstr ""
|
||||
msgstr "Следующие перерывы %(short)s/%(long)s"
|
||||
|
||||
#, python-format
|
||||
msgid "The required plugin '%s' is missing dependencies!"
|
||||
msgstr ""
|
||||
msgstr "В требуемом плагине '%s' отсутствуют зависимости!"
|
||||
|
||||
msgid ""
|
||||
"Please install the dependencies or disable the plugin. To hide this message, "
|
||||
"you can also deactivate the plugin in the settings."
|
||||
msgstr ""
|
||||
"Пожалуйста, установите зависимости или отключите плагин. Чтобы скрыть это "
|
||||
"сообщение, вы также можете отключить плагин в настройках."
|
||||
|
||||
msgid "Click here for more information"
|
||||
msgstr ""
|
||||
msgstr "Нажмите здесь для получения дополнительной информации"
|
||||
|
||||
msgid "Disable plugin temporarily"
|
||||
msgstr ""
|
||||
msgstr "Временно отключите плагин"
|
||||
|
||||
msgid "Disable permanently"
|
||||
msgstr ""
|
||||
msgstr "Отключить навсегда"
|
||||
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
msgstr "Лицензия:"
|
||||
|
||||
# Short break
|
||||
#~ msgid "Tightly close your eyes"
|
||||
|
|
|
@ -6,7 +6,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"POT-Creation-Date: \n"
|
||||
"PO-Revision-Date: 2024-06-28 17:09+0000\n"
|
||||
"PO-Revision-Date: 2024-09-02 07:09+0000\n"
|
||||
"Last-Translator: Oğuz Ersen <oguz@ersen.moe>\n"
|
||||
"Language-Team: Turkish <https://hosted.weblate.org/projects/safe-eyes/"
|
||||
"translations/tr/>\n"
|
||||
|
@ -15,11 +15,11 @@ msgstr ""
|
|||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=n != 1;\n"
|
||||
"X-Generator: Weblate 5.7-dev\n"
|
||||
"X-Generator: Weblate 5.8-dev\n"
|
||||
|
||||
# Short break
|
||||
msgid "Gently close your eyes"
|
||||
msgstr ""
|
||||
msgstr "Yavaşça gözlerinizi kapatın"
|
||||
|
||||
# Short break
|
||||
msgid "Roll your eyes a few times to each side"
|
||||
|
@ -113,11 +113,11 @@ msgstr "Lisans"
|
|||
|
||||
# About dialog
|
||||
msgid "List of Contributors"
|
||||
msgstr ""
|
||||
msgstr "Katkıda Bulunanların Listesi"
|
||||
|
||||
# About dialog
|
||||
msgid "Help us translate this app"
|
||||
msgstr ""
|
||||
msgstr "Bu uygulamayı çevirmemize yardım edin"
|
||||
|
||||
# Break screen
|
||||
msgid "Skip"
|
||||
|
@ -533,57 +533,60 @@ msgstr "Ortamı duraklat"
|
|||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit Consecutive Skipping"
|
||||
msgstr ""
|
||||
msgstr "Ardışık Geçmeyi Sınırla"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "How many skips or postpones are allowed in a row"
|
||||
msgstr ""
|
||||
msgstr "Arka arkaya kaç geçmeye veya ertelemeye izin verilir"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
msgid "Limit how many breaks can be skipped or postponed in a row"
|
||||
msgstr ""
|
||||
"Arka arkaya kaç molanın geçilebileceğini veya ertelenebileceğini sınırlayın"
|
||||
|
||||
# plugin/limitconsecutiveskipping
|
||||
#, python-format
|
||||
msgid "Skipped or postponed %(num)d/%(allowed)d breaks in a row"
|
||||
msgstr ""
|
||||
msgstr "Arka arkaya %(num)d/%(allowed)d mola geçildi veya ertelendi"
|
||||
|
||||
# safeeyes/platform/io.github.slgobinath.SafeEyes.desktop
|
||||
msgid "RSI Prevention"
|
||||
msgstr ""
|
||||
msgstr "Tekrarlayan zorlanma yaralanmalarının önlenmesi"
|
||||
|
||||
msgid ""
|
||||
"Please install service providing tray icons for your desktop environment."
|
||||
msgstr ""
|
||||
msgstr "Lütfen masaüstü ortamınız için tepsi simgeleri sağlayan hizmeti kurun."
|
||||
|
||||
#, python-format
|
||||
msgid "Next long break at %s"
|
||||
msgstr ""
|
||||
msgstr "Sonraki uzun mola: %s"
|
||||
|
||||
#, python-format
|
||||
msgid "Next breaks at %(short)s/%(long)s"
|
||||
msgstr ""
|
||||
msgstr "Sonraki mola: %(short)s/%(long)s"
|
||||
|
||||
#, python-format
|
||||
msgid "The required plugin '%s' is missing dependencies!"
|
||||
msgstr ""
|
||||
msgstr "Gerekli '%s' eklentisinin bağımlılıkları eksik!"
|
||||
|
||||
msgid ""
|
||||
"Please install the dependencies or disable the plugin. To hide this message, "
|
||||
"you can also deactivate the plugin in the settings."
|
||||
msgstr ""
|
||||
"Lütfen bağımlılıkları kurun veya eklentiyi devre dışı bırakın. Bu mesajı "
|
||||
"gizlemek için eklentiyi ayarlardan da devre dışı bırakabilirsiniz."
|
||||
|
||||
msgid "Click here for more information"
|
||||
msgstr ""
|
||||
msgstr "Daha fazla bilgi için buraya tıklayın"
|
||||
|
||||
msgid "Disable plugin temporarily"
|
||||
msgstr ""
|
||||
msgstr "Eklentiyi geçici olarak devre dışı bırak"
|
||||
|
||||
msgid "Disable permanently"
|
||||
msgstr ""
|
||||
msgstr "Kalıcı olarak devre dışı bırak"
|
||||
|
||||
msgid "License:"
|
||||
msgstr ""
|
||||
msgstr "Lisans:"
|
||||
|
||||
# Short break
|
||||
#~ msgid "Tightly close your eyes"
|
||||
|
|
|
@ -407,6 +407,7 @@ class TrayAction:
|
|||
class PluginDependency:
|
||||
message: str
|
||||
link: str | None = None
|
||||
retryable: bool = False
|
||||
|
||||
|
||||
class RequiredPluginException(Exception):
|
||||
|
|
|
@ -58,7 +58,7 @@ import os
|
|||
import sys
|
||||
|
||||
from safeeyes import utility
|
||||
from safeeyes.model import RequiredPluginException
|
||||
from safeeyes.model import PluginDependency, RequiredPluginException
|
||||
|
||||
sys.path.append(os.path.abspath(utility.SYSTEM_PLUGINS_DIR))
|
||||
sys.path.append(os.path.abspath(utility.USER_PLUGINS_DIR))
|
||||
|
@ -67,24 +67,11 @@ HORIZONTAL_LINE_LENGTH = 64
|
|||
|
||||
|
||||
class PluginManager:
|
||||
"""Imports the Safe Eyes plugins and calls the methods defined in those
|
||||
plugins.
|
||||
"""
|
||||
"""Imports the Safe Eyes plugins and calls the methods defined in those plugins."""
|
||||
|
||||
def __init__(self):
|
||||
logging.info("Load all the plugins")
|
||||
self.__plugins = {}
|
||||
self.__plugins_on_init = []
|
||||
self.__plugins_on_start = []
|
||||
self.__plugins_on_stop = []
|
||||
self.__plugins_on_exit = []
|
||||
self.__plugins_on_pre_break = []
|
||||
self.__plugins_on_start_break = []
|
||||
self.__plugins_on_stop_break = []
|
||||
self.__plugins_on_countdown = []
|
||||
self.__plugins_update_next_break = []
|
||||
self.__widget_plugins = []
|
||||
self.__tray_actions_plugins = []
|
||||
self.last_break = None
|
||||
self.horizontal_line = "─" * HORIZONTAL_LINE_LENGTH
|
||||
|
||||
|
@ -95,7 +82,8 @@ class PluginManager:
|
|||
# Load the plugins
|
||||
for plugin in config.get("plugins"):
|
||||
try:
|
||||
self.__load_plugin(plugin)
|
||||
loaded_plugin = LoadedPlugin(plugin)
|
||||
self.__plugins[loaded_plugin.id] = loaded_plugin
|
||||
except RequiredPluginException as e:
|
||||
raise e
|
||||
except BaseException as e:
|
||||
|
@ -109,62 +97,85 @@ class PluginManager:
|
|||
logging.error("Error in loading the plugin %s: %s", plugin["id"], e)
|
||||
continue
|
||||
# Initialize the plugins
|
||||
for plugin in self.__plugins_on_init:
|
||||
plugin["module"].init(context, config, plugin["config"])
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.init_plugin(context, config)
|
||||
return True
|
||||
|
||||
def needs_retry(self):
|
||||
return self.get_retryable_error() is not None
|
||||
|
||||
def get_retryable_error(self):
|
||||
for plugin in self.__plugins.values():
|
||||
if plugin.required_plugin and plugin.errored and plugin.enabled:
|
||||
if (
|
||||
isinstance(plugin.last_error, PluginDependency)
|
||||
and plugin.last_error.retryable
|
||||
):
|
||||
return RequiredPluginException(
|
||||
plugin.id, plugin.get_name(), plugin.last_error
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def retry_errored_plugins(self):
|
||||
for plugin in self.__plugins.values():
|
||||
if plugin.required_plugin and plugin.errored and plugin.enabled:
|
||||
if (
|
||||
isinstance(plugin.last_error, PluginDependency)
|
||||
and plugin.last_error.retryable
|
||||
):
|
||||
plugin.reload_errored()
|
||||
|
||||
def start(self):
|
||||
"""Execute the on_start() function of plugins."""
|
||||
for plugin in self.__plugins_on_start:
|
||||
plugin["module"].on_start()
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.call_plugin_method("on_start")
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
"""Execute the on_stop() function of plugins."""
|
||||
for plugin in self.__plugins_on_stop:
|
||||
plugin["module"].on_stop()
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.call_plugin_method("on_stop")
|
||||
return True
|
||||
|
||||
def exit(self):
|
||||
"""Execute the on_exit() function of plugins."""
|
||||
for plugin in self.__plugins_on_exit:
|
||||
plugin["module"].on_exit()
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.call_plugin_method("on_exit")
|
||||
return True
|
||||
|
||||
def pre_break(self, break_obj):
|
||||
"""Execute the on_pre_break(break_obj) function of plugins."""
|
||||
for plugin in self.__plugins_on_pre_break:
|
||||
if break_obj.plugin_enabled(plugin["id"], plugin["enabled"]):
|
||||
if plugin["module"].on_pre_break(break_obj):
|
||||
return False
|
||||
for plugin in self.__plugins.values():
|
||||
if plugin.call_plugin_method_break_obj("on_pre_break", 1, break_obj):
|
||||
return False
|
||||
return True
|
||||
|
||||
def start_break(self, break_obj):
|
||||
"""Execute the start_break(break_obj) function of plugins."""
|
||||
self.last_break = break_obj
|
||||
for plugin in self.__plugins_on_start_break:
|
||||
if break_obj.plugin_enabled(plugin["id"], plugin["enabled"]):
|
||||
if plugin["module"].on_start_break(break_obj):
|
||||
return False
|
||||
for plugin in self.__plugins.values():
|
||||
if plugin.call_plugin_method_break_obj("on_start_break", 1, break_obj):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def stop_break(self):
|
||||
"""Execute the stop_break() function of plugins."""
|
||||
for plugin in self.__plugins_on_stop_break:
|
||||
if self.last_break.plugin_enabled(plugin["id"], plugin["enabled"]):
|
||||
plugin["module"].on_stop_break()
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.call_plugin_method("on_stop_break")
|
||||
|
||||
def countdown(self, countdown, seconds):
|
||||
"""Execute the on_countdown(countdown, seconds) function of plugins."""
|
||||
for plugin in self.__plugins_on_countdown:
|
||||
if self.last_break.plugin_enabled(plugin["id"], plugin["enabled"]):
|
||||
plugin["module"].on_countdown(countdown, seconds)
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.call_plugin_method("on_countdown", 2, countdown, seconds)
|
||||
|
||||
def update_next_break(self, break_obj, break_time):
|
||||
"""Execute the update_next_break(break_time) function of plugins."""
|
||||
for plugin in self.__plugins_update_next_break:
|
||||
plugin["module"].update_next_break(break_obj, break_time)
|
||||
for plugin in self.__plugins.values():
|
||||
plugin.call_plugin_method_break_obj(
|
||||
"update_next_break", 2, break_obj, break_time
|
||||
)
|
||||
return True
|
||||
|
||||
def get_break_screen_widgets(self, break_obj):
|
||||
|
@ -174,184 +185,219 @@ class PluginManager:
|
|||
get_widget_content functions of plugins.
|
||||
"""
|
||||
widget = ""
|
||||
for plugin in self.__widget_plugins:
|
||||
if break_obj.plugin_enabled(plugin["id"], plugin["enabled"]):
|
||||
try:
|
||||
title = plugin["module"].get_widget_title(break_obj).upper().strip()
|
||||
if title == "":
|
||||
continue
|
||||
content = plugin["module"].get_widget_content(break_obj)
|
||||
if content == "":
|
||||
continue
|
||||
widget += "<b>{}</b>\n{}\n{}\n\n\n".format(
|
||||
title, self.horizontal_line, content
|
||||
)
|
||||
except BaseException:
|
||||
for plugin in self.__plugins.values():
|
||||
try:
|
||||
title = plugin.call_plugin_method_break_obj(
|
||||
"get_widget_title", 1, break_obj
|
||||
)
|
||||
if title is None or not isinstance(title, str) or title == "":
|
||||
continue
|
||||
content = plugin.call_plugin_method_break_obj(
|
||||
"get_widget_content", 1, break_obj
|
||||
)
|
||||
if content is None or not isinstance(content, str) or content == "":
|
||||
continue
|
||||
title = title.upper().strip()
|
||||
if title == "":
|
||||
continue
|
||||
widget += "<b>{}</b>\n{}\n{}\n\n\n".format(
|
||||
title, self.horizontal_line, content
|
||||
)
|
||||
except BaseException:
|
||||
continue
|
||||
return widget.strip()
|
||||
|
||||
def get_break_screen_tray_actions(self, break_obj):
|
||||
"""Return Tray Actions."""
|
||||
actions = []
|
||||
for plugin in self.__tray_actions_plugins:
|
||||
if break_obj.plugin_enabled(plugin["id"], plugin["enabled"]):
|
||||
action = plugin["module"].get_tray_action(break_obj)
|
||||
if action:
|
||||
actions.append(action)
|
||||
for plugin in self.__plugins.values():
|
||||
action = plugin.call_plugin_method_break_obj(
|
||||
"get_tray_action", 1, break_obj
|
||||
)
|
||||
if action:
|
||||
actions.append(action)
|
||||
|
||||
return actions
|
||||
|
||||
def __load_plugin(self, plugin):
|
||||
"""Load the given plugin."""
|
||||
plugin_enabled = plugin["enabled"]
|
||||
if plugin["id"] in self.__plugins and not plugin_enabled:
|
||||
# A disabled plugin but that was loaded earlier
|
||||
plugin_obj = self.__plugins[plugin["id"]]
|
||||
if plugin_obj["enabled"]:
|
||||
# Previously enabled but now disabled
|
||||
plugin_obj["enabled"] = False
|
||||
utility.remove_if_exists(self.__plugins_on_start, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_stop, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_exit, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_update_next_break, plugin_obj)
|
||||
# Call the plugin.disable method if available
|
||||
if utility.has_method(plugin_obj["module"], "disable"):
|
||||
plugin_obj["module"].disable()
|
||||
logging.info("Successfully unloaded the plugin '%s'", plugin["id"])
|
||||
|
||||
if not plugin_obj["break_override_allowed"]:
|
||||
# Remaining methods also should be removed
|
||||
utility.remove_if_exists(self.__plugins_on_init, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_pre_break, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_start_break, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_stop_break, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_countdown, plugin_obj)
|
||||
utility.remove_if_exists(self.__widget_plugins, plugin_obj)
|
||||
utility.remove_if_exists(self.__tray_actions_plugins, plugin_obj)
|
||||
del self.__plugins[plugin["id"]]
|
||||
class LoadedPlugin:
|
||||
# state of the plugin
|
||||
enabled: bool = False
|
||||
break_override_allowed: bool = False
|
||||
errored: bool = False
|
||||
required_plugin: bool = False
|
||||
|
||||
# misc data
|
||||
# FIXME: rename to plugin_config to plugin_json? plugin_config and config are easy
|
||||
# to confuse
|
||||
config = None
|
||||
plugin_config = None
|
||||
plugin_dir = None
|
||||
module = None
|
||||
last_error = None
|
||||
id = None
|
||||
|
||||
def __init__(self, plugin):
|
||||
(plugin_config, plugin_dir) = self._load_config_json(plugin["id"])
|
||||
|
||||
self.id = plugin["id"]
|
||||
self.plugin_config = plugin_config
|
||||
self.plugin_dir = plugin_dir
|
||||
self.enabled = plugin["enabled"]
|
||||
self.break_override_allowed = plugin_config.get("break_override_allowed", False)
|
||||
self.required_plugin = plugin_config.get("required_plugin", False)
|
||||
|
||||
self.config = dict(plugin.get("settings", {}))
|
||||
self.config["path"] = os.path.join(plugin_dir, plugin["id"])
|
||||
|
||||
if self.enabled or self.break_override_allowed:
|
||||
plugin_path = os.path.join(plugin_dir, self.id)
|
||||
message = utility.check_plugin_dependencies(
|
||||
plugin["id"], plugin_config, plugin.get("settings", {}), plugin_path
|
||||
)
|
||||
|
||||
if message:
|
||||
self.errored = True
|
||||
self.last_error = message
|
||||
if self.required_plugin and not (
|
||||
isinstance(message, PluginDependency) and message.retryable
|
||||
):
|
||||
raise RequiredPluginException(
|
||||
plugin["id"], plugin_config["meta"]["name"], message
|
||||
)
|
||||
return
|
||||
|
||||
self._import_plugin()
|
||||
|
||||
def reload_config(self, plugin):
|
||||
if self.enabled and not plugin["enabled"]:
|
||||
self.enabled = False
|
||||
if not self.errored and utility.has_method(self.module, "disable"):
|
||||
self.module.disable()
|
||||
|
||||
if not self.enabled and plugin["enabled"]:
|
||||
self.enabled = True
|
||||
|
||||
# Update the config
|
||||
self.config = dict(plugin.get("settings", {}))
|
||||
self.config["path"] = os.path.join(self.plugin_dir, plugin["id"])
|
||||
|
||||
if self.enabled or self.break_override_allowed:
|
||||
plugin_path = os.path.join(self.plugin_dir, self.id)
|
||||
message = utility.check_plugin_dependencies(
|
||||
self.id, self.plugin_config, self.config, plugin_path
|
||||
)
|
||||
|
||||
if message:
|
||||
self.errored = True
|
||||
self.last_error = message
|
||||
elif self.errored:
|
||||
self.errored = False
|
||||
self.last_error = None
|
||||
|
||||
if not self.errored and self.module is None:
|
||||
# No longer errored, import the module now
|
||||
self._import_plugin()
|
||||
|
||||
def reload_errored(self):
|
||||
if not self.errored:
|
||||
return
|
||||
|
||||
if self.enabled or self.break_override_allowed:
|
||||
plugin_path = os.path.join(self.plugin_dir, self.id)
|
||||
message = utility.check_plugin_dependencies(
|
||||
self.id, self.plugin_config, self.config, plugin_path
|
||||
)
|
||||
|
||||
if message:
|
||||
self.errored = True
|
||||
self.last_error = message
|
||||
elif self.errored:
|
||||
self.errored = False
|
||||
self.last_error = None
|
||||
|
||||
if not self.errored and self.module is None:
|
||||
# No longer errored, import the module now
|
||||
self._import_plugin()
|
||||
|
||||
def get_name(self):
|
||||
return self.plugin_config["meta"]["name"]
|
||||
|
||||
def _import_plugin(self):
|
||||
if self.errored:
|
||||
# do not try to import errored plugin
|
||||
return
|
||||
|
||||
self.module = importlib.import_module((self.id + ".plugin"))
|
||||
logging.info("Successfully loaded %s", str(self.module))
|
||||
|
||||
if utility.has_method(self.module, "enable"):
|
||||
self.module.enable()
|
||||
|
||||
def _load_config_json(self, plugin_id):
|
||||
# Look for plugin.py
|
||||
if os.path.isfile(
|
||||
os.path.join(utility.SYSTEM_PLUGINS_DIR, plugin["id"], "plugin.py")
|
||||
os.path.join(utility.SYSTEM_PLUGINS_DIR, plugin_id, "plugin.py")
|
||||
):
|
||||
plugin_dir = utility.SYSTEM_PLUGINS_DIR
|
||||
elif os.path.isfile(
|
||||
os.path.join(utility.USER_PLUGINS_DIR, plugin["id"], "plugin.py")
|
||||
os.path.join(utility.USER_PLUGINS_DIR, plugin_id, "plugin.py")
|
||||
):
|
||||
plugin_dir = utility.USER_PLUGINS_DIR
|
||||
else:
|
||||
logging.error("plugin.py not found for the plugin: %s", plugin["id"])
|
||||
return
|
||||
raise Exception("plugin.py not found for the plugin: %s", plugin_id)
|
||||
# Look for config.json
|
||||
plugin_path = os.path.join(plugin_dir, plugin["id"])
|
||||
plugin_path = os.path.join(plugin_dir, plugin_id)
|
||||
plugin_config_path = os.path.join(plugin_path, "config.json")
|
||||
if not os.path.isfile(plugin_config_path):
|
||||
logging.error("config.json not found for the plugin: %s", plugin["id"])
|
||||
return
|
||||
raise Exception("config.json not found for the plugin: %s", plugin_id)
|
||||
plugin_config = utility.load_json(plugin_config_path)
|
||||
if plugin_config is None:
|
||||
raise Exception("config.json empty/invalid for the plugin: %s", plugin_id)
|
||||
|
||||
return (plugin_config, plugin_dir)
|
||||
|
||||
def init_plugin(self, context, safeeyes_config):
|
||||
if self.errored:
|
||||
return
|
||||
if self.break_override_allowed or self.enabled:
|
||||
if utility.has_method(self.module, "init", 3):
|
||||
self.module.init(context, safeeyes_config, self.config)
|
||||
|
||||
if plugin_enabled or plugin_config.get("break_override_allowed", False):
|
||||
if plugin["id"] in self.__plugins:
|
||||
# The plugin is already enabled or partially loaded due to
|
||||
# break_override_allowed
|
||||
def call_plugin_method_break_obj(
|
||||
self, method_name: str, num_args, break_obj, *args, **kwargs
|
||||
):
|
||||
if self.errored:
|
||||
return None
|
||||
|
||||
# Validate the dependencies again
|
||||
if utility.check_plugin_dependencies(
|
||||
plugin["id"], plugin_config, plugin.get("settings", {}), plugin_path
|
||||
):
|
||||
plugin_obj["enabled"] = False
|
||||
utility.remove_if_exists(self.__plugins_on_start, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_stop, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_exit, plugin_obj)
|
||||
utility.remove_if_exists(
|
||||
self.__plugins_update_next_break, plugin_obj
|
||||
)
|
||||
utility.remove_if_exists(self.__plugins_on_init, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_pre_break, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_start_break, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_stop_break, plugin_obj)
|
||||
utility.remove_if_exists(self.__plugins_on_countdown, plugin_obj)
|
||||
utility.remove_if_exists(self.__widget_plugins, plugin_obj)
|
||||
utility.remove_if_exists(self.__tray_actions_plugins, plugin_obj)
|
||||
del self.__plugins[plugin["id"]]
|
||||
enabled = False
|
||||
if self.break_override_allowed:
|
||||
enabled = break_obj.plugin_enabled(self.id, self.enabled)
|
||||
else:
|
||||
enabled = self.enabled
|
||||
|
||||
# Use the existing plugin object
|
||||
plugin_obj = self.__plugins[plugin["id"]]
|
||||
if enabled:
|
||||
return self._call_plugin_method_internal(
|
||||
method_name, num_args, break_obj, *args, **kwargs
|
||||
)
|
||||
|
||||
# Update the config
|
||||
plugin_obj["config"] = dict(plugin.get("settings", {}))
|
||||
plugin_obj["config"]["path"] = os.path.join(plugin_dir, plugin["id"])
|
||||
return None
|
||||
|
||||
if plugin_obj["enabled"]:
|
||||
# Already loaded completely
|
||||
return
|
||||
# Plugin was partially loaded due to break_override_allowed
|
||||
if plugin_enabled:
|
||||
# Load the rest of the methods
|
||||
plugin_obj["enabled"] = True
|
||||
module = plugin_obj["module"]
|
||||
self.__init_plugin(module, plugin_obj)
|
||||
else:
|
||||
# This is the first time to load the plugin
|
||||
# Check for dependencies
|
||||
message = utility.check_plugin_dependencies(
|
||||
plugin["id"], plugin_config, plugin.get("settings", {}), plugin_path
|
||||
)
|
||||
if message:
|
||||
if plugin_config.get("required_plugin", False):
|
||||
raise RequiredPluginException(
|
||||
plugin["id"], plugin_config["meta"]["name"], message
|
||||
)
|
||||
return
|
||||
def call_plugin_method(self, method_name: str, num_args=0, *args, **kwargs):
|
||||
if self.errored:
|
||||
return None
|
||||
|
||||
# Load the plugin module
|
||||
module = importlib.import_module((plugin["id"] + ".plugin"))
|
||||
logging.info("Successfully loaded %s", str(module))
|
||||
plugin_obj = {
|
||||
"id": plugin["id"],
|
||||
"module": module,
|
||||
"config": dict(plugin.get("settings", {})),
|
||||
"enabled": plugin_enabled,
|
||||
"break_override_allowed": plugin_config.get(
|
||||
"break_override_allowed", False
|
||||
),
|
||||
}
|
||||
# Inject the plugin directory into the config
|
||||
plugin_obj["config"]["path"] = os.path.join(plugin_dir, plugin["id"])
|
||||
self.__plugins[plugin["id"]] = plugin_obj
|
||||
if utility.has_method(module, "enable"):
|
||||
module.enable()
|
||||
if plugin_enabled:
|
||||
self.__init_plugin(module, plugin_obj)
|
||||
if utility.has_method(module, "init", 3):
|
||||
self.__plugins_on_init.append(plugin_obj)
|
||||
if utility.has_method(module, "on_pre_break", 1):
|
||||
self.__plugins_on_pre_break.append(plugin_obj)
|
||||
if utility.has_method(module, "on_start_break", 1):
|
||||
self.__plugins_on_start_break.append(plugin_obj)
|
||||
if utility.has_method(module, "on_stop_break", 0):
|
||||
self.__plugins_on_stop_break.append(plugin_obj)
|
||||
if utility.has_method(module, "on_countdown", 2):
|
||||
self.__plugins_on_countdown.append(plugin_obj)
|
||||
if utility.has_method(
|
||||
module, "get_widget_title", 1
|
||||
) and utility.has_method(module, "get_widget_content", 1):
|
||||
self.__widget_plugins.append(plugin_obj)
|
||||
if utility.has_method(module, "get_tray_action", 1):
|
||||
self.__tray_actions_plugins.append(plugin_obj)
|
||||
if self.enabled:
|
||||
return self._call_plugin_method_internal(
|
||||
method_name, num_args, *args, **kwargs
|
||||
)
|
||||
|
||||
def __init_plugin(self, module, plugin_obj):
|
||||
"""Collect mandatory methods from the plugin and add them to the life
|
||||
cycle methods list.
|
||||
"""
|
||||
if utility.has_method(module, "on_start"):
|
||||
self.__plugins_on_start.append(plugin_obj)
|
||||
if utility.has_method(module, "on_stop"):
|
||||
self.__plugins_on_stop.append(plugin_obj)
|
||||
if utility.has_method(module, "on_exit"):
|
||||
self.__plugins_on_exit.append(plugin_obj)
|
||||
if utility.has_method(module, "update_next_break", 2):
|
||||
self.__plugins_update_next_break.append(plugin_obj)
|
||||
return None
|
||||
|
||||
def _call_plugin_method_internal(
|
||||
self, method_name: str, num_args=0, *args, **kwargs
|
||||
):
|
||||
# FIXME: cache if method exists
|
||||
if utility.has_method(self.module, method_name, num_args):
|
||||
return getattr(self.module, method_name)(*args, **kwargs)
|
||||
return None
|
||||
|
|
|
@ -44,7 +44,8 @@ def validate(plugin_config, plugin_settings):
|
|||
"Please install service providing tray icons for your desktop"
|
||||
" environment."
|
||||
),
|
||||
link="https://github.com/slgobinath/SafeEyes/wiki/How-to-install-backend-for-Safe-Eyes-tray-icon", # noqa E501
|
||||
link="https://github.com/slgobinath/SafeEyes/wiki/How-to-install-backend-for-Safe-Eyes-tray-icon",
|
||||
retryable=True,
|
||||
)
|
||||
|
||||
command = None
|
||||
|
|
|
@ -51,6 +51,12 @@ SNI_NODE_INFO = Gio.DBusNodeInfo.new_for_xml(
|
|||
<property name="Status" type="s" access="read"/>
|
||||
<signal name="NewIcon"/>
|
||||
<signal name="NewTooltip"/>
|
||||
|
||||
<property name="XAyatanaLabel" type="s" access="read"/>
|
||||
<signal name="XAyatanaNewLabel">
|
||||
<arg type="s" name="label" direction="out" />
|
||||
<arg type="s" name="guide" direction="out" />
|
||||
</signal>
|
||||
</interface>
|
||||
</node>"""
|
||||
).interfaces[0]
|
||||
|
@ -361,6 +367,7 @@ class StatusNotifierItemService(DBusService):
|
|||
IconName = "io.github.slgobinath.SafeEyes-enabled"
|
||||
IconThemePath = ""
|
||||
ToolTip = ("", [], "Safe Eyes", "")
|
||||
XAyatanaLabel = ""
|
||||
ItemIsMenu = True
|
||||
Menu = None
|
||||
|
||||
|
@ -409,6 +416,11 @@ class StatusNotifierItemService(DBusService):
|
|||
|
||||
self.emit_signal("NewTooltip")
|
||||
|
||||
def set_xayatanalabel(self, label):
|
||||
self.XAyatanaLabel = label
|
||||
|
||||
self.emit_signal("XAyatanaNewLabel", (label, ""))
|
||||
|
||||
|
||||
class TrayIcon:
|
||||
"""Create and show the tray icon along with the tray menu."""
|
||||
|
@ -517,11 +529,12 @@ class TrayIcon:
|
|||
)
|
||||
continue
|
||||
|
||||
ttw = time_in_minutes
|
||||
disable_items.append(
|
||||
{
|
||||
"id": disable_option_dynamic_id,
|
||||
"label": label,
|
||||
"callback": lambda: self.on_disable_clicked(time_in_minutes),
|
||||
"callback": lambda ttw=ttw: self.on_disable_clicked(ttw),
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -629,6 +642,7 @@ class TrayIcon:
|
|||
description = ""
|
||||
|
||||
self.sni_service.set_tooltip("Safe Eyes", description)
|
||||
self.sni_service.set_xayatanalabel(description)
|
||||
|
||||
def quit_safe_eyes(self):
|
||||
"""Handle Quit menu action.
|
||||
|
|
|
@ -36,7 +36,7 @@ from safeeyes.core import SafeEyesCore
|
|||
from safeeyes.ui.settings_dialog import SettingsDialog
|
||||
|
||||
gi.require_version("Gtk", "3.0")
|
||||
from gi.repository import Gtk, Gio
|
||||
from gi.repository import Gtk, Gio, GLib
|
||||
|
||||
SAFE_EYES_VERSION = "2.2.2"
|
||||
|
||||
|
@ -45,6 +45,7 @@ class SafeEyes(Gtk.Application):
|
|||
"""This class represents a runnable Safe Eyes instance."""
|
||||
|
||||
required_plugin_dialog_active = False
|
||||
retry_errored_plugins_count = 0
|
||||
|
||||
def __init__(self, system_locale, config, cli_args):
|
||||
super().__init__(
|
||||
|
@ -123,10 +124,7 @@ class SafeEyes(Gtk.Application):
|
|||
try:
|
||||
self.plugins_manager.init(self.context, self.config)
|
||||
except RequiredPluginException as e:
|
||||
self.show_required_plugin_dialog(
|
||||
e.get_plugin_id(), e.get_plugin_name(), e.get_message()
|
||||
)
|
||||
self.required_plugin_dialog_active = True
|
||||
self.show_required_plugin_dialog(e)
|
||||
|
||||
self.hold()
|
||||
|
||||
|
@ -135,7 +133,11 @@ class SafeEyes(Gtk.Application):
|
|||
if self.config.get("use_rpc_server", True):
|
||||
self.__start_rpc_server()
|
||||
|
||||
if not self.required_plugin_dialog_active and self.safe_eyes_core.has_breaks():
|
||||
if (
|
||||
not self.plugins_manager.needs_retry()
|
||||
and not self.required_plugin_dialog_active
|
||||
and self.safe_eyes_core.has_breaks()
|
||||
):
|
||||
self.active = True
|
||||
self.context["state"] = State.START
|
||||
self.plugins_manager.start() # Call the start method of all plugins
|
||||
|
@ -145,6 +147,9 @@ class SafeEyes(Gtk.Application):
|
|||
def do_activate(self):
|
||||
logging.info("Application activated")
|
||||
|
||||
if self.plugins_manager.needs_retry():
|
||||
GLib.timeout_add_seconds(1, self._retry_errored_plugins)
|
||||
|
||||
if self.cli_args.about:
|
||||
self.show_about()
|
||||
elif self.cli_args.disable:
|
||||
|
@ -156,6 +161,30 @@ class SafeEyes(Gtk.Application):
|
|||
elif self.cli_args.take_break:
|
||||
self.take_break()
|
||||
|
||||
def _retry_errored_plugins(self):
|
||||
if not self.plugins_manager.needs_retry():
|
||||
return
|
||||
|
||||
logging.info("Retry loading errored plugin")
|
||||
self.plugins_manager.retry_errored_plugins()
|
||||
|
||||
error = self.plugins_manager.get_retryable_error()
|
||||
|
||||
if error is None:
|
||||
# success
|
||||
self.restart(self.config, set_active=True)
|
||||
return
|
||||
|
||||
# errored again
|
||||
if self.retry_errored_plugins_count >= 3:
|
||||
self.show_required_plugin_dialog(error)
|
||||
return
|
||||
|
||||
timeout = pow(2, self.retry_errored_plugins_count)
|
||||
self.retry_errored_plugins_count += 1
|
||||
|
||||
GLib.timeout_add_seconds(timeout, self._retry_errored_plugins)
|
||||
|
||||
def show_settings(self):
|
||||
"""Listen to tray icon Settings action and send the signal to Settings
|
||||
dialog.
|
||||
|
@ -166,12 +195,16 @@ class SafeEyes(Gtk.Application):
|
|||
settings_dialog = SettingsDialog(self.config.clone(), self.save_settings)
|
||||
settings_dialog.show()
|
||||
|
||||
def show_required_plugin_dialog(self, plugin_id, plugin_name, message):
|
||||
def show_required_plugin_dialog(self, error: RequiredPluginException):
|
||||
self.required_plugin_dialog_active = True
|
||||
|
||||
logging.info("Show RequiredPlugin dialog")
|
||||
plugin_id = error.get_plugin_id()
|
||||
|
||||
dialog = RequiredPluginDialog(
|
||||
plugin_id,
|
||||
plugin_name,
|
||||
message,
|
||||
error.get_plugin_id(),
|
||||
error.get_plugin_name(),
|
||||
error.get_message(),
|
||||
self.quit,
|
||||
lambda: self.disable_plugin(plugin_id),
|
||||
)
|
||||
|
@ -306,10 +339,7 @@ class SafeEyes(Gtk.Application):
|
|||
try:
|
||||
self.plugins_manager.init(self.context, self.config)
|
||||
except RequiredPluginException as e:
|
||||
self.show_required_plugin_dialog(
|
||||
e.get_plugin_id(), e.get_plugin_name(), e.get_message()
|
||||
)
|
||||
self.required_plugin_dialog_active = True
|
||||
self.show_required_plugin_dialog(e)
|
||||
return
|
||||
|
||||
if set_active:
|
||||
|
|
Loading…
Reference in New Issue