mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-06 21:44:16 +02:00
0.9.0
This commit is contained in:
@@ -1,48 +1,82 @@
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from io import StringIO
|
||||
from subprocess import Popen
|
||||
from threading import Lock, Thread
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QCoreApplication, Qt, QSize
|
||||
from PyQt5.QtCore import QThread, pyqtSignal, QCoreApplication, QSize
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QWidget, QSizePolicy
|
||||
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu
|
||||
|
||||
from bauh import __app_name__
|
||||
from bauh.api.abstract.controller import SoftwareManager
|
||||
from bauh import __app_name__, ROOT_DIR
|
||||
from bauh.api.abstract.model import PackageUpdate
|
||||
from bauh.view.qt import qt_utils
|
||||
from bauh.commons.system import run_cmd
|
||||
from bauh.context import generate_i18n
|
||||
from bauh.view.core.tray_client import TRAY_CHECK_FILE
|
||||
from bauh.view.qt.about import AboutDialog
|
||||
from bauh.view.qt.settings import SettingsWindow
|
||||
from bauh.view.qt.view_utils import load_resource_icon
|
||||
from bauh.view.qt.window import ManageWindow
|
||||
from bauh.view.util import util
|
||||
from bauh.view.util.translation import I18n
|
||||
from bauh.view.util import util, resource
|
||||
|
||||
|
||||
def list_updates() -> List[PackageUpdate]:
|
||||
if run_cmd('which bauh-cli', print_error=False):
|
||||
output = run_cmd('bauh-cli updates -f json')
|
||||
|
||||
if output:
|
||||
return [PackageUpdate(pkg_id=o['id'], name=o['name'], version=o['version'], pkg_type=o['type']) for o in json.loads(output)]
|
||||
|
||||
return []
|
||||
|
||||
|
||||
class UpdateCheck(QThread):
|
||||
|
||||
signal = pyqtSignal(list)
|
||||
|
||||
def __init__(self, manager: SoftwareManager, check_interval: int, parent=None):
|
||||
def __init__(self, check_interval: int, lock: Lock, check_file: bool, parent=None):
|
||||
super(UpdateCheck, self).__init__(parent)
|
||||
self.check_interval = check_interval
|
||||
self.manager = manager
|
||||
self.lock = lock
|
||||
self.check_file = check_file
|
||||
|
||||
def _notify_updates(self):
|
||||
self.lock.acquire()
|
||||
try:
|
||||
updates = list_updates()
|
||||
|
||||
if updates is not None:
|
||||
self.signal.emit(updates)
|
||||
finally:
|
||||
self.lock.release()
|
||||
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
def run(self):
|
||||
|
||||
while True:
|
||||
updates = self.manager.list_updates()
|
||||
self.signal.emit(updates)
|
||||
time.sleep(self.check_interval)
|
||||
if self.check_file:
|
||||
if os.path.exists(TRAY_CHECK_FILE):
|
||||
self._notify_updates()
|
||||
try:
|
||||
os.remove(TRAY_CHECK_FILE)
|
||||
except:
|
||||
traceback.print_exc()
|
||||
else:
|
||||
time.sleep(self.check_interval)
|
||||
else:
|
||||
self._notify_updates()
|
||||
|
||||
|
||||
class TrayIcon(QSystemTrayIcon):
|
||||
|
||||
def __init__(self, i18n: I18n, manager: SoftwareManager, manage_window: ManageWindow, config: dict, screen_size: QSize):
|
||||
def __init__(self, config: dict, screen_size: QSize, manage_process: Popen = None, settings_process: Popen = None):
|
||||
super(TrayIcon, self).__init__()
|
||||
self.i18n = i18n
|
||||
self.manager = manager
|
||||
self.i18n = generate_i18n(config, resource.get_path('locale/tray'))
|
||||
self.screen_size = screen_size
|
||||
self.manage_process = manage_process
|
||||
self.settings_process = settings_process
|
||||
|
||||
if config['ui']['tray']['default_icon']:
|
||||
self.icon_default = QIcon(config['ui']['tray']['default_icon'])
|
||||
@@ -67,7 +101,7 @@ class TrayIcon(QSystemTrayIcon):
|
||||
self.action_manage = self.menu.addAction(self.i18n['tray.action.manage'])
|
||||
self.action_manage.triggered.connect(self.show_manage_window)
|
||||
|
||||
self.action_settings = self.menu.addAction(self.i18n['settings'].capitalize())
|
||||
self.action_settings = self.menu.addAction(self.i18n['tray.settings'].capitalize())
|
||||
self.action_settings.triggered.connect(self.show_settings_window)
|
||||
|
||||
self.action_about = self.menu.addAction(self.i18n['tray.action.about'])
|
||||
@@ -82,10 +116,15 @@ class TrayIcon(QSystemTrayIcon):
|
||||
self.dialog_about = None
|
||||
self.settings_window = None
|
||||
|
||||
self.check_thread = UpdateCheck(check_interval=int(config['updates']['check_interval']), manager=self.manager)
|
||||
self.check_lock = Lock()
|
||||
self.check_thread = UpdateCheck(check_interval=int(config['updates']['check_interval']), check_file=False, lock=self.check_lock)
|
||||
self.check_thread.signal.connect(self.notify_updates)
|
||||
self.check_thread.start()
|
||||
|
||||
self.recheck_thread = UpdateCheck(check_interval=2, check_file=True, lock=self.check_lock)
|
||||
self.recheck_thread.signal.connect(self.notify_updates)
|
||||
self.recheck_thread.start()
|
||||
|
||||
self.last_updates = set()
|
||||
self.update_notification = bool(config['system']['notifications'])
|
||||
self.lock_notify = Lock()
|
||||
@@ -93,10 +132,8 @@ class TrayIcon(QSystemTrayIcon):
|
||||
self.activated.connect(self.handle_click)
|
||||
self.set_default_tooltip()
|
||||
|
||||
self.manage_window = manage_window
|
||||
|
||||
def set_default_tooltip(self):
|
||||
self.setToolTip('{} ({})'.format(self.i18n['manage_window.title'], __app_name__).lower())
|
||||
self.setToolTip('{} ({})'.format(self.i18n['tray.action.manage'], __app_name__).lower())
|
||||
|
||||
def handle_click(self, reason):
|
||||
if reason == self.Trigger:
|
||||
@@ -109,7 +146,6 @@ class TrayIcon(QSystemTrayIcon):
|
||||
self.notify_updates(self.manager.list_updates(), notify_user=notify_user)
|
||||
|
||||
def notify_updates(self, updates: List[PackageUpdate], notify_user: bool = True):
|
||||
|
||||
self.lock_notify.acquire()
|
||||
|
||||
try:
|
||||
@@ -133,8 +169,8 @@ class TrayIcon(QSystemTrayIcon):
|
||||
msg.write(self.i18n['notification.update{}'.format('' if n_updates == 1 else 's')].format(n_updates))
|
||||
|
||||
if len(ups_by_type) > 1:
|
||||
for ptype, count in ups_by_type.items():
|
||||
msg.write('\n * {} ( {} )'.format(ptype.capitalize(), count))
|
||||
for ptype in sorted(ups_by_type):
|
||||
msg.write('\n * {} ( {} )'.format(ptype, ups_by_type[ptype]))
|
||||
|
||||
msg.seek(0)
|
||||
msg = msg.read()
|
||||
@@ -155,25 +191,18 @@ class TrayIcon(QSystemTrayIcon):
|
||||
self.lock_notify.release()
|
||||
|
||||
def show_manage_window(self):
|
||||
if self.manage_window.isMinimized():
|
||||
self.manage_window.setWindowState(Qt.WindowNoState)
|
||||
elif not self.manage_window.isVisible():
|
||||
self.manage_window.refresh_apps()
|
||||
self.manage_window.show()
|
||||
if self.manage_process is None:
|
||||
self.manage_process = Popen([sys.executable, '{}/app.py'.format(ROOT_DIR)])
|
||||
elif self.manage_process.poll() is not None: # it means it has finished
|
||||
self.manage_process = None
|
||||
self.show_manage_window()
|
||||
|
||||
def show_settings_window(self):
|
||||
if self.settings_window:
|
||||
self.settings_window.handle_display()
|
||||
else:
|
||||
self.settings_window = SettingsWindow(manager=self.manager,
|
||||
i18n=self.i18n,
|
||||
screen_size=self.screen_size,
|
||||
tray=self,
|
||||
window=self.manage_window)
|
||||
self.settings_window.setMinimumWidth(int(self.screen_size.width() / 4))
|
||||
self.settings_window.adjustSize()
|
||||
qt_utils.centralize(self.settings_window)
|
||||
self.settings_window.show()
|
||||
if self.settings_process is None:
|
||||
self.settings_process = Popen([sys.executable, '{}/app.py'.format(ROOT_DIR), '--settings'])
|
||||
elif self.settings_process.poll() is not None: # it means it has finished
|
||||
self.settings_process = None
|
||||
self.show_settings_window()
|
||||
|
||||
def show_about(self):
|
||||
if self.dialog_about is None:
|
||||
|
||||
Reference in New Issue
Block a user