Uninstall selected app

This commit is contained in:
Vinícius Moreira
2019-06-25 11:48:28 -03:00
committed by GitHub
parent e054186d69
commit 9d6187b0a0
11 changed files with 330 additions and 127 deletions

View File

@@ -4,7 +4,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.2.2] ## [0.3.0]
### Features
- Allows app uninstall by right clicking it.
### Improvements ### Improvements
- Adding tooltips to toolbar buttons - Adding tooltips to toolbar buttons
- "Update ?" column renamed to "Upgrade ?" - "Update ?" column renamed to "Upgrade ?"

View File

@@ -1 +1 @@
__version__ = '0.2.2' __version__ = '0.3.0'

View File

@@ -20,3 +20,6 @@ class FlatpakController:
def get_version(self) -> str: def get_version(self) -> str:
return self.model.get_version() return self.model.get_version()
def uninstall(self, app_ref: str):
return self.model.remove_app(app_ref)

View File

@@ -81,5 +81,14 @@ def update_and_stream(app_ref: str):
return system.stream_cmd(['flatpak', 'update', '-y', app_ref]) return system.stream_cmd(['flatpak', 'update', '-y', app_ref])
def uninstall_and_stream(app_ref: str):
"""
Removes the app by its reference
:param app_ref:
:return:
"""
return system.stream_cmd(['flatpak', 'uninstall', app_ref, '-y'])
def list_updates_as_str(): def list_updates_as_str():
return system.run_cmd('flatpak update', ignore_return_code=True) return system.run_cmd('flatpak update', ignore_return_code=True)

View File

@@ -91,6 +91,12 @@ class FlatpakManager:
return [] return []
def _find_by_ref(self, ref: str):
package_found = [app for app in self.apps if app['ref'] == ref]
if package_found:
return package_found[0]
def update_app(self, ref: str): def update_app(self, ref: str):
""" """
@@ -100,9 +106,19 @@ class FlatpakManager:
if self.apps: if self.apps:
package_found = [app for app in self.apps if app['ref'] == ref] app_found = self._find_by_ref(ref)
if package_found: if app_found:
return flatpak.update_and_stream(ref) return flatpak.update_and_stream(ref)
return None def remove_app(self, ref: str):
"""
:param ref:
:return: the uninstall command stream
"""
if self.apps:
app_found = self._find_by_ref(ref)
if app_found:
return flatpak.uninstall_and_stream(ref)

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<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"
height="36.000004pt"
viewBox="-40 0 36.000001 36.000114"
width="36pt"
version="1.1"
id="svg72"
sodipodi:docname="delete.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata78">
<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></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs76" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1019"
id="namedview74"
showgrid="false"
showborder="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="5.7611241"
inkscape:cx="58.614066"
inkscape:cy="3.8950274"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg72" />
<g
id="g84"
transform="matrix(0.10380557,0,0,0.08430914,-35.847764,0)">
<path
inkscape:connector-curvature="0"
id="path64"
d="m 192.40098,154.70443 c -5.52344,0 -10,4.47657 -10,10 v 189 c 0,5.51954 4.47656,10 10,10 5.52343,0 10,-4.48046 10,-10 v -189 c 0,-5.52343 -4.47657,-10 -10,-10 z m 0,0" />
<path
inkscape:connector-curvature="0"
id="path66"
d="m 74.400978,154.70443 c -5.52344,0 -10,4.47657 -10,10 v 189 c 0,5.51954 4.47656,10 10,10 5.52344,0 10,-4.48046 10,-10 v -189 c 0,-5.52343 -4.47656,-10 -10,-10 z m 0,0" />
<path
inkscape:connector-curvature="0"
id="path68"
d="m -11.599024,127.1224 v 246.37891 c 0,14.5625 5.3398433,28.23828 14.6679683,38.05078 9.2851557,9.83984 22.2070317,15.42578 35.7304687,15.44922 H 228.00254 c 13.52734,-0.0234 26.44922,-5.60938 35.73047,-15.44922 9.32812,-9.8125 14.66797,-23.48828 14.66797,-38.05078 V 127.1224 C 296.94395,122.20053 308.95957,104.28647 306.4791,85.259126 303.99473,66.235689 287.7877,52.00522 268.6002,52.001314 h -51.19922 v -12.5 c 0.0586,-10.511719 -4.09766,-20.605469 -11.53907,-28.03125 -7.4414,-7.4218751 -17.55078,-11.55468758 -28.0625,-11.46875008 H 89.002538 C 78.490818,-0.08462358 68.381448,4.0481889 60.940038,11.470064 53.498632,18.895845 49.342382,28.989595 49.400976,39.501314 v 12.5 H -1.7982427 c -19.1875003,0.0039 -35.3945313,14.234375 -37.8789073,33.257812 -2.480468,19.027344 9.535157,36.941404 28.078126,41.863274 z M 228.00254,407.00131 H 38.799413 c -17.097656,0 -30.3984367,-14.6875 -30.3984367,-33.5 v -245.5 H 258.40098 v 245.5 c 0,18.8125 -13.30078,33.5 -30.39844,33.5 z M 69.400978,39.501314 c -0.0664,-5.207031 1.98047,-10.21875 5.67578,-13.894531 3.69141,-3.675781 8.71484,-5.695313 13.92578,-5.605469 h 88.796872 c 5.21094,-0.08984 10.23438,1.929688 13.92579,5.605469 3.69531,3.671875 5.74218,8.6875 5.67578,13.894531 v 12.5 H 69.400978 Z m -71.1992207,32.5 H 268.6002 c 9.9414,0 18,8.058594 18,18 0,9.941406 -8.0586,17.999996 -18,17.999996 H -1.7982427 c -9.9414073,0 -18.0000003,-8.05859 -18.0000003,-17.999996 0,-9.941406 8.058593,-18 18.0000003,-18 z m 0,0" />
<path
inkscape:connector-curvature="0"
id="path70"
d="m 133.40098,154.70443 c -5.52344,0 -10,4.47657 -10,10 v 189 c 0,5.51954 4.47656,10 10,10 5.52343,0 10,-4.48046 10,-10 v -189 c 0,-5.52343 -4.47657,-10 -10,-10 z m 0,0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -7,10 +7,14 @@ manage_window.columns.arch=Arch
manage_window.columns.ref=Ref manage_window.columns.ref=Ref
manage_window.columns.origin=Origin manage_window.columns.origin=Origin
manage_window.columns.update=Upgrade ? manage_window.columns.update=Upgrade ?
manage_window.apps_table.row.actions.uninstall=Uninstall
manage_window.apps_table.row.actions.uninstall.popup.title=Uninstall
manage_window.apps_table.row.actions.uninstall.popup.body=Remove {} ?
manage_window.checkbox.only_apps=Apps manage_window.checkbox.only_apps=Apps
manage_window.label.updates=Updates manage_window.label.updates=Updates
manage_window.status.refreshing=Refreshing manage_window.status.refreshing=Refreshing
manage_window.status.updating=Updating manage_window.status.updating=Updating
manage_window.status.uninstalling=Uninstalling
manage_window.bt.refresh.tooltip=Reload the data about installed applications manage_window.bt.refresh.tooltip=Reload the data about installed applications
manage_window.bt.upgrade.tooltip=Upgrade all selected applications manage_window.bt.upgrade.tooltip=Upgrade all selected applications
popup.flatpak_not_installed.title=Error popup.flatpak_not_installed.title=Error

View File

@@ -7,10 +7,14 @@ manage_window.columns.arch=Arch
manage_window.columns.ref=Ref manage_window.columns.ref=Ref
manage_window.columns.origin=Origen manage_window.columns.origin=Origen
manage_window.columns.update=¿Actualizar? manage_window.columns.update=¿Actualizar?
manage_window.apps_table.row.actions.uninstall=Desinstalar
manage_window.apps_table.row.actions.uninstall.popup.title=Desinstalación
manage_window.apps_table.row.actions.uninstall.popup.body=¿Eliminar {}?
manage_window.checkbox.only_apps=Apps manage_window.checkbox.only_apps=Apps
manage_window.label.updates=Actualizaciones manage_window.label.updates=Actualizaciones
manage_window.status.refreshing=Recargando manage_window.status.refreshing=Recargando
manage_window.status.updating=Actualizando manage_window.status.updating=Actualizando
manage_window.status.uninstalling=Desinstalando
manage_window.bt.refresh.tooltip=Recarga los datos sobre los aplicativos instalados manage_window.bt.refresh.tooltip=Recarga los datos sobre los aplicativos instalados
manage_window.bt.upgrade.tooltip=Actualiza todos los aplicativos seleccionados manage_window.bt.upgrade.tooltip=Actualiza todos los aplicativos seleccionados
popup.flatpak_not_installed.title=Error popup.flatpak_not_installed.title=Error

View File

@@ -7,10 +7,14 @@ manage_window.columns.arch=Arch
manage_window.columns.ref=Ref manage_window.columns.ref=Ref
manage_window.columns.origin=Origem manage_window.columns.origin=Origem
manage_window.columns.update=Atualizar ? manage_window.columns.update=Atualizar ?
manage_window.apps_table.row.actions.uninstall=Desinstalar
manage_window.apps_table.row.actions.uninstall.popup.title=Desinstalação
manage_window.apps_table.row.actions.uninstall.popup.body=Rmover {}?
manage_window.checkbox.only_apps=Apps manage_window.checkbox.only_apps=Apps
manage_window.label.updates=Atualizações manage_window.label.updates=Atualizações
manage_window.status.refreshing=Recarregando manage_window.status.refreshing=Recarregando
manage_window.status.updating=Atualizando manage_window.status.updating=Atualizando
manage_window.status.uninstalling=Desinstalando
manage_window.bt.refresh.tooltip=Recarrega os dados sobre os aplicativos instalados manage_window.bt.refresh.tooltip=Recarrega os dados sobre os aplicativos instalados
manage_window.bt.upgrade.tooltip=Atualiza todos os aplicativos selecionados manage_window.bt.upgrade.tooltip=Atualiza todos os aplicativos selecionados
popup.flatpak_not_installed.title=Erro popup.flatpak_not_installed.title=Erro

View File

@@ -0,0 +1,154 @@
from typing import List
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QPixmap, QIcon, QColor, QCursor
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \
QMessageBox, QHeaderView
from fpakman.core import resource
from fpakman.core.controller import FlatpakController
class UpdateToggleButton(QToolButton):
def __init__(self, model: dict, root: QWidget, checked: bool = True):
super(UpdateToggleButton, self).__init__()
self.model = model
self.root = root
self.setCheckable(True)
self.clicked.connect(self.change_state)
self.icon_on = QIcon(resource.get_path('img/toggle_on.svg'))
self.icon_off = QIcon(resource.get_path('img/toggle_off.svg'))
self.setIcon(self.icon_on)
self.setStyleSheet('border: 0px;')
if not checked:
self.click()
def change_state(self, not_checked: bool):
self.model['update_checked'] = not not_checked
self.setIcon(self.icon_on if not not_checked else self.icon_off)
self.root.change_update_state()
class AppsTable(QTableWidget):
def __init__(self, parent: QWidget, controller: FlatpakController, columns: List[str]):
super(AppsTable, self).__init__()
self.parent = parent
self.controller = controller
self.columns = columns
self.setColumnCount(len(columns))
self.setFocusPolicy(Qt.NoFocus)
self.setShowGrid(False)
self.verticalHeader().setVisible(False)
self.setSelectionBehavior(QTableView.SelectRows)
self.setHorizontalHeaderLabels(columns)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.icon_flathub = QIcon(resource.get_path('img/flathub_45.svg'))
self.icon_uninstall = QIcon(resource.get_path('img/uninstall.svg'))
self.network_man = QNetworkAccessManager()
self.network_man.finished.connect(self._load_icon)
self.icon_cache = {}
def contextMenuEvent(self, QContextMenuEvent): # selected row right click event
menu_row = QMenu()
action_uninstall = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.uninstall"])
action_uninstall.setIcon(self.icon_uninstall)
action_uninstall.triggered.connect(self._uninstall_app)
menu_row.addAction(action_uninstall)
menu_row.adjustSize()
menu_row.popup(QCursor.pos())
menu_row.exec_()
def _uninstall_app(self):
selected_app = self.parent.apps[self.currentRow()]
confirmation = QMessageBox.question(self, self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.title'],
self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.body'].format(selected_app['model']['name']),
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if confirmation == QMessageBox.Yes:
self.parent.uninstall_app(selected_app['model']['ref'])
def _load_icon(self, http_response):
icon_url = http_response.url().toString()
pixmap = QPixmap()
pixmap.loadFromData(http_response.readAll())
icon = QIcon(pixmap)
self.icon_cache[icon_url] = icon
for idx, app in enumerate(self.parent.apps):
if app['model']['icon'] == icon_url:
self.item(idx, 0).setIcon(icon)
self.parent.resize_and_center()
break
def update_apps(self, apps: List[dict]):
self.setEnabled(True)
self.setRowCount(len(apps) if apps else 0)
if apps:
for idx, app in enumerate(apps):
col_name = QTableWidgetItem()
col_name.setText(app['model']['name'])
col_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
if not app['model']['icon']:
col_name.setIcon(self.icon_flathub)
else:
cached_icon = self.icon_cache.get(app['model']['icon'])
if cached_icon:
col_name.setIcon(cached_icon)
else:
col_name.setIcon(self.icon_flathub)
self.network_man.get(QNetworkRequest(QUrl(app['model']['icon'])))
self.setItem(idx, 0, col_name)
col_version = QTableWidgetItem()
col_version.setText(app['model']['version'])
col_version.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 1, col_version)
col_release = QTableWidgetItem()
col_release.setText(app['model']['latest_version'])
col_release.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 2, col_release)
if app['model']['update']:
col_release.setForeground(QColor('orange'))
col_branch = QTableWidgetItem()
col_branch.setText(app['model']['branch'])
col_branch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 3, col_branch)
col_arch = QTableWidgetItem()
col_arch.setText(app['model']['arch'])
col_arch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 4, col_arch)
col_package = QTableWidgetItem()
col_package.setText(app['model']['ref'])
col_package.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 5, col_package)
col_origin = QTableWidgetItem()
col_origin.setText(app['model']['origin'])
col_origin.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.setItem(idx, 6, col_origin)
col_update = UpdateToggleButton(app['model'], self.parent, app['model']['update']) if app['model']['update'] else None
self.setCellWidget(idx, 7, col_update)
def change_headers_policy(self, policy: QHeaderView = QHeaderView.ResizeToContents):
header_horizontal = self.horizontalHeader()
for i in range(0, len(self.columns)):
header_horizontal.setSectionResizeMode(i, policy)

View File

@@ -3,38 +3,15 @@ from functools import reduce
from threading import Lock from threading import Lock
from typing import List from typing import List
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QUrl, QEvent from PyQt5.QtCore import QThread, pyqtSignal, QEvent
from PyQt5.QtGui import QIcon, QColor, QPixmap, QWindowStateChangeEvent from PyQt5.QtGui import QIcon, QWindowStateChangeEvent
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QTableWidget, \
QTableWidgetItem, QTableView, QCheckBox, QHeaderView, QToolButton, QToolBar, \
QSizePolicy, QLabel, QMessageBox, QPlainTextEdit QSizePolicy, QLabel, QMessageBox, QPlainTextEdit
from fpakman import __version__ from fpakman import __version__
from fpakman.core import resource from fpakman.core import resource
from fpakman.core.controller import FlatpakController from fpakman.core.controller import FlatpakController
from fpakman.view.qt.apps_table import AppsTable
class UpdateToggleButton(QToolButton):
def __init__(self, model: dict, root: QWidget, checked: bool = True):
super(UpdateToggleButton, self).__init__()
self.model = model
self.root = root
self.setCheckable(True)
self.clicked.connect(self.change_state)
self.icon_on = QIcon(resource.get_path('img/toggle_on.svg'))
self.icon_off = QIcon(resource.get_path('img/toggle_off.svg'))
self.setIcon(self.icon_on)
self.setStyleSheet('border: 0px;')
if not checked:
self.click()
def change_state(self, not_checked: bool):
self.model['update_checked'] = not not_checked
self.setIcon(self.icon_on if not not_checked else self.icon_off)
self.root.change_update_state()
class ManageWindow(QWidget): class ManageWindow(QWidget):
@@ -53,16 +30,12 @@ class ManageWindow(QWidget):
locale_keys['manage_window.columns.origin'], locale_keys['manage_window.columns.origin'],
locale_keys['manage_window.columns.update']] locale_keys['manage_window.columns.update']]
self.controller = controller self.controller = controller
self.icon_cache = {}
self.tray_icon = tray_icon self.tray_icon = tray_icon
self.thread_lock = Lock() self.thread_lock = Lock()
self.working = False # restrict the number of threaded actions self.working = False # restrict the number of threaded actions
self.apps = [] self.apps = []
self.label_flatpak = None self.label_flatpak = None
self.network_man = QNetworkAccessManager()
self.network_man.finished.connect(self._load_icon)
self.icon_flathub = QIcon(resource.get_path('img/flathub_45.svg')) self.icon_flathub = QIcon(resource.get_path('img/flathub_45.svg'))
self._check_flatpak_installed() self._check_flatpak_installed()
self.resize(ManageWindow.__BASE_HEIGHT__, ManageWindow.__BASE_HEIGHT__) self.resize(ManageWindow.__BASE_HEIGHT__, ManageWindow.__BASE_HEIGHT__)
@@ -108,16 +81,8 @@ class ManageWindow(QWidget):
self.layout.addWidget(toolbar) self.layout.addWidget(toolbar)
self.table_apps = QTableWidget() self.table_apps = AppsTable(self, self.controller, self.column_names)
self.table_apps.setColumnCount(len(self.column_names)) self.table_apps.change_headers_policy()
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(self.column_names)
self.table_apps.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self._change_table_headers_policy()
self.layout.addWidget(self.table_apps) self.layout.addWidget(self.table_apps)
@@ -135,6 +100,10 @@ class ManageWindow(QWidget):
self.thread_refresh = RefreshApps(self.controller) self.thread_refresh = RefreshApps(self.controller)
self.thread_refresh.signal.connect(self._finish_refresh) self.thread_refresh.signal.connect(self._finish_refresh)
self.thread_uninstall = UninstallApp(self.controller)
self.thread_uninstall.signal_output.connect(self._update_action_output)
self.thread_uninstall.signal_finished.connect(self._finish_uninstall)
self.toolbar_bottom = QToolBar() self.toolbar_bottom = QToolBar()
self.label_updates = QLabel('') self.label_updates = QLabel('')
self.toolbar_bottom.addWidget(self.label_updates) self.toolbar_bottom.addWidget(self.label_updates)
@@ -148,15 +117,11 @@ class ManageWindow(QWidget):
self.centralize() self.centralize()
def _change_table_headers_policy(self, policy: QHeaderView = QHeaderView.ResizeToContents):
header_horizontal = self.table_apps.horizontalHeader()
for i in range(0, len(self.column_names)):
header_horizontal.setSectionResizeMode(i, policy)
def changeEvent(self, e: QEvent): def changeEvent(self, e: QEvent):
if isinstance(e, QWindowStateChangeEvent): if isinstance(e, QWindowStateChangeEvent):
self._change_table_headers_policy(QHeaderView.Stretch if self.isMaximized() else QHeaderView.ResizeToContents) policy = QHeaderView.Stretch if self.isMaximized() else QHeaderView.ResizeToContents
self.table_apps.adjust_header_policy(policy)
def closeEvent(self, event): def closeEvent(self, event):
@@ -164,19 +129,6 @@ class ManageWindow(QWidget):
event.ignore() event.ignore()
self.hide() self.hide()
def _load_icon(self, http_response):
icon_url = http_response.url().toString()
pixmap = QPixmap()
pixmap.loadFromData(http_response.readAll())
icon = QIcon(pixmap)
self.icon_cache[icon_url] = icon
for idx, app in enumerate(self.apps):
if app['model']['icon'] == icon_url:
self.table_apps.item(idx, 0).setIcon(icon)
self.resize_and_center()
break
def _check_flatpak_installed(self): def _check_flatpak_installed(self):
if not self.controller.check_installed(): if not self.controller.check_installed():
@@ -231,6 +183,22 @@ class ManageWindow(QWidget):
self.finish_action() self.finish_action()
self._release_lock() self._release_lock()
def uninstall_app(self, app_ref: str):
self._check_flatpak_installed()
if self._acquire_lock():
self.textarea_output.clear()
self.textarea_output.setVisible(True)
self._begin_action(self.locale_keys['manage_window.status.uninstalling'] + '...')
self.thread_uninstall.app_ref = app_ref
self.thread_uninstall.start()
def _finish_uninstall(self):
self.finish_action()
self._release_lock()
self.refresh(clear_output=False)
def filter_only_apps(self, only_apps: int): def filter_only_apps(self, only_apps: int):
if self.apps: if self.apps:
@@ -242,8 +210,8 @@ class ManageWindow(QWidget):
app['visible'] = not hidden app['visible'] = not hidden
self.change_update_state() self.change_update_state()
self._change_table_headers_policy(QHeaderView.Stretch) self.table_apps.change_headers_policy(QHeaderView.Stretch)
self._change_table_headers_policy() self.table_apps.change_headers_policy()
self.resize_and_center() self.resize_and_center()
def change_update_state(self): def change_update_state(self):
@@ -284,73 +252,16 @@ class ManageWindow(QWidget):
def update_apps(self, apps: List[dict]): def update_apps(self, apps: List[dict]):
self._check_flatpak_installed() self._check_flatpak_installed()
self.table_apps.setEnabled(True)
self.apps = [] self.apps = []
self.table_apps.setRowCount(len(apps) if apps else 0)
if apps: if apps:
for idx, app in enumerate(apps): for app in apps:
col_name = QTableWidgetItem()
col_name.setText(app['name'])
col_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
if not app['icon']:
col_name.setIcon(self.icon_flathub)
else:
cached_icon = self.icon_cache.get(app['icon'])
if cached_icon:
col_name.setIcon(cached_icon)
else:
col_name.setIcon(self.icon_flathub)
self.network_man.get(QNetworkRequest(QUrl(app['icon'])))
self.table_apps.setItem(idx, 0, col_name)
col_version = QTableWidgetItem()
col_version.setText(app['version'])
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, 3, col_branch)
col_arch = QTableWidgetItem()
col_arch.setText(app['arch'])
col_arch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
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, 5, col_package)
col_origin = QTableWidgetItem()
col_origin.setText(app['origin'])
col_origin.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
self.table_apps.setItem(idx, 6, col_origin)
app_model = {'model': app, app_model = {'model': app,
'update_checked': app['update'], 'update_checked': app['update'],
'visible': not app['runtime'] or not self.checkbox_only_apps.isChecked()} 'visible': not app['runtime'] or not self.checkbox_only_apps.isChecked()}
col_update = UpdateToggleButton(app_model, self, app['update']) if app['update'] else None
self.table_apps.setCellWidget(idx, 7, col_update)
self.apps.append(app_model) self.apps.append(app_model)
self.table_apps.update_apps(self.apps)
self.change_update_state() self.change_update_state()
self.filter_only_apps(2 if self.checkbox_only_apps.isChecked() else 0) self.filter_only_apps(2 if self.checkbox_only_apps.isChecked() else 0)
self.resize_and_center() self.resize_and_center()
@@ -431,3 +342,22 @@ class RefreshApps(QThread):
def run(self): def run(self):
self.apps = self.controller.refresh() self.apps = self.controller.refresh()
self.signal.emit() self.signal.emit()
class UninstallApp(QThread):
signal_finished = pyqtSignal()
signal_output = pyqtSignal(str)
def __init__(self, controller: FlatpakController):
super(UninstallApp, self).__init__()
self.controller = controller
self.app_ref = None
def run(self):
if self.app_ref:
for output in self.controller.uninstall(self.app_ref):
line = output.decode().strip()
if line:
self.signal_output.emit(line)
self.signal_finished.emit()