TrayIcon integrated with ManageWindow

This commit is contained in:
Vinicius Moreira
2019-06-13 11:50:29 -03:00
parent c0193a66bf
commit 6d58041f0a
6 changed files with 351 additions and 83 deletions

17
app.py Normal file
View File

@@ -0,0 +1,17 @@
#!env/bin/python
import sys
from PyQt5.QtWidgets import QApplication, QWidget
from core.controller import FlatpakController
from core.model import FlatpakManager
from view.qt.systray import TrayIcon
app = QApplication(sys.argv)
manager = FlatpakManager()
controller = FlatpakController(manager)
hidden_widget = QWidget()
trayIcon = TrayIcon(parent=hidden_widget, controller=controller, check_interval=30)
trayIcon.show()
sys.exit(app.exec_())

View File

@@ -1,20 +0,0 @@
#!env/bin/python
import sys
from PyQt5.QtWidgets import QApplication
from core.controller import FlatpakController
from core.model import FlatpakManager
from view.qt.window import MainWindow
app = QApplication(sys.argv)
app.setStyle('Fusion')
manager = FlatpakManager()
controller = FlatpakController(manager)
window_main = MainWindow(controller)
window_main.refresh()
# tray_icon = SystemTrayIcon(window_main)
window_main.show()
# tray_icon.show()
sys.exit(app.exec_())

View File

@@ -14,7 +14,7 @@
viewBox="0 0 11.495958 11.042967"
version="1.1"
id="svg3871"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="flathub_logo.svg">
<defs
id="defs3865" />
@@ -27,15 +27,15 @@
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="354.2246"
inkscape:cy="117.98097"
inkscape:cy="117.98098"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
showborder="false"
inkscape:window-width="1366"
inkscape:window-height="739"
inkscape:window-width="1360"
inkscape:window-height="707"
inkscape:window-x="0"
inkscape:window-y="260"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-bottom="-0.2"
fit-margin-top="0"

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -0,0 +1,179 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="43.449291"
height="41.737198"
viewBox="0 0 11.495958 11.042967"
version="1.1"
id="svg3871"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
sodipodi:docname="update_logo.svg">
<defs
id="defs3865" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.4"
inkscape:cx="301.87613"
inkscape:cy="-17.251714"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
showborder="false"
inkscape:window-width="1360"
inkscape:window-height="707"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-bottom="-0.2"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
units="px" />
<metadata
id="metadata3868">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-12.111406,-169.00616)">
<g
transform="matrix(0.08047549,0,0,0.0997485,-51.028672,86.747244)"
id="g10674"
style="stroke-width:0.77710575;fill:#ff2a2a;stroke:#aa0000">
<path
sodipodi:nodetypes="ccccccccccc"
inkscape:connector-curvature="0"
id="path10642"
d="m 856.01397,830.22631 -66.76365,43.44891 v 34.93973 l 33.38182,21.72315 33.37926,-21.72315 v -0.005 l 0.003,0.003 33.38183,21.72574 33.37925,-21.72315 v -34.93979 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:9.3252697;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<g
style="stroke-width:0.58728963;fill:#ff2a2a;stroke:#aa0000"
transform="matrix(0.50221552,0,0,0.50636711,429.63205,432.90461)"
id="g10652">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect10644"
width="79.110413"
height="79.110413"
x="1289.9076"
y="279.42584"
rx="0"
ry="0"
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
id="path10648"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path10650"
d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
ry="0"
rx="0"
y="215.8064"
x="1226.2882"
height="79.110413"
width="79.110413"
id="rect10646"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
<g
style="stroke-width:0.58728963;fill:#ff2a2a;stroke:#aa0000"
transform="matrix(0.50221552,0,0,0.50636711,463.01368,454.62849)"
id="g10662">
<rect
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
ry="0"
rx="0"
y="279.42584"
x="1289.9076"
height="79.110413"
width="79.110413"
id="rect10654"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect10656"
width="79.110413"
height="79.110413"
x="1226.2882"
y="215.8064"
rx="0"
ry="0"
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
<path
inkscape:connector-curvature="0"
id="path10658"
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 783.00003,826.54445 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
id="path10660"
inkscape:connector-curvature="0" />
</g>
<g
style="stroke-width:0.58728963;fill:#ff2a2a;stroke:#aa0000"
id="g10672"
transform="matrix(0.50221552,0,0,0.50636711,396.25042,454.62849)">
<rect
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
id="rect10664"
width="79.110413"
height="79.110413"
x="1289.9076"
y="279.42584"
rx="0"
ry="0"
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
<rect
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
ry="0"
rx="0"
y="215.8064"
x="1226.2882"
height="79.110413"
width="79.110413"
id="rect10666"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
<path
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
id="path10668"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
id="path10670"
d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ff2a2a;fill-opacity:1;fill-rule:nonzero;stroke:#aa0000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,29 +1,76 @@
import sys
import time
from PyQt5.QtCore import QThread, pyqtSignal, QCoreApplication
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu, QApplication, QWidget
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu
from core import resource
# to update
#apps = flatpak.list_installed()
#print(apps)
from core.controller import FlatpakController
from view.qt.window import ManageWindow
class SystemTrayIcon(QSystemTrayIcon):
class UpdateCheck(QThread):
def __init__(self, parent=None):
QSystemTrayIcon.__init__(self, QIcon(resource.get_path('img/flathub_logo.svg')), parent)
signal = pyqtSignal(int)
def __init__(self, check_interval: int, controller: FlatpakController, parent=None):
super(UpdateCheck, self).__init__(parent)
self.controller = controller
self.check_interval = check_interval
def run(self):
while True:
apps = self.controller.refresh()
updates = len([app for app in apps if app['update']])
self.signal.emit(updates)
time.sleep(self.check_interval)
class TrayIcon(QSystemTrayIcon):
def __init__(self, controller: FlatpakController, check_interval: int = 60, parent=None):
self.icon_default = QIcon(resource.get_path('img/flathub_logo.svg'))
self.icon_update = QIcon(resource.get_path('img/update_logo.svg'))
QSystemTrayIcon.__init__(self, self.icon_default, parent)
self.menu = QMenu(parent)
exitAction = self.menu.addAction("Exit")
self.action_manage = self.menu.addAction("Manage applications")
self.action_manage.triggered.connect(self.show_manage_window)
self.action_exit = self.menu.addAction("Exit")
self.action_exit.triggered.connect(lambda: QCoreApplication.exit())
self.setContextMenu(self.menu)
self.controller = controller
self.check_thread = UpdateCheck(check_interval=check_interval, controller=self.controller)
self.check_thread.signal.connect(self.notify_update)
self.check_thread.start()
self.manage_window = ManageWindow(controller=controller, tray_icon=self)
def notify_update(self, updates: int):
if updates > 0:
if self.icon() != self.icon_update:
self.setIcon(self.icon_update)
self.setToolTip('Updates found: {}'.format(updates))
if __name__ == '__main__':
app = QApplication(sys.argv)
w = QWidget()
trayIcon = SystemTrayIcon(w)
trayIcon.show()
if self.manage_window:
self.manage_window.refresh()
else:
self.setIcon(self.icon_default)
self.setToolTip(None)
sys.exit(app.exec_())
def show_manage_window(self):
if not self.manage_window:
self.manage_window = ManageWindow(controller=self.controller)
self.manage_window.refresh()
self.manage_window.show()

View File

@@ -1,18 +1,16 @@
import operator
from functools import reduce
from PyQt5 import QtCore
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from core import resource, __version__
from threading import Lock
from typing import List
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QUrl
from PyQt5.QtGui import QIcon, QColor, QPixmap
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QTableWidget, \
QTableWidgetItem, QTableView, QCheckBox, QHeaderView, QToolButton, QToolBar, \
QSizePolicy, QLabel, QMessageBox
from core import resource, __version__
from core.controller import FlatpakController
@@ -38,23 +36,24 @@ class UpdateToggleButton(QToolButton):
self.root.change_update_button_state()
class MainWindow(QWidget):
class ManageWindow(QWidget):
__COLUMNS__ = ['Package', 'Version', 'Branch', 'Arch', 'Ref', 'Latest Version', 'Origin', 'Update ?']
__COLUMNS__ = ['Package', 'Version', 'Latest Version', 'Branch', 'Arch', 'Ref', 'Origin', 'Update ?']
__BASE_HEIGHT__ = 400
def __init__(self, controller: FlatpakController):
super(MainWindow, self).__init__()
def __init__(self, controller: FlatpakController, tray_icon = None):
super(ManageWindow, self).__init__()
self.controller = controller
self.icon_cache = {}
self.tray_icon = tray_icon
self.network_man = QNetworkAccessManager()
self.network_man.finished.connect(self._load_icon)
self.icon_flathub = QIcon(resource.get_path('img/flathub_logo.svg'))
self._check_flatpak_installed()
self.resize(MainWindow.__BASE_HEIGHT__, MainWindow.__BASE_HEIGHT__)
self.setWindowTitle('flatman ({})'.format(__version__))
self.resize(ManageWindow.__BASE_HEIGHT__, ManageWindow.__BASE_HEIGHT__)
self.setWindowTitle('fpakman ({})'.format(__version__))
self.setWindowIcon(self.icon_flathub)
self.layout = QVBoxLayout()
@@ -94,17 +93,17 @@ class MainWindow(QWidget):
self.layout.addWidget(toolbar)
self.table_apps = QTableWidget()
self.table_apps.setColumnCount(len(MainWindow.__COLUMNS__))
self.table_apps.setColumnCount(len(ManageWindow.__COLUMNS__))
self.table_apps.setFocusPolicy(Qt.NoFocus)
self.table_apps.setShowGrid(False)
self.table_apps.verticalHeader().setVisible(False)
self.table_apps.setSelectionBehavior(QTableView.SelectRows)
self.table_apps.setHorizontalHeaderLabels(MainWindow.__COLUMNS__)
self.table_apps.setHorizontalHeaderLabels(ManageWindow.__COLUMNS__)
self.table_apps.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
header_horizontal = self.table_apps.horizontalHeader()
for i in range(0, len(MainWindow.__COLUMNS__)):
header_horizontal.setSectionResizeMode(i, QHeaderView.ResizeToContents)
for i in range(0, len(ManageWindow.__COLUMNS__)):
header_horizontal.setSectionResizeMode(i, QHeaderView.Stretch + QHeaderView.AdjustToContents)
self.layout.addWidget(self.table_apps)
@@ -117,7 +116,24 @@ class MainWindow(QWidget):
self.refresh_thread = RefreshPackages(self.controller)
self.refresh_thread.signal.connect(self._finish_refresh)
self.layout.addWidget(QLabel('flatpak: ' + self.controller.get_version()), alignment=Qt.AlignRight)
self.toolbar_bottom = QToolBar()
self.label_updates = QLabel('')
self.toolbar_bottom.addWidget(self.label_updates)
spacer = QWidget()
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.toolbar_bottom.addWidget(spacer)
self.toolbar_bottom.addWidget(QLabel('flatpak: ' + self.controller.get_version()))
self.layout.addWidget(self.toolbar_bottom)
self.thread_lock = Lock()
self.working = False # restrict the number of threaded actions
def closeEvent(self, event):
if self.tray_icon:
event.ignore()
self.hide()
def _load_icon(self, http_response):
icon_url = http_response.url().toString()
@@ -143,22 +159,37 @@ class MainWindow(QWidget):
error_msg.exec_()
exit(1)
def refresh(self, threaded: bool = False):
def _acquire_lock(self):
self._check_flatpak_installed()
self.thread_lock.acquire()
self._begin_action('Refreshing...')
if not self.working:
self.working = True
if threaded:
self.thread_lock.release()
return self.working
def _release_lock(self):
self.thread_lock.acquire()
if self.working:
self.working = False
self.thread_lock.release()
def refresh(self):
if self._acquire_lock():
self._check_flatpak_installed()
self._begin_action('Refreshing...')
self.refresh_thread.start()
else:
apps = self.controller.refresh()
self.update_packages(apps)
self.finish_action()
def _finish_refresh(self):
self.update_packages(self.refresh_thread.apps)
self.finish_action()
self._release_lock()
def filter_only_apps(self, only_apps: int):
@@ -170,12 +201,19 @@ class MainWindow(QWidget):
self.table_apps.setRowHidden(idx, hidden)
app['visible'] = not hidden
self.change_update_button_state()
self.change_update_state()
def change_update_button_state(self):
def change_update_state(self):
enable_bt_update = False
updates = len([app for app in self.apps if app['model']['update']])
if updates > 0:
self.label_updates.setText('Updates: {}'.format(updates))
else:
self.label_updates.setText('')
for app in self.apps:
if app['visible'] and app['update_checked']:
enable_bt_update = True
@@ -223,28 +261,28 @@ class MainWindow(QWidget):
col_version.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 1, col_version)
col_release = QTableWidgetItem()
col_release.setText(app['latest_version'])
col_release.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 2, col_release)
if app['update']:
col_release.setForeground(QColor('orange'))
col_branch = QTableWidgetItem()
col_branch.setText(app['branch'])
col_branch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 2, col_branch)
self.table_apps.setItem(idx, 3, col_branch)
col_arch = QTableWidgetItem()
col_arch.setText(app['arch'])
col_arch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 3, col_arch)
self.table_apps.setItem(idx, 4, col_arch)
col_package = QTableWidgetItem()
col_package.setText(app['ref'])
col_package.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 4, col_package)
col_release = QTableWidgetItem()
col_release.setText(app['latest_version'])
col_release.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 5, col_release)
if app['update']:
col_release.setForeground(QColor('yellow'))
self.table_apps.setItem(idx, 5, col_package)
col_origin = QTableWidgetItem()
col_origin.setText(app['origin'])
@@ -260,28 +298,35 @@ class MainWindow(QWidget):
self.apps.append(app_model)
self.change_update_button_state()
self.change_update_state()
self.filter_only_apps(2 if self.checkbox_only_apps.isChecked() else 0)
self.resize_and_center()
def resize_and_center(self):
new_width = reduce(operator.add, [self.table_apps.columnWidth(i) for i in range(len(MainWindow.__COLUMNS__))]) * 1.05
new_width = reduce(operator.add, [self.table_apps.columnWidth(i) for i in range(len(ManageWindow.__COLUMNS__))]) * 1.05
self.resize(new_width, self.height())
self.centralize()
def update_selected(self):
if self.apps:
to_update = [pak['model']['ref'] for pak in self.apps if pak['visible'] and pak['update_checked']]
if to_update:
self._begin_action('Updating...')
self.update_thread.refs_to_update = to_update
self.update_thread.start()
if self._acquire_lock():
if self.apps:
to_update = [pak['model']['ref'] for pak in self.apps if pak['visible'] and pak['update_checked']]
if to_update:
self._begin_action('Updating...')
self.update_thread.refs_to_update = to_update
self.update_thread.start()
def _finish_update_selected(self):
self.update_packages(self.update_thread.updated_apps)
self.finish_action()
if self.tray_icon and self.update_thread.updated_apps:
self.tray_icon.notify_update(len([app for app in self.update_thread.updated_apps if app['update']]))
self._release_lock()
def _begin_action(self, action_label: str):
self.label_status.setText(action_label)
self.bt_update.setEnabled(False)