architecture expanded to support other types of packaging

This commit is contained in:
Vinícius Moreira
2019-07-10 11:31:57 -03:00
committed by GitHub
parent 925aa7cec6
commit ff8510153d
11 changed files with 326 additions and 133 deletions

View File

@@ -9,7 +9,7 @@ from colorama import Fore
from fpakman import __version__ from fpakman import __version__
from fpakman.core import resource from fpakman.core import resource
from fpakman.util import util from fpakman.util import util
from fpakman.core.controller import FlatpakManager from fpakman.core.controller import FlatpakManager, GenericApplicationManager
from fpakman.util.cache import Cache from fpakman.util.cache import Cache
from fpakman.util.memory import CacheCleaner from fpakman.util.memory import CacheCleaner
from fpakman.view.qt import common from fpakman.view.qt import common
@@ -66,7 +66,8 @@ caches.append(icon_cache)
app = QApplication(sys.argv) app = QApplication(sys.argv)
app.setWindowIcon(QIcon(resource.get_path('img/logo.svg'))) app.setWindowIcon(QIcon(resource.get_path('img/logo.svg')))
manager = FlatpakManager(flatpak_api_cache) manager = GenericApplicationManager([FlatpakManager(flatpak_api_cache)])
trayIcon = TrayIcon(locale_keys=locale_keys, trayIcon = TrayIcon(locale_keys=locale_keys,
manager=manager, manager=manager,

View File

@@ -1,3 +1,4 @@
from abc import ABC, abstractmethod
from datetime import datetime from datetime import datetime
from threading import Lock from threading import Lock
from typing import List from typing import List
@@ -5,12 +6,59 @@ from typing import List
import requests import requests
from fpakman.core import flatpak from fpakman.core import flatpak
from fpakman.core.model import FlatpakApplication, ApplicationData, ApplicationStatus from fpakman.core.model import FlatpakApplication, ApplicationData, ApplicationStatus, Application
from fpakman.core.worker import FlatpakAsyncDataLoaderManager from fpakman.core.worker import FlatpakAsyncDataLoaderManager
from fpakman.util.cache import Cache from fpakman.util.cache import Cache
class FlatpakManager: class ApplicationManager(ABC):
@abstractmethod
def search(self, word: str) -> List[Application]:
pass
@abstractmethod
def read_installed(self) -> List[Application]:
pass
@abstractmethod
def downgrade_app(self, app: Application, root_password: str):
pass
@abstractmethod
def clean_cache_for(self, app: Application):
pass
@abstractmethod
def can_downgrade(self):
pass
@abstractmethod
def update_and_stream(self, app: Application):
pass
@abstractmethod
def uninstall_and_stream(self, app: Application):
pass
@abstractmethod
def get_app_type(self) -> str:
pass
@abstractmethod
def get_info(self, app: Application) -> dict:
pass
@abstractmethod
def get_history(self, app: Application) -> List[dict]:
pass
@abstractmethod
def install_and_stream(self, app: Application):
pass
class FlatpakManager(ApplicationManager):
def __init__(self, api_cache: Cache): def __init__(self, api_cache: Cache):
self.api_cache = api_cache self.api_cache = api_cache
@@ -19,6 +67,9 @@ class FlatpakManager:
self.async_data_loader = FlatpakAsyncDataLoaderManager(api_cache=self.api_cache) self.async_data_loader = FlatpakAsyncDataLoaderManager(api_cache=self.api_cache)
flatpak.set_default_remotes() flatpak.set_default_remotes()
def get_app_type(self):
return FlatpakApplication
def _map_to_model(self, app: dict) -> FlatpakApplication: def _map_to_model(self, app: dict) -> FlatpakApplication:
model = FlatpakApplication(arch=app.get('arch'), model = FlatpakApplication(arch=app.get('arch'),
@@ -103,6 +154,9 @@ class FlatpakManager:
finally: finally:
self.lock_read.release() self.lock_read.release()
def can_downgrade(self):
return True
def downgrade_app(self, app: FlatpakApplication, root_password: str): def downgrade_app(self, app: FlatpakApplication, root_password: str):
commits = flatpak.get_app_commits(app.ref, app.origin) commits = flatpak.get_app_commits(app.ref, app.origin)
@@ -114,5 +168,77 @@ class FlatpakManager:
return flatpak.downgrade_and_stream(app.ref, commits[commit_idx + 1], root_password) return flatpak.downgrade_and_stream(app.ref, commits[commit_idx + 1], root_password)
def clean_cache_for(self, app_id: str): def clean_cache_for(self, app: FlatpakApplication):
self.api_cache.delete(app_id) self.api_cache.delete(app.base_data.id)
def update_and_stream(self, app: FlatpakApplication):
return flatpak.update_and_stream(app.ref)
def uninstall_and_stream(self, app: FlatpakApplication):
return flatpak.uninstall_and_stream(app.ref)
def get_info(self, app: FlatpakApplication) -> dict:
app_info = flatpak.get_app_info_fields(app.base_data.id, app.branch)
app_info['name'] = app.base_data.name
app_info['type'] = 'runtime' if app.runtime else 'app'
app_info['description'] = app.base_data.description
return app_info
def get_history(self, app: FlatpakApplication) -> List[dict]:
return flatpak.get_app_commits_data(app.ref, app.origin)
def install_and_stream(self, app: FlatpakApplication):
return flatpak.install_and_stream(app.base_data.id, app.origin)
class GenericApplicationManager(ApplicationManager):
def __init__(self, managers: List[ApplicationManager]):
self.managers = managers
self.map = {m.get_app_type(): m for m in self.managers}
def search(self, word: str) -> List[Application]:
apps = []
for man in self.managers:
apps.extend(man.search(word))
return apps
def read_installed(self) -> List[Application]:
installed = []
for man in self.managers:
installed.extend(man.read_installed())
return installed
def can_downgrade(self):
return True
def downgrade_app(self, app: Application, root_password: str):
manager = self.map.get(app.__class__)
if manager.can_downgrade():
return manager.downgrade_app(app, root_password)
else:
raise Exception("downgrade is not possible for {}".format(app.__class__.__name__))
def clean_cache_for(self, app: Application):
self.map[app.__class__].clean_cache_for(app)
def update_and_stream(self, app: Application):
return self.map[app.__class__].update_and_stream(app)
def uninstall_and_stream(self, app: Application):
return self.map[app.__class__].uninstall_and_stream(app)
def install_and_stream(self, app: Application):
return self.map[app.__class__].install_and_stream(app)
def get_info(self, app: Application):
return self.map[app.__class__].get_info(app)
def get_history(self, app: Application):
return self.map[app.__class__].get_history(app)
def get_app_type(self):
return None

View File

@@ -1,6 +1,8 @@
from abc import ABC from abc import ABC, abstractmethod
from enum import Enum from enum import Enum
from fpakman.core import resource
class ApplicationStatus(Enum): class ApplicationStatus(Enum):
READY = 1 READY = 1
@@ -26,6 +28,37 @@ class Application(ABC):
self.installed = installed self.installed = installed
self.update = update self.update = update
@abstractmethod
def has_history(self):
pass
@abstractmethod
def has_info(self):
pass
@abstractmethod
def can_be_downgraded(self):
pass
@abstractmethod
def can_be_uninstalled(self):
pass
@abstractmethod
def can_be_installed(self):
pass
@abstractmethod
def get_type(self):
pass
def get_default_logo_path(self):
return resource.get_path('img/logo.svg')
@abstractmethod
def is_library(self):
pass
class FlatpakApplication(Application): class FlatpakApplication(Application):
@@ -40,3 +73,27 @@ class FlatpakApplication(Application):
def is_incomplete(self): def is_incomplete(self):
return self.base_data.description is None and self.base_data.icon_url return self.base_data.description is None and self.base_data.icon_url
def has_history(self):
return True
def has_info(self):
return True
def can_be_downgraded(self):
return not self.runtime
def can_be_uninstalled(self):
return True
def can_be_installed(self):
return True
def get_type(self):
return 'flatpak'
def get_default_logo_path(self):
return resource.get_path('img/flathub.svg')
def is_library(self):
return self.runtime

View File

@@ -1,6 +1,5 @@
manage_window.title=Flatpak Application Manager manage_window.title=Application Manager
manage_window.columns.latest_version=Latest Version manage_window.columns.latest_version=Latest Version
manage_window.columns.installed=Installed
manage_window.columns.update=Upgrade ? manage_window.columns.update=Upgrade ?
manage_window.apps_table.row.actions.info=Information manage_window.apps_table.row.actions.info=Information
manage_window.apps_table.row.actions.history=History manage_window.apps_table.row.actions.history=History
@@ -43,7 +42,7 @@ tray.action.manage=Manage applications
tray.action.exit=Exit tray.action.exit=Exit
tray.action.about=About tray.action.about=About
tray.action.refreshing=Refreshing tray.action.refreshing=Refreshing
notification.new_updates={} updates notification.new_updates=Updates
flatpak.info.arch=arch flatpak.info.arch=arch
flatpak.info.branch=branch flatpak.info.branch=branch
flatpak.info.collection=collection flatpak.info.collection=collection
@@ -71,3 +70,10 @@ yes=yes
no=no no=no
version.updated=updated version.updated=updated
version.outdated=outdated version.outdated=outdated
name=name
version=version
latest_version=latest version
description=description
type=type
installed=installed
others=others

View File

@@ -1,4 +1,4 @@
manage_window.title=Administrador de Aplicativos Flatpak manage_window.title=Administrador de Aplicativos
manage_window.columns.latest_version=Ultima Versión manage_window.columns.latest_version=Ultima Versión
manage_window.columns.update=Actualizar ? manage_window.columns.update=Actualizar ?
manage_window.columns.installed=Instalado manage_window.columns.installed=Instalado
@@ -43,7 +43,7 @@ tray.action.manage=Administrar aplicativos
tray.action.exit=Salir tray.action.exit=Salir
tray.action.about=Sobre tray.action.about=Sobre
tray.action.refreshing=Recargando tray.action.refreshing=Recargando
notification.new_updates=Actualizaciones {} notification.new_updates=Actualizaciones
flatpak.info.arch=arquitectura flatpak.info.arch=arquitectura
flatpak.info.branch=rama flatpak.info.branch=rama
flatpak.info.collection=colección flatpak.info.collection=colección
@@ -71,3 +71,10 @@ yes=sí
no=no no=no
version.updated=actualizada version.updated=actualizada
version.outdated=desactualizada version.outdated=desactualizada
name=nombre
version=versión
latest_version=ultima versión
description=descripción
type=tipo
installed=instalado
others=otros

View File

@@ -1,4 +1,4 @@
manage_window.title=Gerenciador de Aplicativos Flatpak manage_window.title=Gerenciador de Aplicativos
manage_window.columns.latest_version=Última Versão manage_window.columns.latest_version=Última Versão
manage_window.columns.update=Atualizar ? manage_window.columns.update=Atualizar ?
manage_window.columns.installed=Instalado manage_window.columns.installed=Instalado
@@ -43,7 +43,7 @@ tray.action.manage=Gerenciar aplicativos
tray.action.exit=Sair tray.action.exit=Sair
tray.action.about=Sobre tray.action.about=Sobre
tray.action.refreshing=Recarregando tray.action.refreshing=Recarregando
notification.new_updates=Atualizações {} notification.new_updates=Atualizações
flatpak.info.arch=arquitetura flatpak.info.arch=arquitetura
flatpak.info.branch=ramo flatpak.info.branch=ramo
flatpak.info.collection=coleção flatpak.info.collection=coleção
@@ -71,3 +71,10 @@ yes=sim
no=não no=não
version.updated=atualizada version.updated=atualizada
version.outdated=desatualizada version.outdated=desatualizada
name=nome
version=versão
latest_version=última versão
description=descrição
type=tipo
installed=instalado
others=outros

View File

@@ -43,13 +43,12 @@ class AppsTable(QTableWidget):
super(AppsTable, self).__init__() super(AppsTable, self).__init__()
self.setParent(parent) self.setParent(parent)
self.window = parent self.window = parent
self.column_names = [parent.locale_keys[key].capitalize() for key in ['flatpak.info.name', self.column_names = [parent.locale_keys[key].capitalize() for key in ['name',
'flatpak.info.version', 'version',
'manage_window.columns.latest_version', 'latest_version',
'flatpak.info.branch',
'flatpak.info.description', 'flatpak.info.description',
'flatpak.info.origin', 'type',
'manage_window.columns.installed', 'installed',
'manage_window.columns.update']] 'manage_window.columns.update']]
self.setColumnCount(len(self.column_names)) self.setColumnCount(len(self.column_names))
self.setFocusPolicy(Qt.NoFocus) self.setFocusPolicy(Qt.NoFocus)
@@ -59,6 +58,7 @@ class AppsTable(QTableWidget):
self.setHorizontalHeaderLabels(self.column_names) self.setHorizontalHeaderLabels(self.column_names)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.icon_flathub = QIcon(resource.get_path('img/flathub.svg')) self.icon_flathub = QIcon(resource.get_path('img/flathub.svg'))
self.icon_logo = QIcon(resource.get_path('img/logo.svg'))
self.network_man = QNetworkAccessManager() self.network_man = QNetworkAccessManager()
self.network_man.finished.connect(self._load_icon) self.network_man.finished.connect(self._load_icon)
@@ -73,31 +73,36 @@ class AppsTable(QTableWidget):
menu_row = QMenu() menu_row = QMenu()
if app.model.installed: if app.model.installed:
action_info = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.info"])
action_info.setIcon(QIcon(resource.get_path('img/info.svg')))
action_info.triggered.connect(self._get_app_info)
menu_row.addAction(action_info)
action_history = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.history"]) if app.model.has_info():
action_history.setIcon(QIcon(resource.get_path('img/history.svg'))) action_info = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.info"])
action_history.triggered.connect(self._get_app_history) action_info.setIcon(QIcon(resource.get_path('img/info.svg')))
menu_row.addAction(action_history) action_info.triggered.connect(self._get_app_info)
menu_row.addAction(action_info)
action_uninstall = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.uninstall"]) if app.model.has_history():
action_uninstall.setIcon(QIcon(resource.get_path('img/uninstall.svg'))) action_history = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.history"])
action_uninstall.triggered.connect(self._uninstall_app) action_history.setIcon(QIcon(resource.get_path('img/history.svg')))
menu_row.addAction(action_uninstall) action_history.triggered.connect(self._get_app_history)
menu_row.addAction(action_history)
if isinstance(app.model, FlatpakApplication) and not app.model.runtime: # not available for runtimes if app.model.can_be_uninstalled():
action_uninstall = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.uninstall"])
action_uninstall.setIcon(QIcon(resource.get_path('img/uninstall.svg')))
action_uninstall.triggered.connect(self._uninstall_app)
menu_row.addAction(action_uninstall)
if app.model.can_be_downgraded():
action_downgrade = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.downgrade"]) action_downgrade = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.downgrade"])
action_downgrade.triggered.connect(self._downgrade_app) action_downgrade.triggered.connect(self._downgrade_app)
action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg'))) action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
menu_row.addAction(action_downgrade) menu_row.addAction(action_downgrade)
else: else:
action_install = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.install"]) if app.model.can_be_installed():
action_install.setIcon(QIcon(resource.get_path('img/install.svg'))) action_install = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.install"])
action_install.triggered.connect(self._install_app) action_install.setIcon(QIcon(resource.get_path('img/install.svg')))
menu_row.addAction(action_install) action_install.triggered.connect(self._install_app)
menu_row.addAction(action_install)
menu_row.adjustSize() menu_row.adjustSize()
menu_row.popup(QCursor.pos()) menu_row.popup(QCursor.pos())
@@ -108,20 +113,21 @@ class AppsTable(QTableWidget):
self.lock_async_data.acquire() self.lock_async_data.acquire()
if self.window.apps: if self.window.apps:
for idx, app_v in enumerate(self.window.apps):
if app_v.visible and app_v.status == ApplicationViewStatus.LOADING and app_v.model.status == ApplicationStatus.READY:
self.network_man.get(QNetworkRequest(QUrl(app_v.model.base_data.icon_url)))
self.item(idx, 2).setText(app_v.model.base_data.latest_version)
self._set_col_description(self.item(idx, 4), app_v)
visible, ready = 0, 0 visible, ready = 0, 0
for idx, app_v in enumerate(self.window.apps):
for app_v in self.window.apps:
if app_v.visible: if app_v.visible:
visible += 1 visible += 1
if app_v.status == ApplicationViewStatus.READY: if app_v.status == ApplicationViewStatus.LOADING and app_v.model.status == ApplicationStatus.READY:
ready += 1 self.network_man.get(QNetworkRequest(QUrl(app_v.model.base_data.icon_url)))
self.item(idx, 2).setText(app_v.model.base_data.latest_version)
self._set_col_description(self.item(idx, 3), app_v)
app_v.status = ApplicationViewStatus.READY
if app_v.status == ApplicationViewStatus.READY:
ready += 1
if ready == visible: if ready == visible:
self.window.resize_and_center() self.window.resize_and_center()
@@ -185,14 +191,14 @@ class AppsTable(QTableWidget):
col_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) col_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
if not app_v.model.base_data.icon_url: if not app_v.model.base_data.icon_url:
col_name.setIcon(self.icon_flathub) col_name.setIcon(QIcon(app_v.model.get_default_logo_path()))
else: else:
cached_icon = self.icon_cache.get(app_v.model.base_data.icon_url) cached_icon = self.icon_cache.get(app_v.model.base_data.icon_url)
if cached_icon: if cached_icon:
col_name.setIcon(cached_icon) col_name.setIcon(cached_icon)
else: else:
col_name.setIcon(self.icon_flathub) col_name.setIcon(QIcon(app_v.model.get_default_logo_path()))
self.setItem(idx, 0, col_name) self.setItem(idx, 0, col_name)
@@ -209,30 +215,25 @@ class AppsTable(QTableWidget):
if app_v.model.base_data.version and app_v.model.base_data.latest_version and app_v.model.base_data.version < app_v.model.base_data.latest_version: if app_v.model.base_data.version and app_v.model.base_data.latest_version and app_v.model.base_data.version < app_v.model.base_data.latest_version:
col_release.setForeground(QColor('orange')) col_release.setForeground(QColor('orange'))
col_branch = QTableWidgetItem()
col_branch.setText(app_v.model.branch if isinstance(app_v.model, FlatpakApplication) else '')
col_branch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 3, col_branch)
col_description = QTableWidgetItem() col_description = QTableWidgetItem()
col_description.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) col_description.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self._set_col_description(col_description, app_v) self._set_col_description(col_description, app_v)
self.setItem(idx, 4, col_description) self.setItem(idx, 3, col_description)
col_origin = QTableWidgetItem() col_type = QTableWidgetItem()
col_origin.setText(app_v.model.origin if isinstance(app_v.model, FlatpakApplication) else '') col_type.setText(app_v.model.get_type())
col_origin.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) col_type.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 5, col_origin) self.setItem(idx, 4, col_type)
col_installed = QLabel() col_installed = QLabel()
col_installed.setPixmap((QPixmap(resource.get_path('img/{}.svg'.format('checked' if app_v.model.installed else 'red_cross'))))) col_installed.setPixmap((QPixmap(resource.get_path('img/{}.svg'.format('checked' if app_v.model.installed else 'red_cross')))))
col_installed.setAlignment(Qt.AlignCenter) col_installed.setAlignment(Qt.AlignCenter)
self.setCellWidget(idx, 6, col_installed) self.setCellWidget(idx, 5, col_installed)
col_update = UpdateToggleButton(app_v, self.window, self.window.locale_keys, app_v.model.update) if app_v.model.update else None col_update = UpdateToggleButton(app_v, self.window, self.window.locale_keys, app_v.model.update) if app_v.model.update else None
self.setCellWidget(idx, 7, col_update) self.setCellWidget(idx, 6, col_update)
def _set_col_description(self, col: QTableWidgetItem, app_v: ApplicationView): def _set_col_description(self, col: QTableWidgetItem, app_v: ApplicationView):
desc = app_v.get_async_attr('description', strip_html=True) desc = app_v.get_async_attr('description', strip_html=True)

View File

@@ -8,7 +8,7 @@ from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTableWidget, QTableWidgetItem
class HistoryDialog(QDialog): class HistoryDialog(QDialog):
def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict): def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict):
super(HistoryDialog, self).__init__() super(HistoryDialog, self).__init__()
self.setWindowTitle('{} - {} '.format(locale_keys['popup.history.title'], app['model'].base_data.name)) self.setWindowTitle('{} - {} '.format(locale_keys['popup.history.title'], app['model'].base_data.name))
@@ -23,11 +23,11 @@ class HistoryDialog(QDialog):
table_history.verticalHeader().setVisible(False) table_history.verticalHeader().setVisible(False)
table_history.setAlternatingRowColors(True) table_history.setAlternatingRowColors(True)
table_history.setColumnCount(len(app['commits'][0])) table_history.setColumnCount(len(app['history'][0]))
table_history.setRowCount(len(app['commits'])) table_history.setRowCount(len(app['history']))
table_history.setHorizontalHeaderLabels([locale_keys['flatpak.info.' + key].capitalize() for key in sorted(app['commits'][0].keys())]) table_history.setHorizontalHeaderLabels([locale_keys['flatpak.info.' + key].capitalize() for key in sorted(app['history'][0].keys())])
for row, commit in enumerate(app['commits']): for row, commit in enumerate(app['history']):
current_app_commit = app['model'].commit == commit['commit'] current_app_commit = app['model'].commit == commit['commit']

View File

@@ -7,7 +7,7 @@ from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu from PyQt5.QtWidgets import QSystemTrayIcon, QMenu
from fpakman.core import resource, system from fpakman.core import resource, system
from fpakman.core.controller import FlatpakManager from fpakman.core.controller import FlatpakManager, ApplicationManager
from fpakman.core.model import Application from fpakman.core.model import Application
from fpakman.util.cache import Cache from fpakman.util.cache import Cache
from fpakman.view.qt.about import AboutDialog from fpakman.view.qt.about import AboutDialog
@@ -18,7 +18,7 @@ class UpdateCheck(QThread):
signal = pyqtSignal(list) signal = pyqtSignal(list)
def __init__(self, manager: FlatpakManager, check_interval: int, parent=None): def __init__(self, manager: ApplicationManager, check_interval: int, parent=None):
super(UpdateCheck, self).__init__(parent) super(UpdateCheck, self).__init__(parent)
self.check_interval = check_interval self.check_interval = check_interval
self.manager = manager self.manager = manager
@@ -39,7 +39,7 @@ class UpdateCheck(QThread):
class TrayIcon(QSystemTrayIcon): class TrayIcon(QSystemTrayIcon):
def __init__(self, locale_keys: dict, manager: FlatpakManager, icon_cache: Cache, check_interval: int = 60, update_notification: bool = True): def __init__(self, locale_keys: dict, manager: ApplicationManager, icon_cache: Cache, check_interval: int = 60, update_notification: bool = True):
super(TrayIcon, self).__init__() super(TrayIcon, self).__init__()
self.locale_keys = locale_keys self.locale_keys = locale_keys
self.manager = manager self.manager = manager
@@ -86,7 +86,7 @@ class TrayIcon(QSystemTrayIcon):
if update_keys.difference(self.last_updates): if update_keys.difference(self.last_updates):
self.last_updates = update_keys self.last_updates = update_keys
msg = '{}: {}'.format(self.locale_keys['notification.new_updates'].format('Flatpak'), len(updates)) msg = '{}: {}'.format(self.locale_keys['notification.new_updates'], len(updates))
self.setToolTip(msg) self.setToolTip(msg)
if self.update_notification: if self.update_notification:

View File

@@ -4,12 +4,11 @@ from typing import List
from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtCore import QThread, pyqtSignal
from fpakman.core import flatpak from fpakman.core.controller import ApplicationManager
from fpakman.core.controller import FlatpakManager from fpakman.core.model import ApplicationStatus
from fpakman.core.model import ApplicationStatus, FlatpakApplication
from fpakman.util.cache import Cache from fpakman.util.cache import Cache
from fpakman.view.qt import dialog from fpakman.view.qt import dialog
from fpakman.view.qt.view_model import ApplicationView, ApplicationViewStatus from fpakman.view.qt.view_model import ApplicationView
class UpdateSelectedApps(QThread): class UpdateSelectedApps(QThread):
@@ -17,14 +16,15 @@ class UpdateSelectedApps(QThread):
signal_finished = pyqtSignal() signal_finished = pyqtSignal()
signal_output = pyqtSignal(str) signal_output = pyqtSignal(str)
def __init__(self): def __init__(self, manager: ApplicationManager, apps_to_update: List[ApplicationView] = None):
super(UpdateSelectedApps, self).__init__() super(UpdateSelectedApps, self).__init__()
self.refs_to_update = [] self.apps_to_update = apps_to_update
self.manager = manager
def run(self): def run(self):
for app_ref in self.refs_to_update: for app in self.apps_to_update:
for output in flatpak.update_and_stream(app_ref): for output in self.manager.update_and_stream(app.model):
line = output.decode().strip() line = output.decode().strip()
if line: if line:
self.signal_output.emit(line) self.signal_output.emit(line)
@@ -36,7 +36,7 @@ class RefreshApps(QThread):
signal = pyqtSignal(list) signal = pyqtSignal(list)
def __init__(self, manager: FlatpakManager): def __init__(self, manager: ApplicationManager):
super(RefreshApps, self).__init__() super(RefreshApps, self).__init__()
self.manager = manager self.manager = manager
@@ -48,21 +48,21 @@ class UninstallApp(QThread):
signal_finished = pyqtSignal() signal_finished = pyqtSignal()
signal_output = pyqtSignal(str) signal_output = pyqtSignal(str)
def __init__(self, manager: FlatpakManager, icon_cache: Cache, app: ApplicationView = None): def __init__(self, manager: ApplicationManager, icon_cache: Cache, app: ApplicationView = None):
super(UninstallApp, self).__init__() super(UninstallApp, self).__init__()
self.app = app self.app = app
self.manager = manager self.manager = manager
self.icon_cache = icon_cache self.icon_cache = icon_cache
def run(self): def run(self):
if self.app and isinstance(self.app.model, FlatpakApplication): if self.app:
for output in flatpak.uninstall_and_stream(self.app.model.ref): for output in self.manager.uninstall_and_stream(self.app.model):
line = output.decode().strip() line = output.decode().strip()
if line: if line:
self.signal_output.emit(line) self.signal_output.emit(line)
self.icon_cache.delete(self.app.model.base_data.icon_url) self.icon_cache.delete(self.app.model.base_data.icon_url)
self.manager.clean_cache_for(self.app.model.base_data.id) self.manager.clean_cache_for(self.app.model)
self.signal_finished.emit() self.signal_finished.emit()
@@ -70,7 +70,7 @@ class DowngradeApp(QThread):
signal_finished = pyqtSignal() signal_finished = pyqtSignal()
signal_output = pyqtSignal(str) signal_output = pyqtSignal(str)
def __init__(self, manager: FlatpakManager, locale_keys: dict, app: ApplicationView = None): def __init__(self, manager: ApplicationManager, locale_keys: dict, app: ApplicationView = None):
super(DowngradeApp, self).__init__() super(DowngradeApp, self).__init__()
self.manager = manager self.manager = manager
self.app = app self.app = app
@@ -78,7 +78,7 @@ class DowngradeApp(QThread):
self.root_password = None self.root_password = None
def run(self): def run(self):
if self.app and isinstance(self.app.model, FlatpakApplication): if self.app:
stream = self.manager.downgrade_app(self.app.model, self.root_password) stream = self.manager.downgrade_app(self.app.model, self.root_password)
@@ -99,38 +99,35 @@ class DowngradeApp(QThread):
class GetAppInfo(QThread): class GetAppInfo(QThread):
signal_finished = pyqtSignal(dict) signal_finished = pyqtSignal(dict)
def __init__(self, app: ApplicationView = None): def __init__(self, manager: ApplicationManager, app: ApplicationView = None):
super(GetAppInfo, self).__init__() super(GetAppInfo, self).__init__()
self.app = app self.app = app
self.manager = manager
def run(self): def run(self):
if self.app and isinstance(self.app.model, FlatpakApplication): if self.app:
app_info = flatpak.get_app_info_fields(self.app.model.base_data.id, self.app.model.branch) self.signal_finished.emit(self.manager.get_info(self.app.model))
app_info['name'] = self.app.model.base_data.name
app_info['type'] = 'runtime' if self.app.model.runtime else 'app'
app_info['description'] = self.app.model.base_data.description
self.signal_finished.emit(app_info)
self.app = None self.app = None
class GetAppHistory(QThread): class GetAppHistory(QThread):
signal_finished = pyqtSignal(dict) signal_finished = pyqtSignal(dict)
def __init__(self, app: ApplicationView = None): def __init__(self, manager: ApplicationManager, app: ApplicationView = None):
super(GetAppHistory, self).__init__() super(GetAppHistory, self).__init__()
self.app = app self.app = app
self.manager = manager
def run(self): def run(self):
if self.app and isinstance(self.app.model, FlatpakApplication): if self.app:
commits = flatpak.get_app_commits_data(self.app.model.ref, self.app.model.origin) self.signal_finished.emit({'model': self.app.model, 'history': self.manager.get_history(self.app.model)})
self.signal_finished.emit({'model': self.app.model, 'commits': commits})
self.app = None self.app = None
class SearchApps(QThread): class SearchApps(QThread):
signal_finished = pyqtSignal(list) signal_finished = pyqtSignal(list)
def __init__(self, manager: FlatpakManager): def __init__(self, manager: ApplicationManager):
super(SearchApps, self).__init__() super(SearchApps, self).__init__()
self.word = None self.word = None
self.manager = manager self.manager = manager
@@ -150,14 +147,15 @@ class InstallApp(QThread):
signal_finished = pyqtSignal() signal_finished = pyqtSignal()
signal_output = pyqtSignal(str) signal_output = pyqtSignal(str)
def __init__(self, app: ApplicationView = None): def __init__(self, manager: ApplicationManager, app: ApplicationView = None):
super(InstallApp, self).__init__() super(InstallApp, self).__init__()
self.app = app self.app = app
self.manager = manager
def run(self): def run(self):
if self.app and isinstance(self.app.model, FlatpakApplication): if self.app:
for output in flatpak.install_and_stream(self.app.model.base_data.id, self.app.model.origin): for output in self.manager.install_and_stream(self.app.model):
line = output.decode().strip() line = output.decode().strip()
if line: if line:
self.signal_output.emit(line) self.signal_output.emit(line)

View File

@@ -8,11 +8,11 @@ from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \
QSizePolicy, QLabel, QPlainTextEdit, QLineEdit, QProgressBar QSizePolicy, QLabel, QPlainTextEdit, QLineEdit, QProgressBar
from fpakman.core import resource, flatpak from fpakman.core import resource
from fpakman.core.controller import FlatpakManager from fpakman.core.controller import ApplicationManager
from fpakman.core.model import Application, FlatpakApplication from fpakman.core.model import Application
from fpakman.util.cache import Cache from fpakman.util.cache import Cache
from fpakman.view.qt import dialog, common from fpakman.view.qt import common
from fpakman.view.qt.apps_table import AppsTable from fpakman.view.qt.apps_table import AppsTable
from fpakman.view.qt.history import HistoryDialog from fpakman.view.qt.history import HistoryDialog
from fpakman.view.qt.info import InfoDialog from fpakman.view.qt.info import InfoDialog
@@ -27,7 +27,7 @@ DARK_ORANGE = '#FF4500'
class ManageWindow(QWidget): class ManageWindow(QWidget):
__BASE_HEIGHT__ = 400 __BASE_HEIGHT__ = 400
def __init__(self, locale_keys: dict, icon_cache: Cache, manager: FlatpakManager, tray_icon=None): def __init__(self, locale_keys: dict, icon_cache: Cache, manager: ApplicationManager, tray_icon=None):
super(ManageWindow, self).__init__() super(ManageWindow, self).__init__()
self.locale_keys = locale_keys self.locale_keys = locale_keys
self.manager = manager self.manager = manager
@@ -128,7 +128,7 @@ class ManageWindow(QWidget):
self.textarea_output.setVisible(False) self.textarea_output.setVisible(False)
self.textarea_output.setReadOnly(True) self.textarea_output.setReadOnly(True)
self.thread_update = UpdateSelectedApps() self.thread_update = UpdateSelectedApps(self.manager)
self.thread_update.signal_output.connect(self._update_action_output) self.thread_update.signal_output.connect(self._update_action_output)
self.thread_update.signal_finished.connect(self._finish_update_selected) self.thread_update.signal_finished.connect(self._finish_update_selected)
@@ -143,16 +143,16 @@ class ManageWindow(QWidget):
self.thread_downgrade.signal_output.connect(self._update_action_output) self.thread_downgrade.signal_output.connect(self._update_action_output)
self.thread_downgrade.signal_finished.connect(self._finish_downgrade) self.thread_downgrade.signal_finished.connect(self._finish_downgrade)
self.thread_get_info = GetAppInfo() self.thread_get_info = GetAppInfo(self.manager)
self.thread_get_info.signal_finished.connect(self._finish_get_info) self.thread_get_info.signal_finished.connect(self._finish_get_info)
self.thread_get_history = GetAppHistory() self.thread_get_history = GetAppHistory(self.manager)
self.thread_get_history.signal_finished.connect(self._finish_get_history) self.thread_get_history.signal_finished.connect(self._finish_get_history)
self.thread_search = SearchApps(self.manager) self.thread_search = SearchApps(self.manager)
self.thread_search.signal_finished.connect(self._finish_search) self.thread_search.signal_finished.connect(self._finish_search)
self.thread_install = InstallApp() self.thread_install = InstallApp(self.manager)
self.thread_install.signal_output.connect(self._update_action_output) self.thread_install.signal_output.connect(self._update_action_output)
self.thread_install.signal_finished.connect(self._finish_install) self.thread_install.signal_finished.connect(self._finish_install)
@@ -175,9 +175,6 @@ class ManageWindow(QWidget):
self.toolbar_bottom.addWidget(self._new_spacer()) self.toolbar_bottom.addWidget(self._new_spacer())
self.label_flatpak = QLabel(self._get_flatpak_label())
self.toolbar_bottom.addWidget(self.label_flatpak)
self.layout.addWidget(self.toolbar_bottom) self.layout.addWidget(self.toolbar_bottom)
self.centralize() self.centralize()
@@ -204,15 +201,8 @@ class ManageWindow(QWidget):
self._handle_console_option(False) self._handle_console_option(False)
def _check_flatpak_installed(self): def _check_flatpak_installed(self):
common.check_flatpak_installed(self.locale_keys) common.check_flatpak_installed(self.locale_keys)
if self.label_flatpak:
self.label_flatpak.setText(self._get_flatpak_label())
def _get_flatpak_label(self):
return 'flatpak: ' + flatpak.get_version()
def _acquire_lock(self): def _acquire_lock(self):
self.thread_lock.acquire() self.thread_lock.acquire()
@@ -288,7 +278,7 @@ class ManageWindow(QWidget):
show_only_apps = True if only_apps == 2 else False show_only_apps = True if only_apps == 2 else False
for idx, app_v in enumerate(self.apps): for idx, app_v in enumerate(self.apps):
hidden = show_only_apps and isinstance(app_v.model, FlatpakApplication) and app_v.model.runtime hidden = show_only_apps and app_v.model.is_library()
self.table_apps.setRowHidden(idx, hidden) self.table_apps.setRowHidden(idx, hidden)
app_v.visible = not hidden app_v.visible = not hidden
@@ -301,22 +291,22 @@ class ManageWindow(QWidget):
enable_bt_update = False enable_bt_update = False
app_updates, runtime_updates = 0, 0 app_updates, library_updates = 0, 0
for app_v in self.apps: for app_v in self.apps:
if app_v.model.update: if app_v.model.update:
if app_v.model.runtime: if app_v.model.runtime:
runtime_updates += 1 library_updates += 1
else: else:
app_updates += 1 app_updates += 1
total_updates = app_updates + runtime_updates total_updates = app_updates + library_updates
if total_updates > 0: if total_updates > 0:
self.label_updates.setText('{}: {}'.format(self.locale_keys['manage_window.label.updates'], total_updates)) self.label_updates.setText('{}: {}'.format(self.locale_keys['manage_window.label.updates'], total_updates))
self.label_updates.setToolTip('{} {} | {} runtimes'.format(app_updates, self.label_updates.setToolTip('{} {} | {} {}'.format(app_updates,
self.locale_keys[ self.locale_keys['manage_window.checkbox.only_apps'].lower(),
'manage_window.checkbox.only_apps'].lower(), library_updates,
runtime_updates)) self.locale_keys['others'].lower()))
else: else:
self.label_updates.setText('') self.label_updates.setText('')
@@ -340,14 +330,14 @@ class ManageWindow(QWidget):
self.apps = [] self.apps = []
napps = 0 # number of apps (not runtimes) napps = 0 # number of apps (not libraries)
if apps: if apps:
for app in apps: for app in apps:
app_model = ApplicationView(model=app, app_model = ApplicationView(model=app,
visible=(isinstance(app, FlatpakApplication) and not app.runtime) or not self.checkbox_only_apps.isChecked()) visible=(not app.is_library()) or not self.checkbox_only_apps.isChecked())
napps += 1 if isinstance(app, FlatpakApplication) and not app.runtime else 0 napps += 1 if not app.is_library() else 0
self.apps.append(app_model) self.apps.append(app_model)
if napps == 0: if napps == 0:
@@ -375,13 +365,13 @@ class ManageWindow(QWidget):
if self._acquire_lock(): if self._acquire_lock():
if self.apps: if self.apps:
to_update = [app_v.model.ref for app_v in self.apps if app_v.visible and app_v.update_checked and isinstance(app_v.model, FlatpakApplication)] to_update = [app_v for app_v in self.apps if app_v.visible and app_v.update_checked]
if to_update: if to_update:
self._handle_console_option(True) self._handle_console_option(True)
self._begin_action(self.locale_keys['manage_window.status.upgrading']) self._begin_action(self.locale_keys['manage_window.status.upgrading'])
self.thread_update.refs_to_update = to_update self.thread_update.apps_to_update = to_update
self.thread_update.start() self.thread_update.start()
def _finish_update_selected(self): def _finish_update_selected(self):