Retrieving app information and history

This commit is contained in:
Vinícius Moreira
2019-06-26 15:52:26 -03:00
committed by GitHub
parent f9f47d1429
commit c2e59ba757
12 changed files with 694 additions and 69 deletions

View File

@@ -6,6 +6,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## [0.3.0] ## [0.3.0]
### Features ### Features
- Allows to retrieve app information and history by right clicking it.
- Allows app uninstall and downgrade by right clicking it. - Allows app uninstall and downgrade by right clicking it.
### Improvements ### Improvements

View File

@@ -4,6 +4,8 @@ from typing import List
from fpakman.core import system from fpakman.core import system
BASE_CMD = 'flatpak'
def app_str_to_json(line: str, version: str) -> dict: def app_str_to_json(line: str, version: str) -> dict:
@@ -39,21 +41,23 @@ def app_str_to_json(line: str, version: str) -> dict:
return app return app
def get_app_info_fields(app_id: str, branch: str, fields: List[str], check_runtime: bool = False): def get_app_info_fields(app_id: str, branch: str, fields: List[str] = [], check_runtime: bool = False):
info = re.findall(r'\w+:\s.+', get_app_info(app_id, branch)) info = re.findall(r'\w+:\s.+', get_app_info(app_id, branch))
data = {} data = {}
fields_to_retrieve = len(fields) + (1 if check_runtime and 'ref' not in fields else 0) fields_to_retrieve = len(fields) + (1 if check_runtime and 'ref' not in fields else 0)
for field in info: for field in info:
if fields_to_retrieve == 0: if fields and fields_to_retrieve == 0:
break break
field_val = field.split(':') field_val = field.split(':')
field_name = field_val[0].lower() field_name = field_val[0].lower()
if field_name in fields or (check_runtime and field_name == 'ref'): if not fields or field_name in fields or (check_runtime and field_name == 'ref'):
data[field_name] = field_val[1].strip() data[field_name] = field_val[1].strip()
if fields:
fields_to_retrieve -= 1 fields_to_retrieve -= 1
if check_runtime and field_name == 'ref': if check_runtime and field_name == 'ref':
@@ -63,16 +67,16 @@ def get_app_info_fields(app_id: str, branch: str, fields: List[str], check_runti
def get_version(): def get_version():
res = system.run_cmd('flatpak --version') res = system.run_cmd('{} --version'.format(BASE_CMD))
return res.split(' ')[1].strip() if res else None return res.split(' ')[1].strip() if res else None
def get_app_info(app_id: str, branch: str): def get_app_info(app_id: str, branch: str):
return system.run_cmd('flatpak info {} {}'.format(app_id, branch)) return system.run_cmd('{} info {} {}'.format(BASE_CMD, app_id, branch))
def list_installed() -> List[dict]: def list_installed() -> List[dict]:
apps_str = system.run_cmd('flatpak list') apps_str = system.run_cmd('{} list'.format(BASE_CMD))
if apps_str: if apps_str:
version = get_version() version = get_version()
@@ -83,7 +87,7 @@ def list_installed() -> List[dict]:
def update(app_ref: str) -> bool: def update(app_ref: str) -> bool:
return bool(system.run_cmd('flatpak update -y ' + app_ref)) return bool(system.run_cmd('{} update -y {}'.format(BASE_CMD, app_ref)))
def update_and_stream(app_ref: str): def update_and_stream(app_ref: str):
@@ -92,7 +96,7 @@ def update_and_stream(app_ref: str):
:param app_ref: :param app_ref:
:return: :return:
""" """
return system.stream_cmd(['flatpak', 'update', '-y', app_ref]) return system.stream_cmd([BASE_CMD, 'update', '-y', app_ref])
def uninstall_and_stream(app_ref: str): def uninstall_and_stream(app_ref: str):
@@ -101,11 +105,11 @@ def uninstall_and_stream(app_ref: str):
:param app_ref: :param app_ref:
:return: :return:
""" """
return system.stream_cmd(['flatpak', 'uninstall', app_ref, '-y']) return system.stream_cmd([BASE_CMD, '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('{} update'.format(BASE_CMD), ignore_return_code=True)
def downgrade_and_stream(app_ref: str, commit: str, root_password: str): def downgrade_and_stream(app_ref: str, commit: str, root_password: str):
@@ -114,12 +118,31 @@ def downgrade_and_stream(app_ref: str, commit: str, root_password: str):
if root_password is not None: if root_password is not None:
downgrade_cmd.extend(['sudo', '-S']) downgrade_cmd.extend(['sudo', '-S'])
pwdin = subprocess.Popen(['echo', root_password], stdout=subprocess.PIPE).stdout pwdin = system.stream_cmd(['echo', root_password])
downgrade_cmd.extend(['flatpak', 'update', '--commit={}'.format(commit), app_ref, '-y']) downgrade_cmd.extend([BASE_CMD, 'update', '--commit={}'.format(commit), app_ref, '-y'])
return subprocess.Popen(downgrade_cmd, stdin=pwdin, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout return subprocess.Popen(downgrade_cmd, stdin=pwdin, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout
def get_app_commits(app_ref: str, origin: str) -> List[str]: def get_app_commits(app_ref: str, origin: str) -> List[str]:
log = system.run_cmd('flatpak remote-info --log {} {}'.format(origin, app_ref)) log = system.run_cmd('{} remote-info --log {} {}'.format(BASE_CMD, origin, app_ref))
return re.findall(r'Commit+:\s(.+)', log) return re.findall(r'Commit+:\s(.+)', log)
def get_app_commits_data(app_ref: str, origin: str) -> List[dict]:
log = system.run_cmd('{} remote-info --log {} {}'.format(BASE_CMD, origin, app_ref))
res = re.findall(r'(Commit|Subject|Date):\s(.+)', log)
commits = []
commit = {}
for idx, data in enumerate(res):
commit[data[0].strip().lower()] = data[1].strip()
if (idx + 1) % 3 == 0:
commits.append(commit)
commit = {}
return commits

View File

@@ -3,9 +3,9 @@ from typing import List
def run_cmd(cmd: str, expected_code: int = 0, ignore_return_code: bool = False) -> str: def run_cmd(cmd: str, expected_code: int = 0, ignore_return_code: bool = False) -> str:
res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE) res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, env={'LANG': 'en'})
return res.stdout.decode() if ignore_return_code or res.returncode == expected_code else None return res.stdout.decode() if ignore_return_code or res.returncode == expected_code else None
def stream_cmd(cmd: List[str]): def stream_cmd(cmd: List[str]):
return subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout return subprocess.Popen(cmd, stdout=subprocess.PIPE, env={'LANG': 'en'}).stdout

218
fpakman/resources/img/history.svg Executable file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

154
fpakman/resources/img/info.svg Executable file
View File

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<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:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
width="47.999996"
height="48.000004"
viewBox="0 0 47.999997 48.000005"
xml:space="preserve"
sodipodi:docname="info.svg"
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
id="metadata128"><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="defs126"><linearGradient
inkscape:collect="always"
id="linearGradient153"><stop
style="stop-color:#0000ff;stop-opacity:1;"
offset="0"
id="stop149" /><stop
style="stop-color:#0000ff;stop-opacity:0;"
offset="1"
id="stop151" /></linearGradient><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient153"
id="linearGradient155"
x1="-180.77992"
y1="-30.518711"
x2="337.13013"
y2="868.49902"
gradientUnits="userSpaceOnUse" /><linearGradient
inkscape:collect="always"
xlink:href="#linearGradient153"
id="linearGradient157"
gradientUnits="userSpaceOnUse"
x1="-180.77992"
y1="-30.518711"
x2="337.13013"
y2="868.49902" /></defs><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="739"
id="namedview124"
showgrid="false"
showborder="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="1.8698707"
inkscape:cx="239.58875"
inkscape:cy="26.740828"
inkscape:window-x="0"
inkscape:window-y="260"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g93"
transform="translate(0,-390.534)">
</g>
<g
id="g95"
transform="translate(0,-390.534)">
</g>
<g
id="g97"
transform="translate(0,-390.534)">
</g>
<g
id="g99"
transform="translate(0,-390.534)">
</g>
<g
id="g101"
transform="translate(0,-390.534)">
</g>
<g
id="g103"
transform="translate(0,-390.534)">
</g>
<g
id="g105"
transform="translate(0,-390.534)">
</g>
<g
id="g107"
transform="translate(0,-390.534)">
</g>
<g
id="g109"
transform="translate(0,-390.534)">
</g>
<g
id="g111"
transform="translate(0,-390.534)">
</g>
<g
id="g113"
transform="translate(0,-390.534)">
</g>
<g
id="g115"
transform="translate(0,-390.534)">
</g>
<g
id="g117"
transform="translate(0,-390.534)">
</g>
<g
id="g119"
transform="translate(0,-390.534)">
</g>
<g
id="g121"
transform="translate(0,-390.534)">
</g>
<g
id="g96"><g
style="fill:url(#linearGradient155);fill-opacity:1"
transform="scale(0.10945609,0.1094556)"
id="g91">
<path
style="fill:url(#linearGradient157);fill-opacity:1"
inkscape:connector-curvature="0"
id="path89"
d="M 409.133,109.203 C 389.525,75.611 362.928,49.014 329.335,29.407 295.736,9.801 259.058,0 219.273,0 179.492,0 142.803,9.801 109.21,29.407 75.615,49.011 49.018,75.608 29.41,109.203 9.801,142.8 0,179.489 0,219.267 c 0,39.78 9.804,76.463 29.407,110.062 19.607,33.592 46.204,60.189 79.799,79.798 33.597,19.605 70.283,29.407 110.063,29.407 39.78,0 76.47,-9.802 110.065,-29.407 33.593,-19.602 60.189,-46.206 79.795,-79.798 19.603,-33.596 29.403,-70.284 29.403,-110.062 0.001,-39.782 -9.8,-76.472 -29.399,-110.064 z M 182.727,54.813 c 0,-2.666 0.855,-4.853 2.57,-6.565 1.712,-1.711 3.903,-2.57 6.567,-2.57 h 54.82 c 2.662,0 4.853,0.859 6.561,2.57 1.711,1.712 2.573,3.899 2.573,6.565 v 45.682 c 0,2.664 -0.862,4.854 -2.573,6.564 -1.708,1.712 -3.898,2.568 -6.561,2.568 h -54.82 c -2.664,0 -4.854,-0.856 -6.567,-2.568 -1.715,-1.709 -2.57,-3.9 -2.57,-6.564 z m 109.632,301.496 c 0,2.662 -0.863,4.853 -2.57,6.561 -1.704,1.714 -3.895,2.57 -6.563,2.57 H 155.317 c -2.667,0 -4.854,-0.856 -6.567,-2.57 -1.712,-1.708 -2.568,-3.898 -2.568,-6.564 v -45.682 c 0,-2.67 0.856,-4.853 2.568,-6.567 1.713,-1.708 3.903,-2.57 6.567,-2.57 h 27.41 v -91.358 h -27.41 c -2.667,0 -4.853,-0.855 -6.567,-2.568 -1.712,-1.711 -2.568,-3.901 -2.568,-6.567 v -45.679 c 0,-2.666 0.856,-4.853 2.568,-6.567 1.715,-1.713 3.905,-2.568 6.567,-2.568 h 91.367 c 2.662,0 4.853,0.855 6.561,2.568 1.711,1.714 2.573,3.901 2.573,6.567 v 146.179 h 27.401 c 2.669,0 4.859,0.855 6.57,2.566 1.704,1.712 2.566,3.901 2.566,6.567 v 45.683 h 0.004 z" />
</g><path
inkscape:connector-curvature="0"
id="path88"
d="m 16.36476,36.447391 v -3.208779 h 1.871787 1.871787 V 27.890649 22.542686 H 18.236547 16.36476 V 19.333908 16.12513 h 5.615361 5.615362 v 8.556741 8.556741 h 2.139185 2.139186 v 3.208779 3.208778 H 24.119307 16.36476 Z"
style="fill:#ffffff;stroke-width:0.53479636" /><path
inkscape:connector-curvature="0"
id="path90"
d="M 20.571824,11.490228 C 20.375732,11.294136 20.215294,9.8501861 20.215294,8.2814501 V 5.429203 h 3.743574 3.743574 v 3.208778 3.208778 h -3.387043 c -1.862874,0 -3.547483,-0.160439 -3.743575,-0.356531 z"
style="fill:#ffffff;stroke-width:0.53479636" /></g></svg>

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -1,12 +1,8 @@
manage_window.title=Flatpak Application Manager manage_window.title=Flatpak Application Manager
manage_window.columns.name=Name
manage_window.columns.version=Version
manage_window.columns.latest_version=Latest Version manage_window.columns.latest_version=Latest Version
manage_window.columns.branch=Branch
manage_window.columns.arch=Arch
manage_window.columns.ref=Ref
manage_window.columns.origin=Origin
manage_window.columns.update=Upgrade ? manage_window.columns.update=Upgrade ?
manage_window.apps_table.row.actions.info=Information
manage_window.apps_table.row.actions.history=History
manage_window.apps_table.row.actions.uninstall=Uninstall 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.title=Uninstall
manage_window.apps_table.row.actions.uninstall.popup.body=Remove {} ? manage_window.apps_table.row.actions.uninstall.popup.body=Remove {} ?
@@ -18,6 +14,8 @@ manage_window.status.refreshing=Refreshing
manage_window.status.upgrading=Upgrading manage_window.status.upgrading=Upgrading
manage_window.status.uninstalling=Uninstalling manage_window.status.uninstalling=Uninstalling
manage_window.status.downgrading=Downgrading manage_window.status.downgrading=Downgrading
manage_window.status.info=Retrieving information
manage_window.status.history=Retrieving history
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
@@ -28,9 +26,29 @@ popup.root.bad_password.title=Error
popup.root.bad_password.body=Wrong password popup.root.bad_password.body=Wrong password
popup.downgrade.impossible.title=Impossible to downgrade popup.downgrade.impossible.title=Impossible to downgrade
popup.downgrade.impossible.body=The app is in its first version popup.downgrade.impossible.body=The app is in its first version
popup.history.title=History
popup.history.selected.tooltip=Current version
popup.button.yes=Yes popup.button.yes=Yes
popup.button.no=No popup.button.no=No
popup.button.cancel=Cancel popup.button.cancel=Cancel
tray.action.manage=Manage applications tray.action.manage=Manage applications
tray.action.exit=Exit tray.action.exit=Exit
notification.new_updates=Updates found notification.new_updates=Updates found
flatpak.info.arch=arch
flatpak.info.branch=branch
flatpak.info.collection=collection
flatpak.info.commit=commit
flatpak.info.date=date
flatpak.info.id=id
flatpak.info.installation=installation
flatpak.info.installed=installed
flatpak.info.license=license
flatpak.info.name=name
flatpak.info.origin=origin
flatpak.info.parent=parent
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=subject
flatpak.info.type=type
flatpak.info.version=version

View File

@@ -1,23 +1,21 @@
manage_window.title=Administrador de Aplicativos Flatpak manage_window.title=Administrador de Aplicativos Flatpak
manage_window.columns.name=Nombre
manage_window.columns.version=Versión
manage_window.columns.latest_version=Ultima Versión manage_window.columns.latest_version=Ultima Versión
manage_window.columns.branch=Rama manage_window.columns.update=Actualizar ?
manage_window.columns.arch=Arch manage_window.apps_table.row.actions.info=Información
manage_window.columns.ref=Ref manage_window.apps_table.row.actions.history=Historia
manage_window.columns.origin=Origen
manage_window.columns.update=¿Actualizar?
manage_window.apps_table.row.actions.uninstall=Desinstalar 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.title=Desinstalación
manage_window.apps_table.row.actions.uninstall.popup.body=¿Eliminar {}? manage_window.apps_table.row.actions.uninstall.popup.body=¿Eliminar {}?
manage_window.apps_table.row.actions.downgrade=Revertir versión manage_window.apps_table.row.actions.downgrade=Revertir versión
manage_window.apps_table.row.actions.downgrade.popup.body=¿Realmente quieres revertir la versión actual de {}? manage_window.apps_table.row.actions.downgrade.popup.body=¿Realmente quieres revertir la versión actual de {}?
manage_window.checkbox.only_apps=Apps manage_window.checkbox.only_apps=Aplicativos
manage_window.label.updates=Actualizaciones manage_window.label.updates=Actualizaciones
manage_window.status.refreshing=Recargando manage_window.status.refreshing=Recargando
manage_window.status.upgrading=Actualizando manage_window.status.upgrading=Actualizando
manage_window.status.uninstalling=Desinstalando manage_window.status.uninstalling=Desinstalando
manage_window.status.downgrading=Revirtiendo manage_window.status.downgrading=Revirtiendo
manage_window.status.info=Obteniendo información
manage_window.status.history=Obteniendo la historia
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
@@ -28,9 +26,29 @@ popup.root.bad_password.title=Error
popup.root.bad_password.body=Contraseña incorrecta popup.root.bad_password.body=Contraseña incorrecta
popup.downgrade.impossible.title=Imposible revertir la versión popup.downgrade.impossible.title=Imposible revertir la versión
popup.downgrade.impossible.body=El aplicativo está en su primera versión popup.downgrade.impossible.body=El aplicativo está en su primera versión
popup.history.title=Historia
popup.history.selected.tooltip=Versión actual
popup.button.yes=Sí popup.button.yes=Sí
popup.button.no=No popup.button.no=No
popup.button.cancel=Cancelar popup.button.cancel=Cancelar
tray.action.manage=Administrar aplicativos tray.action.manage=Administrar aplicativos
tray.action.exit=Salir tray.action.exit=Salir
notification.new_updates=Actualizaciones encontradas notification.new_updates=Actualizaciones encontradas
flatpak.info.arch=arquitectura
flatpak.info.branch=rama
flatpak.info.collection=colección
flatpak.info.commit=commit
flatpak.info.date=fecha
flatpak.info.id=id
flatpak.info.installation=instalación
flatpak.info.installed=instalado
flatpak.info.license=licencia
flatpak.info.name=nombre
flatpak.info.origin=origen
flatpak.info.parent=padre
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=tema
flatpak.info.type=tipo
flatpak.info.version=versión

View File

@@ -1,23 +1,21 @@
manage_window.title=Gerenciador de Aplicativos Flatpak manage_window.title=Gerenciador de Aplicativos Flatpak
manage_window.columns.name=Nome
manage_window.columns.version=Versão
manage_window.columns.latest_version=Última Versão manage_window.columns.latest_version=Última Versão
manage_window.columns.branch=Ramo
manage_window.columns.arch=Arch
manage_window.columns.ref=Ref
manage_window.columns.origin=Origem
manage_window.columns.update=Atualizar ? manage_window.columns.update=Atualizar ?
manage_window.apps_table.row.actions.info=Informação
manage_window.apps_table.row.actions.history=Histórico
manage_window.apps_table.row.actions.uninstall=Desinstalar 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.title=Desinstalação
manage_window.apps_table.row.actions.uninstall.popup.body=Remover {}? manage_window.apps_table.row.actions.uninstall.popup.body=Remover {}?
manage_window.apps_table.row.actions.downgrade=Reverter versão manage_window.apps_table.row.actions.downgrade=Reverter versão
manage_window.apps_table.row.actions.downgrade.popup.body=Você realmente quer reverter a versão atual de {} ? manage_window.apps_table.row.actions.downgrade.popup.body=Você realmente quer reverter a versão atual de {} ?
manage_window.checkbox.only_apps=Apps manage_window.checkbox.only_apps=Aplicativos
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.upgrading=Atualizando manage_window.status.upgrading=Atualizando
manage_window.status.uninstalling=Desinstalando manage_window.status.uninstalling=Desinstalando
manage_window.status.downgrading=Revertendo manage_window.status.downgrading=Revertendo
manage_window.status.info=Obtendo informação
manage_window.status.history=Obtendo histórico
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
@@ -28,9 +26,29 @@ popup.root.bad_password.title=Erro
popup.root.bad_password.body=Senha incorreta popup.root.bad_password.body=Senha incorreta
popup.downgrade.impossible.title=Impossível reverter a versão popup.downgrade.impossible.title=Impossível reverter a versão
popup.downgrade.impossible.body=O aplicativo está na sua primeira versão popup.downgrade.impossible.body=O aplicativo está na sua primeira versão
popup.history.title=Histórico
popup.history.selected.tooltip=Versão atual
popup.button.yes=Sim popup.button.yes=Sim
popup.button.no=Não popup.button.no=Não
popup.button.cancel=Cancelar popup.button.cancel=Cancelar
tray.action.manage=Gerenciar aplicativos tray.action.manage=Gerenciar aplicativos
tray.action.exit=Sair tray.action.exit=Sair
notification.new_updates=Atualizações encontradas notification.new_updates=Atualizações encontradas
flatpak.info.arch=arquitetura
flatpak.info.branch=ramo
flatpak.info.collection=coleção
flatpak.info.commit=commit
flatpak.info.date=data
flatpak.info.id=id
flatpak.info.installation=instalação
flatpak.info.installed=instalado
flatpak.info.license=licença
flatpak.info.name=nome
flatpak.info.origin=origem
flatpak.info.parent=pai
flatpak.info.ref=ref
flatpak.info.runtime=runtime
flatpak.info.sdk=sdk
flatpak.info.subject=assunto
flatpak.info.type=tipo
flatpak.info.version=versão

View File

@@ -1,12 +1,13 @@
import json
from typing import List from typing import List
from PyQt5.QtCore import Qt, QUrl from PyQt5.QtCore import Qt, QUrl, QThread, pyqtSignal
from PyQt5.QtGui import QPixmap, QIcon, QColor, QCursor from PyQt5.QtGui import QPixmap, QIcon, QColor, QCursor
from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \ from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \
QMessageBox, QHeaderView QMessageBox, QHeaderView, QDialog, QLineEdit, QVBoxLayout, QPlainTextEdit
from fpakman.core import resource from fpakman.core import resource, flatpak
from fpakman.core.controller import FlatpakController from fpakman.core.controller import FlatpakController
from fpakman.view.qt import dialog from fpakman.view.qt import dialog
@@ -48,8 +49,6 @@ class AppsTable(QTableWidget):
self.setHorizontalHeaderLabels(columns) self.setHorizontalHeaderLabels(columns)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.icon_flathub = QIcon(resource.get_path('img/flathub_45.svg')) self.icon_flathub = QIcon(resource.get_path('img/flathub_45.svg'))
self.icon_uninstall = QIcon(resource.get_path('img/uninstall.svg'))
self.icon_downgrade = QIcon(resource.get_path('img/downgrade.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)
@@ -59,28 +58,41 @@ class AppsTable(QTableWidget):
def contextMenuEvent(self, QContextMenuEvent): # selected row right click event def contextMenuEvent(self, QContextMenuEvent): # selected row right click event
menu_row = QMenu() menu_row = QMenu()
action_info = QAction(self.parent.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.parent.locale_keys["manage_window.apps_table.row.actions.history"])
action_history.setIcon(QIcon(resource.get_path('img/history.svg')))
action_history.triggered.connect(self._get_app_history)
menu_row.addAction(action_history)
action_uninstall = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.uninstall"]) action_uninstall = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.uninstall"])
action_uninstall.setIcon(self.icon_uninstall) action_uninstall.setIcon(QIcon(resource.get_path('img/uninstall.svg')))
action_uninstall.triggered.connect(self._uninstall_app) action_uninstall.triggered.connect(self._uninstall_app)
menu_row.addAction(action_uninstall) menu_row.addAction(action_uninstall)
app = self._get_selected_app() app = self.get_selected_app()
if not app['model']['runtime']: # downgrade only allowed for apps if not app['model']['runtime']: # downgrade only allowed for apps
action_downgrade = QAction(self.parent.locale_keys["manage_window.apps_table.row.actions.downgrade"]) action_downgrade = QAction(self.parent.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(self.icon_downgrade) action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
menu_row.addAction(action_downgrade) menu_row.addAction(action_downgrade)
menu_row.adjustSize() menu_row.adjustSize()
menu_row.popup(QCursor.pos()) menu_row.popup(QCursor.pos())
menu_row.exec_() menu_row.exec_()
def _get_selected_app(self): def get_selected_app(self):
return self.parent.apps[self.currentRow()] return self.parent.apps[self.currentRow()]
def get_selected_app_icon(self):
return self.item(self.currentRow(), 0).icon()
def _uninstall_app(self): def _uninstall_app(self):
selected_app = self._get_selected_app() selected_app = self.get_selected_app()
if dialog.ask_confirmation(title=self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.title'], if dialog.ask_confirmation(title=self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.title'],
body=self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.body'].format(selected_app['model']['name']), body=self.parent.locale_keys['manage_window.apps_table.row.actions.uninstall.popup.body'].format(selected_app['model']['name']),
@@ -88,13 +100,19 @@ class AppsTable(QTableWidget):
self.parent.uninstall_app(selected_app['model']['ref']) self.parent.uninstall_app(selected_app['model']['ref'])
def _downgrade_app(self): def _downgrade_app(self):
selected_app = self._get_selected_app() selected_app = self.get_selected_app()
if dialog.ask_confirmation(title=self.parent.locale_keys['manage_window.apps_table.row.actions.downgrade'], if dialog.ask_confirmation(title=self.parent.locale_keys['manage_window.apps_table.row.actions.downgrade'],
body=self.parent.locale_keys['manage_window.apps_table.row.actions.downgrade.popup.body'].format(selected_app['model']['name']), body=self.parent.locale_keys['manage_window.apps_table.row.actions.downgrade.popup.body'].format(selected_app['model']['name']),
locale_keys=self.parent.locale_keys): locale_keys=self.parent.locale_keys):
self.parent.downgrade_app(selected_app['model']['ref']) self.parent.downgrade_app(selected_app['model']['ref'])
def _get_app_info(self):
self.parent.get_app_info(self.get_selected_app())
def _get_app_history(self):
self.parent.get_app_history(self.get_selected_app())
def _load_icon(self, http_response): def _load_icon(self, http_response):
icon_url = http_response.url().toString() icon_url = http_response.url().toString()
pixmap = QPixmap() pixmap = QPixmap()

View File

@@ -0,0 +1,52 @@
import operator
from functools import reduce
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTableWidget, QTableWidgetItem, QHeaderView
class HistoryDialog(QDialog):
def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict):
super(HistoryDialog, self).__init__()
self.setWindowTitle('{} - {} '.format(locale_keys['popup.history.title'], app['model']['name']))
self.setWindowIcon(app_icon)
layout = QVBoxLayout()
self.setLayout(layout)
table_history = QTableWidget()
table_history.setFocusPolicy(Qt.NoFocus)
table_history.setShowGrid(False)
table_history.verticalHeader().setVisible(False)
table_history.setAlternatingRowColors(True)
table_history.setColumnCount(len(app['commits'][0]))
table_history.setRowCount(len(app['commits']))
table_history.setHorizontalHeaderLabels([locale_keys['flatpak.info.' + key].capitalize() for key in sorted(app['commits'][0].keys())])
for row, commit in enumerate(app['commits']):
current_app_commit = app['model']['commit'] == commit['commit']
for col, key in enumerate(sorted(commit.keys())):
item = QTableWidgetItem()
item.setText(commit[key])
item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
if current_app_commit:
item.setBackground(Qt.darkYellow)
item.setToolTip(locale_keys['popup.history.selected.tooltip'])
table_history.setItem(row, col, item)
layout.addWidget(table_history)
header_horizontal = table_history.horizontalHeader()
for i in range(0, table_history.columnCount()):
header_horizontal.setSectionResizeMode(i, QHeaderView.Stretch)
new_width = reduce(operator.add, [table_history.columnWidth(i) for i in range(table_history.columnCount())])
self.resize(new_width, table_history.height())

34
fpakman/view/qt/info.py Normal file
View File

@@ -0,0 +1,34 @@
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QFormLayout, QGroupBox, \
QLineEdit, QLabel
class InfoDialog(QDialog):
def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict):
super(InfoDialog, self).__init__()
self.setWindowTitle(app['name'])
self.setWindowIcon(app_icon)
layout = QVBoxLayout()
self.setLayout(layout)
gbox_info_layout = QFormLayout()
gbox_info = QGroupBox()
gbox_info.setLayout(gbox_info_layout)
layout.addWidget(gbox_info)
for attr in sorted(app.keys()):
if attr != 'name':
text = QLineEdit()
text.setText(app[attr])
text.setStyleSheet("width: 400px")
text.setReadOnly(True)
text.setCursorPosition(0)
label = QLabel("{}: ".format(locale_keys.get('flatpak.info.' + attr, attr)).capitalize())
label.setStyleSheet("font-weight: bold")
gbox_info_layout.addRow(label, text)
self.adjustSize()

View File

@@ -1,19 +1,22 @@
import json
import operator import operator
from functools import reduce from functools import reduce
from threading import Lock from threading import Lock
from typing import List from typing import List
from PyQt5.QtCore import QThread, pyqtSignal, QEvent from PyQt5.QtCore import QThread, pyqtSignal, QEvent, Qt
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent from PyQt5.QtGui import QIcon, QWindowStateChangeEvent
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \ from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \
QSizePolicy, QLabel, QMessageBox, QPlainTextEdit QSizePolicy, QLabel, QPlainTextEdit, QDialog, QGroupBox, QFormLayout, QLineEdit, QTableWidget, QTableWidgetItem
from fpakman.core.model import FlatpakManager, ImpossibleDowngradeException
from fpakman import __version__ from fpakman import __version__
from fpakman.core import resource from fpakman.core import resource, flatpak
from fpakman.core.controller import FlatpakController from fpakman.core.controller import FlatpakController
from fpakman.core.model import FlatpakManager, ImpossibleDowngradeException
from fpakman.view.qt import dialog from fpakman.view.qt import dialog
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.info import InfoDialog
from fpakman.view.qt.root import is_root, ask_root_password from fpakman.view.qt.root import is_root, ask_root_password
@@ -21,17 +24,17 @@ class ManageWindow(QWidget):
__BASE_HEIGHT__ = 400 __BASE_HEIGHT__ = 400
def __init__(self, locale_keys: dict, controller: FlatpakController, manager: FlatpakManager, tray_icon = None): def __init__(self, locale_keys: dict, controller: FlatpakController, manager: FlatpakManager, tray_icon=None):
super(ManageWindow, self).__init__() super(ManageWindow, self).__init__()
self.locale_keys = locale_keys self.locale_keys = locale_keys
self.column_names = [locale_keys['manage_window.columns.name'], self.column_names = [locale_keys[key].capitalize() for key in ['flatpak.info.name',
locale_keys['manage_window.columns.version'], 'flatpak.info.version',
locale_keys['manage_window.columns.latest_version'], 'manage_window.columns.latest_version',
locale_keys['manage_window.columns.branch'], 'flatpak.info.branch',
locale_keys['manage_window.columns.arch'], 'flatpak.info.arch',
locale_keys['manage_window.columns.ref'], 'flatpak.info.ref',
locale_keys['manage_window.columns.origin'], 'flatpak.info.origin',
locale_keys['manage_window.columns.update']] 'manage_window.columns.update']]
self.controller = controller self.controller = controller
self.manager = manager self.manager = manager
self.tray_icon = tray_icon self.tray_icon = tray_icon
@@ -112,6 +115,12 @@ 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.signal_finished.connect(self._finish_get_info)
self.thread_get_history = GetAppHistory()
self.thread_get_history.signal_finished.connect(self._finish_get_history)
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)
@@ -174,7 +183,7 @@ class ManageWindow(QWidget):
if self._acquire_lock(): if self._acquire_lock():
self._check_flatpak_installed() self._check_flatpak_installed()
self._begin_action(self.locale_keys['manage_window.status.refreshing'] + '...') self._begin_action(self.locale_keys['manage_window.status.refreshing'])
if clear_output: if clear_output:
self.textarea_output.clear() self.textarea_output.clear()
@@ -194,7 +203,7 @@ class ManageWindow(QWidget):
if self._acquire_lock(): if self._acquire_lock():
self.textarea_output.clear() self.textarea_output.clear()
self.textarea_output.setVisible(True) self.textarea_output.setVisible(True)
self._begin_action(self.locale_keys['manage_window.status.uninstalling'] + '...') self._begin_action(self.locale_keys['manage_window.status.uninstalling'])
self.thread_uninstall.app_ref = app_ref self.thread_uninstall.app_ref = app_ref
self.thread_uninstall.start() self.thread_uninstall.start()
@@ -303,7 +312,7 @@ class ManageWindow(QWidget):
self.textarea_output.clear() self.textarea_output.clear()
self.textarea_output.setVisible(True) self.textarea_output.setVisible(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.refs_to_update = to_update
self.thread_update.start() self.thread_update.start()
@@ -316,7 +325,7 @@ class ManageWindow(QWidget):
self.textarea_output.appendPlainText(output) self.textarea_output.appendPlainText(output)
def _begin_action(self, action_label: str): def _begin_action(self, action_label: str):
self.label_status.setText(action_label) self.label_status.setText(action_label + "...")
self.bt_upgrade.setEnabled(False) self.bt_upgrade.setEnabled(False)
self.bt_refresh.setEnabled(False) self.bt_refresh.setEnabled(False)
self.checkbox_only_apps.setEnabled(False) self.checkbox_only_apps.setEnabled(False)
@@ -345,12 +354,44 @@ class ManageWindow(QWidget):
self.textarea_output.clear() self.textarea_output.clear()
self.textarea_output.setVisible(True) self.textarea_output.setVisible(True)
self._begin_action(self.locale_keys['manage_window.status.downgrading'] + '...') self._begin_action(self.locale_keys['manage_window.status.downgrading'])
self.thread_downgrade.app_ref = app_ref self.thread_downgrade.app_ref = app_ref
self.thread_downgrade.root_password = pwd self.thread_downgrade.root_password = pwd
self.thread_downgrade.start() self.thread_downgrade.start()
def get_app_info(self, app: dict):
if self._acquire_lock():
self.textarea_output.clear()
self.textarea_output.setVisible(False)
self._begin_action(self.locale_keys['manage_window.status.info'])
self.thread_get_info.app = app
self.thread_get_info.start()
def get_app_history(self, app: dict):
if self._acquire_lock():
self.textarea_output.clear()
self.textarea_output.setVisible(False)
self._begin_action(self.locale_keys['manage_window.status.history'])
self.thread_get_history.app = app
self.thread_get_history.start()
def _finish_get_info(self, app_info: dict):
self._release_lock()
self.finish_action()
dialog_info = InfoDialog(app_info, self.table_apps.get_selected_app_icon(), self.locale_keys)
dialog_info.exec_()
def _finish_get_history(self, app: dict):
self._release_lock()
self.finish_action()
dialog_history = HistoryDialog(app, self.table_apps.get_selected_app_icon(), self.locale_keys)
dialog_history.exec_()
# Threaded actions # Threaded actions
class UpdateSelectedApps(QThread): class UpdateSelectedApps(QThread):
@@ -433,3 +474,33 @@ class DowngradeApp(QThread):
self.app_ref = None self.app_ref = None
self.root_password = None self.root_password = None
self.signal_finished.emit() self.signal_finished.emit()
class GetAppInfo(QThread):
signal_finished = pyqtSignal(dict)
def __init__(self):
super(GetAppInfo, self).__init__()
self.app = None
def run(self):
if self.app:
app_info = flatpak.get_app_info_fields(self.app['model']['id'], self.app['model']['branch'])
app_info['name'] = self.app['model']['name']
app_info['type'] = 'runtime' if self.app['model']['runtime'] else 'app'
self.signal_finished.emit(app_info)
self.app = None
class GetAppHistory(QThread):
signal_finished = pyqtSignal(dict)
def __init__(self):
super(GetAppHistory, self).__init__()
self.app = None
def run(self):
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'], 'commits': commits})
self.app = None