mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-08 14:24:15 +02:00
0.2.0
**Features** - Management panel shows update commands streams - Management panel status label is "orange" now **Fixes** - Application name is not properly showing for Flatpak 1.2.X
This commit is contained in:
18
CHANGELOG.md
18
CHANGELOG.md
@@ -4,10 +4,18 @@ 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.0] - 2019-06-18
|
||||||
|
### Features
|
||||||
|
- Management panel shows update commands streams
|
||||||
|
- Management panel status label is "orange" now
|
||||||
|
|
||||||
|
### Fixes
|
||||||
|
- Application name is not properly showing for Flatpak 1.2.X
|
||||||
|
|
||||||
## [0.1.0] - 2019-06-14
|
## [0.1.0] - 2019-06-14
|
||||||
### Features
|
### Features
|
||||||
- System tray icon.
|
- System tray icon.
|
||||||
- Applications management window.
|
- Applications management window.
|
||||||
- Support for the following locales: PT, EN, ES.
|
- Support for the following locales: PT, EN, ES.
|
||||||
- System notification for new updates.
|
- System notification for new updates.
|
||||||
- Update applications.
|
- Update applications.
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ It has also a management window allowing the user to see all installed applicati
|
|||||||
- python-pyqt5
|
- python-pyqt5
|
||||||
|
|
||||||
### Distribution
|
### Distribution
|
||||||
Currently available via **PyPi** (sudo pip3 install fpakman) or **AUR** (for Arch Linux users. **fpakman-staging** is just for testing, do not install it.)
|
**PyPi**
|
||||||
|
```
|
||||||
|
sudo pip3 install fpakman
|
||||||
|
```
|
||||||
|
|
||||||
|
**AUR**
|
||||||
|
As **fpakman** package. There is also a staging version (**fpakman-staging**) but is intended for testing and it may not work properly.
|
||||||
|
|
||||||
|
|
||||||
### Manual installation:
|
### Manual installation:
|
||||||
@@ -38,6 +44,5 @@ You can change some application settings via environment variables:
|
|||||||
- **FPAKMAN_CHECK_INTERVAL**: define the updates check interval in seconds. Default: 60.
|
- **FPAKMAN_CHECK_INTERVAL**: define the updates check interval in seconds. Default: 60.
|
||||||
|
|
||||||
### Roadmap
|
### Roadmap
|
||||||
- Show updates being applied
|
|
||||||
- Search and install applications
|
- Search and install applications
|
||||||
- Uninstall applications
|
- Uninstall applications
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# used for AUR installation
|
# used for AUR installation
|
||||||
import subprocess
|
import os
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
@@ -7,14 +7,18 @@ desktop_file = """
|
|||||||
[Desktop Entry]
|
[Desktop Entry]
|
||||||
Type = Application
|
Type = Application
|
||||||
Name = fpakman
|
Name = fpakman
|
||||||
|
Categories = System;
|
||||||
Comment = Manage your Flatpak applications
|
Comment = Manage your Flatpak applications
|
||||||
Exec = /usr/bin/fpakman
|
Exec = /usr/bin/fpakman
|
||||||
Icon = /usr/lib/python{version}/site-packages/fpakman/resources/img/flathub_45.svg
|
Icon = /usr/lib/python{version}/site-packages/fpakman/resources/img/flathub_45.svg
|
||||||
""".format(version="{}.{}".format(sys.version_info.major, sys.version_info.minor))
|
""".format(version="{}.{}".format(sys.version_info.major, sys.version_info.minor))
|
||||||
|
|
||||||
file_path = '{}/.local/share/applications/fpakman.desktop'.format(str(Path.home()))
|
apps_path = '{}/.local/share/applications'.format(str(Path.home()))
|
||||||
|
|
||||||
|
if not os.path.exists(apps_path):
|
||||||
|
os.mkdir(apps_path)
|
||||||
|
|
||||||
|
file_path = '{}/fpakman.desktop'.format(apps_path)
|
||||||
|
|
||||||
with open(file_path, 'w+') as f:
|
with open(file_path, 'w+') as f:
|
||||||
f.write(desktop_file)
|
f.write(desktop_file)
|
||||||
|
|
||||||
subprocess.run('desktop-file-install {}'.format(file_path), shell=True)
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
__version__ = '0.2.0'
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ import argparse
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from PyQt5.QtWidgets import QApplication, QWidget
|
from PyQt5.QtGui import QIcon
|
||||||
|
from PyQt5.QtWidgets import QApplication
|
||||||
|
|
||||||
|
from fpakman import __version__
|
||||||
|
from fpakman.core import resource
|
||||||
|
from fpakman.core import util
|
||||||
from fpakman.core.controller import FlatpakController
|
from fpakman.core.controller import FlatpakController
|
||||||
from fpakman.core.model import FlatpakManager
|
from fpakman.core.model import FlatpakManager
|
||||||
from fpakman.view.qt.systray import TrayIcon
|
from fpakman.view.qt.systray import TrayIcon
|
||||||
from fpakman.core import __version__
|
|
||||||
from fpakman.core import util
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(prog='fpakman', description="GUI for Flatpak applications management")
|
parser = argparse.ArgumentParser(prog='fpakman', description="GUI for Flatpak applications management")
|
||||||
parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(__version__))
|
parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(__version__))
|
||||||
@@ -17,13 +19,12 @@ args = parser.parse_args()
|
|||||||
locale_keys = util.get_locale_keys()
|
locale_keys = util.get_locale_keys()
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
app.setWindowIcon(QIcon(resource.get_path('img/flathub_45.svg')))
|
||||||
manager = FlatpakManager()
|
manager = FlatpakManager()
|
||||||
manager.load_database_async()
|
manager.load_database_async()
|
||||||
controller = FlatpakController(manager)
|
controller = FlatpakController(manager)
|
||||||
hidden_widget = QWidget()
|
|
||||||
|
|
||||||
trayIcon = TrayIcon(locale_keys=locale_keys,
|
trayIcon = TrayIcon(locale_keys=locale_keys,
|
||||||
parent=hidden_widget,
|
|
||||||
controller=controller,
|
controller=controller,
|
||||||
check_interval=int(os.getenv('FPAKMAN_CHECK_INTERVAL', 60)))
|
check_interval=int(os.getenv('FPAKMAN_CHECK_INTERVAL', 60)))
|
||||||
trayIcon.show()
|
trayIcon.show()
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = '0.1.0'
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ class FlatpakController:
|
|||||||
def refresh(self) -> List[dict]:
|
def refresh(self) -> List[dict]:
|
||||||
return self.model.read_installed()
|
return self.model.read_installed()
|
||||||
|
|
||||||
def update(self, package_refs: List[str]) -> List[dict]:
|
def update(self, app_ref: str):
|
||||||
return self.model.update_apps(package_refs)
|
return self.model.update_app(app_ref)
|
||||||
|
|
||||||
def check_installed(self) -> bool:
|
def check_installed(self) -> bool:
|
||||||
version = self.model.get_version()
|
version = self.model.get_version()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def app_str_to_json(line: str, version: str) -> dict:
|
|||||||
app['name'] = ref_data[0].split('.')[-1]
|
app['name'] = ref_data[0].split('.')[-1]
|
||||||
app['version'] = None
|
app['version'] = None
|
||||||
elif '1.2' <= version < '1.3':
|
elif '1.2' <= version < '1.3':
|
||||||
app = {'name': app_array[0][1].split('.')[-1],
|
app = {'name': app_array[1].strip().split('.')[-1],
|
||||||
'id': app_array[1],
|
'id': app_array[1],
|
||||||
'version': app_array[2],
|
'version': app_array[2],
|
||||||
'branch': app_array[3],
|
'branch': app_array[3],
|
||||||
@@ -68,8 +68,17 @@ def list_installed() -> List[dict]:
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def update(ref: str):
|
def update(app_ref: str) -> bool:
|
||||||
return bool(system.run_cmd('flatpak update -y ' + ref))
|
return bool(system.run_cmd('flatpak update -y ' + app_ref))
|
||||||
|
|
||||||
|
|
||||||
|
def update_and_stream(app_ref: str):
|
||||||
|
"""
|
||||||
|
Updates the app reference and streams Flatpak output,
|
||||||
|
:param app_ref:
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
return system.stream_cmd(['flatpak', 'update', '-y', app_ref])
|
||||||
|
|
||||||
|
|
||||||
def list_updates_as_str():
|
def list_updates_as_str():
|
||||||
|
|||||||
@@ -90,3 +90,19 @@ class FlatpakManager:
|
|||||||
return [*self.apps]
|
return [*self.apps]
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
def update_app(self, ref: str):
|
||||||
|
|
||||||
|
"""
|
||||||
|
:param ref:
|
||||||
|
:return: the update command stream
|
||||||
|
"""
|
||||||
|
|
||||||
|
if self.apps:
|
||||||
|
|
||||||
|
package_found = [app for app in self.apps if app['ref'] == ref]
|
||||||
|
|
||||||
|
if package_found:
|
||||||
|
return flatpak.update_and_stream(ref)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|||||||
@@ -1,10 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
|
app_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
|
|
||||||
|
|
||||||
def get_path(resource_path):
|
def get_path(resource_path):
|
||||||
app_dir = get_app_dir()
|
|
||||||
return app_dir + '/resources/' + resource_path
|
return app_dir + '/resources/' + resource_path
|
||||||
|
|
||||||
|
|
||||||
def get_app_dir():
|
|
||||||
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
|
|||||||
@@ -1,6 +1,11 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
|
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)
|
||||||
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]):
|
||||||
|
return subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
|
||||||
|
|||||||
@@ -8,10 +8,11 @@ def get_locale_keys():
|
|||||||
|
|
||||||
current_locale = locale.getdefaultlocale()
|
current_locale = locale.getdefaultlocale()
|
||||||
locale_path = None
|
locale_path = None
|
||||||
|
|
||||||
if current_locale:
|
if current_locale:
|
||||||
current_locale = current_locale[0]
|
current_locale = current_locale[0]
|
||||||
|
|
||||||
locale_dir = '{}/resources/locale'.format(resource.get_app_dir())
|
locale_dir = resource.get_path('locale')
|
||||||
|
|
||||||
for locale_file in glob.glob(locale_dir + '/*'):
|
for locale_file in glob.glob(locale_dir + '/*'):
|
||||||
name = locale_file.split('/')[-1]
|
name = locale_file.split('/')[-1]
|
||||||
@@ -21,7 +22,7 @@ def get_locale_keys():
|
|||||||
break
|
break
|
||||||
|
|
||||||
if not locale_path:
|
if not locale_path:
|
||||||
locale_path = '{}/resources/locale/en'.format(resource.get_app_dir())
|
locale_path = resource.get_path('locale/en')
|
||||||
|
|
||||||
with open(locale_path, 'r') as f:
|
with open(locale_path, 'r') as f:
|
||||||
locale_keys = f.readlines()
|
locale_keys = f.readlines()
|
||||||
|
|||||||
@@ -1,179 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
|
||||||
xmlns:cc="http://creativecommons.org/ns#"
|
|
||||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg"
|
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
|
||||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
|
||||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
|
||||||
width="9.6111898"
|
|
||||||
height="8.805685"
|
|
||||||
viewBox="0 0 2.5429606 2.3298375"
|
|
||||||
version="1.1"
|
|
||||||
id="svg3871"
|
|
||||||
inkscape:version="0.92.4 5da689c313, 2019-01-14"
|
|
||||||
sodipodi:docname="flathub_5.svg">
|
|
||||||
<defs
|
|
||||||
id="defs3865" />
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="base"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#666666"
|
|
||||||
borderopacity="1.0"
|
|
||||||
inkscape:pageopacity="0.0"
|
|
||||||
inkscape:pageshadow="2"
|
|
||||||
inkscape:zoom="0.35"
|
|
||||||
inkscape:cx="354.03019"
|
|
||||||
inkscape:cy="118.62781"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
inkscape:current-layer="layer1"
|
|
||||||
showgrid="false"
|
|
||||||
showborder="false"
|
|
||||||
inkscape:window-width="1360"
|
|
||||||
inkscape:window-height="707"
|
|
||||||
inkscape:window-x="0"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="1"
|
|
||||||
fit-margin-bottom="-0.2"
|
|
||||||
fit-margin-top="0"
|
|
||||||
fit-margin-left="0"
|
|
||||||
fit-margin-right="0"
|
|
||||||
units="px" />
|
|
||||||
<metadata
|
|
||||||
id="metadata3868">
|
|
||||||
<rdf:RDF>
|
|
||||||
<cc:Work
|
|
||||||
rdf:about="">
|
|
||||||
<dc:format>image/svg+xml</dc:format>
|
|
||||||
<dc:type
|
|
||||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
|
||||||
<dc:title></dc:title>
|
|
||||||
</cc:Work>
|
|
||||||
</rdf:RDF>
|
|
||||||
</metadata>
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1"
|
|
||||||
transform="translate(-12.162843,-177.89043)">
|
|
||||||
<g
|
|
||||||
transform="matrix(0.01780156,0,0,0.02142021,-1.8040418,160.22597)"
|
|
||||||
id="g10674"
|
|
||||||
style="stroke-width:0.77710575">
|
|
||||||
<path
|
|
||||||
sodipodi:nodetypes="ccccccccccc"
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path10642"
|
|
||||||
d="m 856.01397,830.22631 -66.76365,43.44891 v 34.93973 l 33.38182,21.72315 33.37926,-21.72315 v -0.005 l 0.003,0.003 33.38183,21.72574 33.37925,-21.72315 v -34.93979 z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:9.3252697;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<g
|
|
||||||
style="stroke-width:0.58728963"
|
|
||||||
transform="matrix(0.50221552,0,0,0.50636711,429.63205,432.90461)"
|
|
||||||
id="g10652">
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect10644"
|
|
||||||
width="79.110413"
|
|
||||||
height="79.110413"
|
|
||||||
x="1289.9076"
|
|
||||||
y="279.42584"
|
|
||||||
rx="0"
|
|
||||||
ry="0"
|
|
||||||
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
|
|
||||||
id="path10648"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path10650"
|
|
||||||
d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
|
|
||||||
ry="0"
|
|
||||||
rx="0"
|
|
||||||
y="215.8064"
|
|
||||||
x="1226.2882"
|
|
||||||
height="79.110413"
|
|
||||||
width="79.110413"
|
|
||||||
id="rect10646"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
style="stroke-width:0.58728963"
|
|
||||||
transform="matrix(0.50221552,0,0,0.50636711,463.01368,454.62849)"
|
|
||||||
id="g10662">
|
|
||||||
<rect
|
|
||||||
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
|
|
||||||
ry="0"
|
|
||||||
rx="0"
|
|
||||||
y="279.42584"
|
|
||||||
x="1289.9076"
|
|
||||||
height="79.110413"
|
|
||||||
width="79.110413"
|
|
||||||
id="rect10654"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect10656"
|
|
||||||
width="79.110413"
|
|
||||||
height="79.110413"
|
|
||||||
x="1226.2882"
|
|
||||||
y="215.8064"
|
|
||||||
rx="0"
|
|
||||||
ry="0"
|
|
||||||
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path10658"
|
|
||||||
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 783.00003,826.54445 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
|
|
||||||
id="path10660"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
</g>
|
|
||||||
<g
|
|
||||||
style="stroke-width:0.58728963"
|
|
||||||
id="g10672"
|
|
||||||
transform="matrix(0.50221552,0,0,0.50636711,396.25042,454.62849)">
|
|
||||||
<rect
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
id="rect10664"
|
|
||||||
width="79.110413"
|
|
||||||
height="79.110413"
|
|
||||||
x="1289.9076"
|
|
||||||
y="279.42584"
|
|
||||||
rx="0"
|
|
||||||
ry="0"
|
|
||||||
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)" />
|
|
||||||
<rect
|
|
||||||
transform="matrix(0.84019328,0.54228706,-0.84019328,0.54228706,0,0)"
|
|
||||||
ry="0"
|
|
||||||
rx="0"
|
|
||||||
y="215.8064"
|
|
||||||
x="1226.2882"
|
|
||||||
height="79.110413"
|
|
||||||
width="79.110413"
|
|
||||||
id="rect10666"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.4608953;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
<path
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#204a87;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
|
||||||
d="m 915.46811,824.92983 -5e-5,68.99997 -66.46803,42.90055 5e-5,-68.99997 z"
|
|
||||||
id="path10668"
|
|
||||||
inkscape:connector-curvature="0" />
|
|
||||||
<path
|
|
||||||
inkscape:connector-curvature="0"
|
|
||||||
id="path10670"
|
|
||||||
d="m 783.00003,824.92983 5e-5,68.99997 66.46803,42.90055 -5e-5,-68.99997 z"
|
|
||||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:2.34915853;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none;paint-order:normal;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
||||||
|
Before Width: | Height: | Size: 14 KiB |
@@ -7,7 +7,7 @@ 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.checkbox.only_apps=Apps
|
manage_window.checkbox.only_apps=Apps
|
||||||
manage_window.label.updates=Actualizaciones
|
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
|
||||||
popup.flatpak_not_installed.title=Erro
|
popup.flatpak_not_installed.title=Erro
|
||||||
|
|||||||
@@ -34,15 +34,16 @@ class UpdateCheck(QThread):
|
|||||||
|
|
||||||
class TrayIcon(QSystemTrayIcon):
|
class TrayIcon(QSystemTrayIcon):
|
||||||
|
|
||||||
def __init__(self, locale_keys: dict, controller: FlatpakController, check_interval: int = 60, parent=None):
|
def __init__(self, locale_keys: dict, controller: FlatpakController, check_interval: int = 60):
|
||||||
|
super(TrayIcon, self).__init__()
|
||||||
self.locale_keys = locale_keys
|
self.locale_keys = locale_keys
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
|
|
||||||
self.icon_default = QIcon(resource.get_path('img/flathub_45.svg'))
|
self.icon_default = QIcon(resource.get_path('img/flathub_45.svg'))
|
||||||
self.icon_update = QIcon(resource.get_path('img/update_logo.svg'))
|
self.icon_update = QIcon(resource.get_path('img/update_logo.svg'))
|
||||||
QSystemTrayIcon.__init__(self, self.icon_default, parent)
|
self.setIcon(self.icon_default)
|
||||||
|
|
||||||
self.menu = QMenu(parent)
|
self.menu = QMenu()
|
||||||
self.action_manage = self.menu.addAction(self.locale_keys['tray.action.manage'])
|
self.action_manage = self.menu.addAction(self.locale_keys['tray.action.manage'])
|
||||||
self.action_manage.triggered.connect(self.show_manage_window)
|
self.action_manage.triggered.connect(self.show_manage_window)
|
||||||
self.action_exit = self.menu.addAction(self.locale_keys['tray.action.exit'])
|
self.action_exit = self.menu.addAction(self.locale_keys['tray.action.exit'])
|
||||||
@@ -63,7 +64,7 @@ class TrayIcon(QSystemTrayIcon):
|
|||||||
self.setToolTip(msg)
|
self.setToolTip(msg)
|
||||||
|
|
||||||
if bool(os.getenv('FPAKMAN_UPDATE_NOTIFICATION', 1)):
|
if bool(os.getenv('FPAKMAN_UPDATE_NOTIFICATION', 1)):
|
||||||
os.system("notify-send -i {} '{}'".format(resource.get_path('img/flathub_10.svg'), msg))
|
os.system("notify-send -i {} '{}'".format(resource.get_path('img/flathub_45.svg'), msg))
|
||||||
|
|
||||||
if self.manage_window:
|
if self.manage_window:
|
||||||
self.manage_window.refresh()
|
self.manage_window.refresh()
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ from PyQt5.QtGui import QIcon, QColor, QPixmap, QWindowStateChangeEvent
|
|||||||
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
|
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
|
||||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QTableWidget, \
|
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QTableWidget, \
|
||||||
QTableWidgetItem, QTableView, QCheckBox, QHeaderView, QToolButton, QToolBar, \
|
QTableWidgetItem, QTableView, QCheckBox, QHeaderView, QToolButton, QToolBar, \
|
||||||
QSizePolicy, QLabel, QMessageBox
|
QSizePolicy, QLabel, QMessageBox, QPlainTextEdit
|
||||||
|
|
||||||
from fpakman.core 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
|
||||||
|
|
||||||
@@ -86,6 +86,7 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
self.label_status = QLabel()
|
self.label_status = QLabel()
|
||||||
self.label_status.setText('')
|
self.label_status.setText('')
|
||||||
|
self.label_status.setStyleSheet("color: orange")
|
||||||
toolbar.addWidget(self.label_status)
|
toolbar.addWidget(self.label_status)
|
||||||
|
|
||||||
spacer = QWidget()
|
spacer = QWidget()
|
||||||
@@ -94,7 +95,7 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
self.bt_refresh = QToolButton()
|
self.bt_refresh = QToolButton()
|
||||||
self.bt_refresh.setIcon(QIcon(resource.get_path('img/refresh.svg')))
|
self.bt_refresh.setIcon(QIcon(resource.get_path('img/refresh.svg')))
|
||||||
self.bt_refresh.clicked.connect(self.refresh)
|
self.bt_refresh.clicked.connect(lambda: self.refresh(clear_output=True))
|
||||||
toolbar.addWidget(self.bt_refresh)
|
toolbar.addWidget(self.bt_refresh)
|
||||||
|
|
||||||
self.bt_update = QToolButton()
|
self.bt_update = QToolButton()
|
||||||
@@ -118,8 +119,16 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
self.layout.addWidget(self.table_apps)
|
self.layout.addWidget(self.table_apps)
|
||||||
|
|
||||||
|
self.textarea_output = QPlainTextEdit(self)
|
||||||
|
self.textarea_output.resize(self.table_apps.size())
|
||||||
|
self.textarea_output.setStyleSheet("background: black; color: white;")
|
||||||
|
self.layout.addWidget(self.textarea_output)
|
||||||
|
self.textarea_output.setVisible(False)
|
||||||
|
self.textarea_output.setReadOnly(True)
|
||||||
|
|
||||||
self.thread_update = UpdateSelectedApps(self.controller)
|
self.thread_update = UpdateSelectedApps(self.controller)
|
||||||
self.thread_update.signal.connect(self._finish_update_selected)
|
self.thread_update.signal_output.connect(self._update_action_output)
|
||||||
|
self.thread_update.signal_finished.connect(self._finish_update_selected)
|
||||||
|
|
||||||
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)
|
||||||
@@ -202,11 +211,16 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
self.thread_lock.release()
|
self.thread_lock.release()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self, clear_output: bool = True):
|
||||||
|
|
||||||
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:
|
||||||
|
self.textarea_output.clear()
|
||||||
|
self.textarea_output.hide()
|
||||||
|
|
||||||
self.thread_refresh.start()
|
self.thread_refresh.start()
|
||||||
|
|
||||||
def _finish_refresh(self):
|
def _finish_refresh(self):
|
||||||
@@ -248,6 +262,8 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
self.bt_update.setEnabled(enable_bt_update)
|
self.bt_update.setEnabled(enable_bt_update)
|
||||||
|
|
||||||
|
self.tray_icon.notify_updates(updates)
|
||||||
|
|
||||||
def centralize(self):
|
def centralize(self):
|
||||||
geo = self.frameGeometry()
|
geo = self.frameGeometry()
|
||||||
screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
|
screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
|
||||||
@@ -338,21 +354,24 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
if self._acquire_lock():
|
if self._acquire_lock():
|
||||||
if self.apps:
|
if self.apps:
|
||||||
|
|
||||||
to_update = [pak['model']['ref'] for pak in self.apps if pak['visible'] and pak['update_checked']]
|
to_update = [pak['model']['ref'] for pak in self.apps if pak['visible'] and pak['update_checked']]
|
||||||
|
|
||||||
if to_update:
|
if to_update:
|
||||||
|
self.textarea_output.clear()
|
||||||
|
self.textarea_output.setVisible(True)
|
||||||
|
|
||||||
self._begin_action(self.locale_keys['manage_window.status.updating'] + '...')
|
self._begin_action(self.locale_keys['manage_window.status.updating'] + '...')
|
||||||
self.thread_update.refs_to_update = to_update
|
self.thread_update.refs_to_update = to_update
|
||||||
self.thread_update.start()
|
self.thread_update.start()
|
||||||
|
|
||||||
def _finish_update_selected(self):
|
def _finish_update_selected(self):
|
||||||
self.update_apps(self.thread_update.updated_apps)
|
|
||||||
self.finish_action()
|
self.finish_action()
|
||||||
|
|
||||||
if self.tray_icon and self.thread_update.updated_apps:
|
|
||||||
self.tray_icon.notify_updates(len([app for app in self.thread_update.updated_apps if app['update']]))
|
|
||||||
|
|
||||||
self._release_lock()
|
self._release_lock()
|
||||||
|
self.refresh(clear_output=False)
|
||||||
|
|
||||||
|
def _update_action_output(self, output: str):
|
||||||
|
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)
|
||||||
@@ -369,20 +388,25 @@ class ManageWindow(QWidget):
|
|||||||
|
|
||||||
|
|
||||||
# Threaded actions
|
# Threaded actions
|
||||||
|
|
||||||
class UpdateSelectedApps(QThread):
|
class UpdateSelectedApps(QThread):
|
||||||
|
|
||||||
signal = pyqtSignal()
|
signal_finished = pyqtSignal()
|
||||||
|
signal_output = pyqtSignal(str)
|
||||||
|
|
||||||
def __init__(self, controller: FlatpakController):
|
def __init__(self, controller: FlatpakController):
|
||||||
super(UpdateSelectedApps, self).__init__()
|
super(UpdateSelectedApps, self).__init__()
|
||||||
self.controller = controller
|
self.controller = controller
|
||||||
self.refs_to_update = []
|
self.refs_to_update = []
|
||||||
self.updated_apps = None
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
self.updated_apps = self.controller.update(self.refs_to_update)
|
|
||||||
self.signal.emit()
|
for app_ref in self.refs_to_update:
|
||||||
|
for output in self.controller.update(app_ref):
|
||||||
|
line = output.decode().strip()
|
||||||
|
if line:
|
||||||
|
self.signal_output.emit(line)
|
||||||
|
|
||||||
|
self.signal_finished.emit()
|
||||||
|
|
||||||
|
|
||||||
class RefreshApps(QThread):
|
class RefreshApps(QThread):
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -15,7 +15,7 @@ with open(file_dir + '/requirements.txt', 'r') as f:
|
|||||||
requirements = [line.strip() for line in f.readlines() if line]
|
requirements = [line.strip() for line in f.readlines() if line]
|
||||||
|
|
||||||
|
|
||||||
with open(file_dir + '/fpakman/core/__init__.py', 'r') as f:
|
with open(file_dir + '/fpakman/__init__.py', 'r') as f:
|
||||||
exec(f.readlines()[0])
|
exec(f.readlines()[0])
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user