mirror of
https://github.com/spalencsar/bearhub.git
synced 2026-07-07 00:04:15 +02:00
search and install
This commit is contained in:
@@ -6,8 +6,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [0.3.0] - 2019-06-XX
|
||||
### Features
|
||||
- Allows to retrieve app information and history by right clicking it.
|
||||
- Allows app uninstall and downgrade by right clicking it.
|
||||
- Applications search
|
||||
- Now when you right-click a selected application you can:
|
||||
- retrieve its information
|
||||
- retrieve its commit history
|
||||
- downgrade
|
||||
- install it
|
||||
- "About" window available when right-clicking the tray icon.
|
||||
|
||||
### Improvements
|
||||
@@ -18,7 +22,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- Showing runtime apps when no app is available
|
||||
- Allowing to specify a custom app translation with the environment variable **FPAKMAN_LOCALE**
|
||||
- Adding expiration time for cached app data. Default to 1 hour. The environment variable **FPAKMAN_CACHE_EXPIRATION** can change this value.
|
||||
- Retrieving only the installed applications data from the origin API.
|
||||
- Minor GUI improvements
|
||||
|
||||
## [0.2.1] - 2019-06-24
|
||||
|
||||
@@ -25,6 +25,7 @@ manager = FlatpakManager(cache_expire=int(os.getenv('FPAKMAN_CACHE_EXPIRATION',
|
||||
trayIcon = TrayIcon(locale_keys=locale_keys,
|
||||
manager=manager,
|
||||
check_interval=int(os.getenv('FPAKMAN_CHECK_INTERVAL', 60)))
|
||||
trayIcon.load_database()
|
||||
trayIcon.show()
|
||||
|
||||
sys.exit(app.exec_())
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from datetime import datetime, timedelta
|
||||
from threading import Lock, Thread
|
||||
from threading import Lock
|
||||
from typing import List
|
||||
|
||||
import requests
|
||||
@@ -19,17 +19,12 @@ class FlatpakManager:
|
||||
self.lock_db_read = Lock()
|
||||
self.lock_read = Lock()
|
||||
|
||||
# TODO remove if not necessary for future releases
|
||||
def load_full_database_async(self):
|
||||
Thread(target=self.load_full_database, daemon=True).start()
|
||||
|
||||
# TODO remove if not necessary for future releases
|
||||
def load_full_database(self):
|
||||
|
||||
self.lock_db_read.acquire()
|
||||
|
||||
try:
|
||||
res = self.http_session.get(__FLATHUB_API_URL__ + '/apps')
|
||||
res = self.http_session.get(__FLATHUB_API_URL__ + '/apps', timeout=30)
|
||||
|
||||
if res.status_code == 200:
|
||||
for app in res.json():
|
||||
@@ -40,7 +35,7 @@ class FlatpakManager:
|
||||
def _request_app_data(self, app_id: str):
|
||||
|
||||
try:
|
||||
res = self.http_session.get('{}/apps/{}'.format(__FLATHUB_API_URL__, app_id), timeout=60)
|
||||
res = self.http_session.get('{}/apps/{}'.format(__FLATHUB_API_URL__, app_id), timeout=30)
|
||||
|
||||
if res.status_code == 200:
|
||||
return res.json()
|
||||
@@ -50,6 +45,58 @@ class FlatpakManager:
|
||||
print("Could not retrieve app data for id '{}'. Timeout".format(app_id))
|
||||
return None
|
||||
|
||||
def _fill_api_data(self, app: dict):
|
||||
|
||||
api_data = self.cache_apps.get(app['id'])
|
||||
|
||||
if (not app['runtime'] and not api_data) or (api_data and api_data.get('expires_at') and api_data['expires_at'] <= datetime.utcnow()): # if api data is not cached or expired, tries to retrieve it
|
||||
api_data = self._request_app_data(app['id'])
|
||||
|
||||
if api_data:
|
||||
api_data['expires_at'] = datetime.utcnow() + timedelta(seconds=self.cache_expire)
|
||||
self.cache_apps[app['id']] = api_data
|
||||
|
||||
if not api_data:
|
||||
for attr in ('latest_version', 'icon', 'description'):
|
||||
if attr not in app:
|
||||
app[attr] = None
|
||||
else:
|
||||
app['latest_version'] = api_data.get('currentReleaseVersion')
|
||||
app['icon'] = api_data.get('iconMobileUrl')
|
||||
|
||||
for attr in ('name', 'description'):
|
||||
if not app.get(attr):
|
||||
app[attr] = api_data.get(attr)
|
||||
|
||||
if app['icon'].startswith('/'):
|
||||
app['icon'] = __FLATHUB_URL__ + app['icon']
|
||||
|
||||
def search(self, word: str) -> List[dict]:
|
||||
|
||||
res = []
|
||||
apps_found = flatpak.search(word)
|
||||
|
||||
if apps_found:
|
||||
|
||||
already_read = set()
|
||||
installed_apps = self.read_installed()
|
||||
|
||||
if installed_apps:
|
||||
for app in apps_found:
|
||||
for installed_app in installed_apps:
|
||||
if app['id'] == installed_app['id']:
|
||||
res.append(installed_app)
|
||||
already_read.add(app['id'])
|
||||
|
||||
for app in apps_found:
|
||||
if app['id'] not in already_read:
|
||||
app['update'] = False
|
||||
app['installed'] = False
|
||||
self._fill_api_data(app)
|
||||
res.append(app)
|
||||
|
||||
return res
|
||||
|
||||
def read_installed(self) -> List[dict]:
|
||||
|
||||
self.lock_read.acquire()
|
||||
@@ -63,25 +110,9 @@ class FlatpakManager:
|
||||
available_updates = flatpak.list_updates_as_str()
|
||||
|
||||
for app in installed:
|
||||
|
||||
app_data = self.cache_apps.get(app['id'])
|
||||
|
||||
if (not app['runtime'] and not app_data) or (app_data and app_data['expires_at'] <= datetime.utcnow()): # if data is not cached or expired, tries to retrieve it
|
||||
app_data = self._request_app_data(app['id'])
|
||||
app_data['expires_at'] = datetime.utcnow() + timedelta(seconds=self.cache_expire)
|
||||
self.cache_apps[app['id']] = app_data
|
||||
|
||||
if not app_data:
|
||||
app['latest_version'] = None
|
||||
app['icon'] = None
|
||||
else:
|
||||
app['latest_version'] = app_data['currentReleaseVersion']
|
||||
app['icon'] = app_data['iconMobileUrl']
|
||||
|
||||
if app['icon'].startswith('/'):
|
||||
app['icon'] = __FLATHUB_URL__ + app['icon']
|
||||
|
||||
self._fill_api_data(app)
|
||||
app['update'] = app['id'] in available_updates
|
||||
app['installed'] = True
|
||||
|
||||
return installed
|
||||
|
||||
|
||||
@@ -147,3 +147,67 @@ def get_app_commits_data(app_ref: str, origin: str) -> List[dict]:
|
||||
commit = {}
|
||||
|
||||
return commits
|
||||
|
||||
|
||||
def search(word: str) -> List[dict]:
|
||||
cli_version = get_version()
|
||||
|
||||
res = system.run_cmd('{} search {}'.format(BASE_CMD, word))
|
||||
|
||||
found = []
|
||||
|
||||
split_res = res.split('\n')
|
||||
|
||||
if split_res and split_res[0].lower() != 'no matches found':
|
||||
for info in split_res:
|
||||
if info:
|
||||
info_list = info.split('\t')
|
||||
|
||||
if cli_version >= '1.3.0':
|
||||
version = info_list[3].strip()
|
||||
found.append({
|
||||
'name': info_list[0].strip(),
|
||||
'description': info_list[1].strip(),
|
||||
'id': info_list[2].strip(),
|
||||
'version': version,
|
||||
'latest_version': version,
|
||||
'branch': info_list[4].strip(),
|
||||
'origin': info_list[5].strip(),
|
||||
'runtime': False,
|
||||
'arch': None, # unknown at this moment,
|
||||
'ref': None # unknown at this moment
|
||||
})
|
||||
elif cli_version >= '1.2.0':
|
||||
desc = info_list[0].split('-')
|
||||
version = info_list[2].strip()
|
||||
found.append({
|
||||
'name': desc[0].strip(),
|
||||
'description': desc[1].strip(),
|
||||
'id': info_list[1].strip(),
|
||||
'version': version,
|
||||
'latest_version': version,
|
||||
'branch': info_list[3].strip(),
|
||||
'origin': info_list[4].strip(),
|
||||
'runtime': False,
|
||||
'arch': None, # unknown at this moment,
|
||||
'ref': None # unknown at this moment
|
||||
})
|
||||
else:
|
||||
version = info_list[1].strip()
|
||||
found.append({
|
||||
'name': '',
|
||||
'description': info_list[4].strip(),
|
||||
'id': info_list[0].strip(),
|
||||
'version': version,
|
||||
'latest_version': version,
|
||||
'branch': info_list[2].strip(),
|
||||
'origin': info_list[3].strip(),
|
||||
'runtime': False,
|
||||
'arch': None, # unknown at this moment,
|
||||
'ref': None # unknown at this moment
|
||||
})
|
||||
return found
|
||||
|
||||
|
||||
def install_and_stream(app_id: str, origin: str):
|
||||
return system.stream_cmd([BASE_CMD, 'install', origin, app_id, '-y'])
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import os
|
||||
import subprocess
|
||||
from typing import List
|
||||
|
||||
from fpakman.core import resource
|
||||
|
||||
|
||||
def run_cmd(cmd: str, expected_code: int = 0, ignore_return_code: bool = False) -> str:
|
||||
res = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, env={'LANG': 'en'})
|
||||
@@ -9,3 +12,8 @@ def run_cmd(cmd: str, expected_code: int = 0, ignore_return_code: bool = False)
|
||||
|
||||
def stream_cmd(cmd: List[str]):
|
||||
return subprocess.Popen(cmd, stdout=subprocess.PIPE, env={'LANG': 'en'}).stdout
|
||||
|
||||
|
||||
def notify_user(msg: str, icon_path: str = resource.get_path('img/flathub_45.svg')):
|
||||
if bool(os.getenv('FPAKMAN_UPDATE_NOTIFICATION', 1)):
|
||||
os.system("notify-send {} '{}'".format("-i {}".format(icon_path) if icon_path else '', msg))
|
||||
|
||||
@@ -2,6 +2,9 @@ import locale
|
||||
|
||||
from fpakman.core import resource
|
||||
import glob
|
||||
import re
|
||||
|
||||
HTML_RE = re.compile(r'<[^>]+>')
|
||||
|
||||
|
||||
def get_locale_keys(key: str = None):
|
||||
@@ -38,3 +41,7 @@ def get_locale_keys(key: str = None):
|
||||
locale_obj[keyval[0].strip()] = keyval[1].strip()
|
||||
|
||||
return locale_obj
|
||||
|
||||
|
||||
def strip_html(string: str):
|
||||
return HTML_RE.sub('', string)
|
||||
|
||||
120
fpakman/resources/img/install.svg
Executable file
120
fpakman/resources/img/install.svg
Executable file
@@ -0,0 +1,120 @@
|
||||
<?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: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="48"
|
||||
height="48"
|
||||
viewBox="0 0 48 47.999999"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="install.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"><metadata
|
||||
id="metadata135"><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="defs133" /><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="namedview131"
|
||||
showgrid="false"
|
||||
showborder="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="0.67615769"
|
||||
inkscape:cx="286.91482"
|
||||
inkscape:cy="174.51451"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="260"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Capa_1" />
|
||||
<g
|
||||
id="g98"
|
||||
transform="scale(0.137524)"
|
||||
style="fill:#00ff00">
|
||||
<path
|
||||
d="m 349.03,141.226 v 66.579 c 0,5.012 -4.061,9.079 -9.079,9.079 H 216.884 v 123.067 c 0,5.019 -4.067,9.079 -9.079,9.079 h -66.579 c -5.009,0 -9.079,-4.061 -9.079,-9.079 V 216.884 H 9.079 C 4.063,216.884 0,212.817 0,207.805 v -66.579 c 0,-5.013 4.063,-9.079 9.079,-9.079 H 132.147 V 9.079 C 132.147,4.061 136.216,0 141.226,0 h 66.579 c 5.012,0 9.079,4.061 9.079,9.079 v 123.068 h 123.067 c 5.019,0 9.079,4.066 9.079,9.079 z"
|
||||
id="path96"
|
||||
inkscape:connector-curvature="0"
|
||||
style="fill:#00ff00" />
|
||||
</g>
|
||||
<g
|
||||
id="g100"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g102"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g104"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g106"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g108"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g110"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g112"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g114"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g116"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g118"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g120"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g122"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g124"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g126"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
<g
|
||||
id="g128"
|
||||
transform="translate(0,-301.03)">
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.0 KiB |
120
fpakman/resources/img/search.svg
Executable file
120
fpakman/resources/img/search.svg
Executable file
@@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 18.1.1, 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: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"
|
||||
viewBox="0 0 12 12"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="search.svg"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
width="12"
|
||||
height="12"><metadata
|
||||
id="metadata126"><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="defs124" /><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="namedview122"
|
||||
showgrid="false"
|
||||
showborder="false"
|
||||
inkscape:zoom="0.53133476"
|
||||
inkscape:cx="834.65593"
|
||||
inkscape:cy="-101.88082"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="260"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Capa_1"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" />
|
||||
<g
|
||||
id="Search"
|
||||
transform="scale(0.04794017)"
|
||||
style="fill:#999999">
|
||||
<path
|
||||
style="clip-rule:evenodd;fill:#999999;fill-rule:evenodd"
|
||||
d="m 244.186,214.604 -54.379,-54.378 c -0.289,-0.289 -0.628,-0.491 -0.93,-0.76 10.7,-16.231 16.945,-35.66 16.945,-56.554 C 205.822,46.075 159.747,0 102.911,0 46.075,0 0,46.075 0,102.911 c 0,56.835 46.074,102.911 102.91,102.911 20.895,0 40.323,-6.245 56.554,-16.945 0.269,0.301 0.47,0.64 0.759,0.929 l 54.38,54.38 c 8.169,8.168 21.413,8.168 29.583,0 8.168,-8.169 8.168,-21.413 0,-29.582 z M 102.911,170.146 c -37.134,0 -67.236,-30.102 -67.236,-67.235 0,-37.134 30.103,-67.236 67.236,-67.236 37.132,0 67.235,30.103 67.235,67.236 0,37.133 -30.103,67.235 -67.235,67.235 z"
|
||||
id="path88"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g91"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g93"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g95"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g97"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g99"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g101"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g103"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g105"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g107"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g109"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g111"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g113"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g115"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g117"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
<g
|
||||
id="g119"
|
||||
transform="translate(0,-238.312)">
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.2 KiB |
@@ -1,5 +1,6 @@
|
||||
manage_window.title=Flatpak Application Manager
|
||||
manage_window.columns.latest_version=Latest Version
|
||||
manage_window.columns.installed=Installed
|
||||
manage_window.columns.update=Upgrade ?
|
||||
manage_window.apps_table.row.actions.info=Information
|
||||
manage_window.apps_table.row.actions.history=History
|
||||
@@ -8,8 +9,11 @@ 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.downgrade=Downgrade
|
||||
manage_window.apps_table.row.actions.downgrade.popup.body=Do you really want to downgrade {} ?
|
||||
manage_window.apps_table.row.actions.install=Install
|
||||
manage_window.apps_table.upgrade_toggle.tooltip=Click it to check or uncheck the update
|
||||
manage_window.checkbox.only_apps=Apps
|
||||
window_manage.input_search.placeholder=Search
|
||||
window_manage.input_search.tooltip=Type and press ENTER to search for applications
|
||||
manage_window.label.updates=Updates
|
||||
manage_window.status.refreshing=Refreshing
|
||||
manage_window.status.upgrading=Upgrading
|
||||
@@ -17,6 +21,8 @@ manage_window.status.uninstalling=Uninstalling
|
||||
manage_window.status.downgrading=Downgrading
|
||||
manage_window.status.info=Retrieving information
|
||||
manage_window.status.history=Retrieving history
|
||||
manage_window.status.searching=Searching
|
||||
manage_window.status.installing=Installing
|
||||
manage_window.bt.refresh.tooltip=Reload the data about installed applications
|
||||
manage_window.bt.upgrade.tooltip=Upgrade all selected applications
|
||||
popup.flatpak_not_installed.title=Error
|
||||
@@ -35,12 +41,14 @@ popup.button.cancel=Cancel
|
||||
tray.action.manage=Manage applications
|
||||
tray.action.exit=Exit
|
||||
tray.action.about=About
|
||||
tray.action.refreshing=Refreshing
|
||||
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.description=description
|
||||
flatpak.info.id=id
|
||||
flatpak.info.installation=installation
|
||||
flatpak.info.installed=installed
|
||||
@@ -58,3 +66,5 @@ about.info.desc=Non-official Flatpak application management graphical interface
|
||||
about.info.link=More information at
|
||||
about.info.license=Free license
|
||||
about.info.rate=If this tool is useful for you, give it a star on Github to keep it up
|
||||
yes=yes
|
||||
no=no
|
||||
@@ -1,6 +1,7 @@
|
||||
manage_window.title=Administrador de Aplicativos Flatpak
|
||||
manage_window.columns.latest_version=Ultima Versión
|
||||
manage_window.columns.update=Actualizar ?
|
||||
manage_window.columns.installed=Instalado
|
||||
manage_window.apps_table.row.actions.info=Información
|
||||
manage_window.apps_table.row.actions.history=Historia
|
||||
manage_window.apps_table.row.actions.uninstall=Desinstalar
|
||||
@@ -8,8 +9,11 @@ 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.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.install=Instalar
|
||||
manage_window.apps_table.upgrade_toggle.tooltip=Haz clic para marcar o desmarcar la actualización
|
||||
manage_window.checkbox.only_apps=Aplicativos
|
||||
window_manage.input_search.placeholder=Buscar
|
||||
window_manage.input_search.tooltip=Escriba y oprima ENTER para buscar aplicativos
|
||||
manage_window.label.updates=Actualizaciones
|
||||
manage_window.status.refreshing=Recargando
|
||||
manage_window.status.upgrading=Actualizando
|
||||
@@ -17,6 +21,8 @@ manage_window.status.uninstalling=Desinstalando
|
||||
manage_window.status.downgrading=Revirtiendo
|
||||
manage_window.status.info=Obteniendo información
|
||||
manage_window.status.history=Obteniendo la historia
|
||||
manage_window.status.searching=Buscando
|
||||
manage_window.status.installing=Instalando
|
||||
manage_window.bt.refresh.tooltip=Recarga los datos sobre los aplicativos instalados
|
||||
manage_window.bt.upgrade.tooltip=Actualiza todos los aplicativos seleccionados
|
||||
popup.flatpak_not_installed.title=Error
|
||||
@@ -35,12 +41,14 @@ popup.button.cancel=Cancelar
|
||||
tray.action.manage=Administrar aplicativos
|
||||
tray.action.exit=Salir
|
||||
tray.action.about=Sobre
|
||||
tray.action.refreshing=Recargando
|
||||
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.description=descripción
|
||||
flatpak.info.id=id
|
||||
flatpak.info.installation=instalación
|
||||
flatpak.info.installed=instalado
|
||||
@@ -58,3 +66,5 @@ about.info.desc=Interfaz grafica no oficial para administración de aplicativos
|
||||
about.info.link=Mas informaciones en
|
||||
about.info.license=Licencia gratuita
|
||||
about.info.rate=Si esta herramienta es útil para ti, dale una estrella en Github para mantenerla
|
||||
yes=sí
|
||||
no=no
|
||||
@@ -1,6 +1,7 @@
|
||||
manage_window.title=Gerenciador de Aplicativos Flatpak
|
||||
manage_window.columns.latest_version=Última Versão
|
||||
manage_window.columns.update=Atualizar ?
|
||||
manage_window.columns.installed=Instalado
|
||||
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
|
||||
@@ -8,8 +9,11 @@ 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.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.install=Instalar
|
||||
manage_window.apps_table.upgrade_toggle.tooltip=Clique para marcar ou desmarcar a atualização
|
||||
manage_window.checkbox.only_apps=Aplicativos
|
||||
window_manage.input_search.placeholder=Buscar
|
||||
window_manage.input_search.tooltip=Digite e pressione ENTER para buscar aplicativos
|
||||
manage_window.label.updates=Atualizações
|
||||
manage_window.status.refreshing=Recarregando
|
||||
manage_window.status.upgrading=Atualizando
|
||||
@@ -17,6 +21,8 @@ manage_window.status.uninstalling=Desinstalando
|
||||
manage_window.status.downgrading=Revertendo
|
||||
manage_window.status.info=Obtendo informação
|
||||
manage_window.status.history=Obtendo histórico
|
||||
manage_window.status.searching=Buscando
|
||||
manage_window.status.installing=Instalando
|
||||
manage_window.bt.refresh.tooltip=Recarrega os dados sobre os aplicativos instalados
|
||||
manage_window.bt.upgrade.tooltip=Atualiza todos os aplicativos selecionados
|
||||
popup.flatpak_not_installed.title=Erro
|
||||
@@ -35,12 +41,14 @@ popup.button.cancel=Cancelar
|
||||
tray.action.manage=Gerenciar aplicativos
|
||||
tray.action.exit=Sair
|
||||
tray.action.about=Sobre
|
||||
tray.action.refreshing=Recarregando
|
||||
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.description=descrição
|
||||
flatpak.info.id=id
|
||||
flatpak.info.installation=instalação
|
||||
flatpak.info.installed=instalado
|
||||
@@ -58,3 +66,5 @@ about.info.desc=Interface gráfica não oficial para gerenciamento de aplicativo
|
||||
about.info.link=Mais informações em
|
||||
about.info.license=Licença gratuita
|
||||
about.info.rate=Se essa ferramenta é útil para você, dê uma estrela no Github para mantê-la de pé
|
||||
yes=sim
|
||||
no=não
|
||||
@@ -6,7 +6,7 @@ from PyQt5.QtNetwork import QNetworkRequest, QNetworkAccessManager
|
||||
from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \
|
||||
QHeaderView
|
||||
|
||||
from fpakman.core import resource
|
||||
from fpakman.core import resource, util
|
||||
from fpakman.view.qt import dialog
|
||||
|
||||
|
||||
@@ -44,8 +44,9 @@ class AppsTable(QTableWidget):
|
||||
'manage_window.columns.latest_version',
|
||||
'flatpak.info.branch',
|
||||
'flatpak.info.arch',
|
||||
'flatpak.info.ref',
|
||||
'flatpak.info.id',
|
||||
'flatpak.info.origin',
|
||||
'manage_window.columns.installed',
|
||||
'manage_window.columns.update']]
|
||||
self.setColumnCount(len(self.column_names))
|
||||
self.setFocusPolicy(Qt.NoFocus)
|
||||
@@ -62,10 +63,14 @@ class AppsTable(QTableWidget):
|
||||
self.icon_cache = {}
|
||||
|
||||
def contextMenuEvent(self, QContextMenuEvent): # selected row right click event
|
||||
napps = len([app for app in self.window.apps if not app['model']['runtime']])
|
||||
|
||||
app = self.get_selected_app()
|
||||
|
||||
menu_row = QMenu()
|
||||
|
||||
if app['model']['installed']:
|
||||
napps = len([app for app in self.window.apps if not app['model']['runtime']])
|
||||
|
||||
action_info = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.info"])
|
||||
action_info.setIcon(QIcon(resource.get_path('img/info.svg')))
|
||||
action_info.triggered.connect(self._get_app_info)
|
||||
@@ -76,8 +81,6 @@ class AppsTable(QTableWidget):
|
||||
action_history.triggered.connect(self._get_app_history)
|
||||
menu_row.addAction(action_history)
|
||||
|
||||
app = self.get_selected_app()
|
||||
|
||||
action_uninstall = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.uninstall"])
|
||||
action_uninstall.setIcon(QIcon(resource.get_path('img/uninstall.svg')))
|
||||
action_uninstall.triggered.connect(self._uninstall_app)
|
||||
@@ -89,6 +92,11 @@ class AppsTable(QTableWidget):
|
||||
action_downgrade.triggered.connect(self._downgrade_app)
|
||||
action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
|
||||
menu_row.addAction(action_downgrade)
|
||||
else:
|
||||
action_install = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.install"])
|
||||
action_install.setIcon(QIcon(resource.get_path('img/install.svg')))
|
||||
action_install.triggered.connect(self._install_app)
|
||||
menu_row.addAction(action_install)
|
||||
|
||||
menu_row.adjustSize()
|
||||
menu_row.popup(QCursor.pos())
|
||||
@@ -122,6 +130,9 @@ class AppsTable(QTableWidget):
|
||||
def _get_app_history(self):
|
||||
self.window.get_app_history(self.get_selected_app())
|
||||
|
||||
def _install_app(self):
|
||||
self.window.install_app(self.get_selected_app())
|
||||
|
||||
def _load_icon(self, http_response):
|
||||
icon_url = http_response.url().toString()
|
||||
pixmap = QPixmap()
|
||||
@@ -142,9 +153,12 @@ class AppsTable(QTableWidget):
|
||||
if apps:
|
||||
for idx, app in enumerate(apps):
|
||||
|
||||
tooltip = util.strip_html(app['model']['description']) if app['model']['description'] else None
|
||||
|
||||
col_name = QTableWidgetItem()
|
||||
col_name.setText(app['model']['name'])
|
||||
col_name.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_name.setToolTip(tooltip)
|
||||
|
||||
if not app['model']['icon']:
|
||||
col_name.setIcon(self.icon_flathub)
|
||||
@@ -162,11 +176,13 @@ class AppsTable(QTableWidget):
|
||||
col_version = QTableWidgetItem()
|
||||
col_version.setText(app['model']['version'])
|
||||
col_version.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_version.setToolTip(tooltip)
|
||||
self.setItem(idx, 1, col_version)
|
||||
|
||||
col_release = QTableWidgetItem()
|
||||
col_release.setText(app['model']['latest_version'])
|
||||
col_release.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_release.setToolTip(tooltip)
|
||||
self.setItem(idx, 2, col_release)
|
||||
|
||||
if app['model']['version'] and app['model']['latest_version'] and app['model']['version'] < app['model']['latest_version']:
|
||||
@@ -175,25 +191,38 @@ class AppsTable(QTableWidget):
|
||||
col_branch = QTableWidgetItem()
|
||||
col_branch.setText(app['model']['branch'])
|
||||
col_branch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_branch.setToolTip(tooltip)
|
||||
self.setItem(idx, 3, col_branch)
|
||||
|
||||
col_arch = QTableWidgetItem()
|
||||
col_arch.setText(app['model']['arch'])
|
||||
col_arch.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_arch.setToolTip(tooltip)
|
||||
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_id = QTableWidgetItem()
|
||||
col_id.setText(app['model']['id'])
|
||||
col_id.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_id.setToolTip(tooltip)
|
||||
self.setItem(idx, 5, col_id)
|
||||
|
||||
col_origin = QTableWidgetItem()
|
||||
col_origin.setText(app['model']['origin'])
|
||||
col_origin.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_origin.setToolTip(tooltip)
|
||||
self.setItem(idx, 6, col_origin)
|
||||
|
||||
col_installed = QTableWidgetItem()
|
||||
col_installed.setText(self.parent().locale_keys['yes'] if app['model']['installed'] else self.parent().locale_keys['no'])
|
||||
col_installed.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
|
||||
col_installed.setTextAlignment(Qt.AlignCenter)
|
||||
col_installed.setToolTip(tooltip)
|
||||
col_installed.setForeground(Qt.blue if app['model']['installed'] else Qt.red)
|
||||
|
||||
self.setItem(idx, 7, col_installed)
|
||||
|
||||
col_update = UpdateToggleButton(app, self.window, self.window.locale_keys, app['model']['update']) if app['model']['update'] else None
|
||||
self.setCellWidget(idx, 7, col_update)
|
||||
self.setCellWidget(idx, 8, col_update)
|
||||
|
||||
def change_headers_policy(self, policy: QHeaderView = QHeaderView.ResizeToContents):
|
||||
header_horizontal = self.horizontalHeader()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QFormLayout, QGroupBox, \
|
||||
QLineEdit, QLabel
|
||||
QLineEdit, QLabel, QPlainTextEdit
|
||||
|
||||
|
||||
class InfoDialog(QDialog):
|
||||
@@ -19,12 +19,17 @@ class InfoDialog(QDialog):
|
||||
|
||||
for attr in sorted(app.keys()):
|
||||
|
||||
if attr != 'name':
|
||||
if attr != 'name' and app[attr]:
|
||||
if attr == 'description':
|
||||
text = QPlainTextEdit()
|
||||
text.appendHtml(app[attr])
|
||||
else:
|
||||
text = QLineEdit()
|
||||
text.setText(app[attr])
|
||||
text.setStyleSheet("width: 400px")
|
||||
text.setReadOnly(True)
|
||||
text.setCursorPosition(0)
|
||||
text.setStyleSheet("width: 400px")
|
||||
|
||||
text.setReadOnly(True)
|
||||
|
||||
label = QLabel("{}: ".format(locale_keys.get('flatpak.info.' + attr, attr)).capitalize())
|
||||
label.setStyleSheet("font-weight: bold")
|
||||
|
||||
@@ -6,7 +6,7 @@ from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QSystemTrayIcon, QMenu
|
||||
from fpakman.core.controller import FlatpakManager
|
||||
|
||||
from fpakman.core import resource
|
||||
from fpakman.core import resource, system
|
||||
from fpakman.view.qt.about import AboutDialog
|
||||
from fpakman.view.qt.window import ManageWindow
|
||||
|
||||
@@ -33,6 +33,19 @@ class UpdateCheck(QThread):
|
||||
time.sleep(self.check_interval)
|
||||
|
||||
|
||||
class LoadDatabase(QThread):
|
||||
|
||||
signal_finished = pyqtSignal()
|
||||
|
||||
def __init__(self, manager: FlatpakManager, parent=None):
|
||||
super(LoadDatabase, self).__init__(parent)
|
||||
self.manager = manager
|
||||
|
||||
def run(self):
|
||||
self.manager.load_full_database()
|
||||
self.signal_finished.emit()
|
||||
|
||||
|
||||
class TrayIcon(QSystemTrayIcon):
|
||||
|
||||
def __init__(self, locale_keys: dict, manager: FlatpakManager, check_interval: int = 60):
|
||||
@@ -46,8 +59,12 @@ class TrayIcon(QSystemTrayIcon):
|
||||
|
||||
self.menu = QMenu()
|
||||
|
||||
self.action_refreshing = self.menu.addAction(self.locale_keys['tray.action.refreshing'] + '...')
|
||||
self.action_refreshing.setEnabled(False)
|
||||
|
||||
self.action_manage = self.menu.addAction(self.locale_keys['tray.action.manage'])
|
||||
self.action_manage.triggered.connect(self.show_manage_window)
|
||||
self.action_manage.setVisible(False)
|
||||
|
||||
self.action_about = self.menu.addAction(self.locale_keys['tray.action.about'])
|
||||
self.action_about.triggered.connect(self.show_about)
|
||||
@@ -64,6 +81,16 @@ class TrayIcon(QSystemTrayIcon):
|
||||
|
||||
self.dialog_about = AboutDialog(self.locale_keys)
|
||||
|
||||
self.thread_database = LoadDatabase(manager)
|
||||
self.thread_database.signal_finished.connect(self._update_menu)
|
||||
|
||||
def load_database(self):
|
||||
self.thread_database.start()
|
||||
|
||||
def _update_menu(self):
|
||||
self.action_refreshing.setVisible(False)
|
||||
self.action_manage.setVisible(True)
|
||||
|
||||
def notify_updates(self, updates: int):
|
||||
if updates > 0:
|
||||
if self.icon().cacheKey() != self.icon_update.cacheKey():
|
||||
@@ -72,11 +99,7 @@ class TrayIcon(QSystemTrayIcon):
|
||||
msg = '{}: {}'.format(self.locale_keys['notification.new_updates'], updates)
|
||||
self.setToolTip(msg)
|
||||
|
||||
if bool(os.getenv('FPAKMAN_UPDATE_NOTIFICATION', 1)):
|
||||
os.system("notify-send -i {} '{}'".format(resource.get_path('img/flathub_45.svg'), msg))
|
||||
|
||||
if self.manage_window:
|
||||
self.manage_window.refresh()
|
||||
system.notify_user(msg)
|
||||
|
||||
else:
|
||||
self.setIcon(self.icon_default)
|
||||
|
||||
@@ -97,6 +97,7 @@ class GetAppInfo(QThread):
|
||||
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'
|
||||
app_info['description'] = self.app['model']['description']
|
||||
self.signal_finished.emit(app_info)
|
||||
self.app = None
|
||||
|
||||
@@ -113,3 +114,42 @@ class GetAppHistory(QThread):
|
||||
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
|
||||
|
||||
|
||||
class SearchApps(QThread):
|
||||
signal_finished = pyqtSignal(list)
|
||||
|
||||
def __init__(self, manager: FlatpakManager):
|
||||
super(SearchApps, self).__init__()
|
||||
self.word = None
|
||||
self.manager = manager
|
||||
|
||||
def run(self):
|
||||
apps_found = []
|
||||
|
||||
if self.word:
|
||||
apps_found = self.manager.search(self.word)
|
||||
|
||||
self.signal_finished.emit(apps_found)
|
||||
self.word = None
|
||||
|
||||
|
||||
class InstallApp(QThread):
|
||||
|
||||
signal_finished = pyqtSignal()
|
||||
signal_output = pyqtSignal(str)
|
||||
|
||||
def __init__(self):
|
||||
super(InstallApp, self).__init__()
|
||||
self.app = None
|
||||
|
||||
def run(self):
|
||||
|
||||
if self.app:
|
||||
for output in flatpak.install_and_stream(self.app['model']['id'], self.app['model']['origin']):
|
||||
line = output.decode().strip()
|
||||
if line:
|
||||
self.signal_output.emit(line)
|
||||
|
||||
self.app = None
|
||||
self.signal_finished.emit()
|
||||
|
||||
@@ -4,9 +4,9 @@ from threading import Lock
|
||||
from typing import List
|
||||
|
||||
from PyQt5.QtCore import QEvent
|
||||
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent
|
||||
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap
|
||||
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \
|
||||
QSizePolicy, QLabel, QPlainTextEdit
|
||||
QSizePolicy, QLabel, QPlainTextEdit, QLineEdit
|
||||
|
||||
from fpakman.core import resource, flatpak
|
||||
from fpakman.core.controller import FlatpakManager
|
||||
@@ -16,7 +16,7 @@ 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.thread import UpdateSelectedApps, RefreshApps, UninstallApp, DowngradeApp, GetAppInfo, \
|
||||
GetAppHistory
|
||||
GetAppHistory, SearchApps, InstallApp
|
||||
|
||||
|
||||
class ManageWindow(QWidget):
|
||||
@@ -42,12 +42,43 @@ class ManageWindow(QWidget):
|
||||
self.layout = QVBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.toolbar_search = QToolBar()
|
||||
self.toolbar_search.setStyleSheet("spacing: 0px;")
|
||||
self.toolbar_search.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
spacer = QWidget()
|
||||
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
|
||||
self.toolbar_search.addWidget(spacer)
|
||||
|
||||
label_pre_search = QLabel()
|
||||
label_pre_search.setStyleSheet("background: white; border-top-left-radius: 5px; border-bottom-left-radius: 5px;")
|
||||
self.toolbar_search.addWidget(label_pre_search)
|
||||
|
||||
self.input_search = QLineEdit()
|
||||
self.input_search.setFrame(False)
|
||||
self.input_search.setPlaceholderText(self.locale_keys['window_manage.input_search.placeholder']+"...")
|
||||
self.input_search.setToolTip(self.locale_keys['window_manage.input_search.tooltip'])
|
||||
self.input_search.setStyleSheet("QLineEdit { background-color: white; color: grey; spacing: 0;}")
|
||||
self.input_search.returnPressed.connect(self.search)
|
||||
self.toolbar_search.addWidget(self.input_search)
|
||||
|
||||
label_pos_search = QLabel()
|
||||
label_pos_search.setPixmap(QPixmap(resource.get_path('img/search.svg')))
|
||||
label_pos_search.setStyleSheet("background: white; padding-right: 10px; border-top-right-radius: 5px; border-bottom-right-radius: 5px;")
|
||||
self.toolbar_search.addWidget(label_pos_search)
|
||||
|
||||
spacer = QWidget()
|
||||
spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||
self.toolbar_search.addWidget(spacer)
|
||||
self.layout.addWidget(self.toolbar_search)
|
||||
|
||||
toolbar = QToolBar()
|
||||
|
||||
self.checkbox_only_apps = QCheckBox()
|
||||
self.checkbox_only_apps.setText(self.locale_keys['manage_window.checkbox.only_apps'])
|
||||
self.checkbox_only_apps.setChecked(True)
|
||||
self.checkbox_only_apps.stateChanged.connect(self.filter_only_apps)
|
||||
|
||||
toolbar = QToolBar()
|
||||
toolbar.addWidget(self.checkbox_only_apps)
|
||||
|
||||
spacer = QWidget()
|
||||
@@ -56,7 +87,7 @@ class ManageWindow(QWidget):
|
||||
|
||||
self.label_status = QLabel()
|
||||
self.label_status.setText('')
|
||||
self.label_status.setStyleSheet("color: orange")
|
||||
self.label_status.setStyleSheet("color: orange; font-weight: bold")
|
||||
toolbar.addWidget(self.label_status)
|
||||
|
||||
spacer = QWidget()
|
||||
@@ -111,6 +142,13 @@ class ManageWindow(QWidget):
|
||||
self.thread_get_history = GetAppHistory()
|
||||
self.thread_get_history.signal_finished.connect(self._finish_get_history)
|
||||
|
||||
self.thread_search = SearchApps(self.manager)
|
||||
self.thread_search.signal_finished.connect(self._finish_search)
|
||||
|
||||
self.thread_install = InstallApp()
|
||||
self.thread_install.signal_output.connect(self._update_action_output)
|
||||
self.thread_install.signal_finished.connect(self._finish_install)
|
||||
|
||||
self.toolbar_bottom = QToolBar()
|
||||
self.label_updates = QLabel('')
|
||||
self.label_updates.setStyleSheet("color: red;")
|
||||
@@ -170,6 +208,14 @@ class ManageWindow(QWidget):
|
||||
|
||||
self.thread_lock.release()
|
||||
|
||||
def _hide_output(self):
|
||||
self.textarea_output.clear()
|
||||
self.textarea_output.hide()
|
||||
|
||||
def _show_output(self):
|
||||
self.textarea_output.clear()
|
||||
self.textarea_output.show()
|
||||
|
||||
def refresh(self, clear_output: bool = True):
|
||||
|
||||
if self._acquire_lock():
|
||||
@@ -177,8 +223,7 @@ class ManageWindow(QWidget):
|
||||
self._begin_action(self.locale_keys['manage_window.status.refreshing'])
|
||||
|
||||
if clear_output:
|
||||
self.textarea_output.clear()
|
||||
self.textarea_output.hide()
|
||||
self._hide_output()
|
||||
|
||||
self.thread_refresh.start()
|
||||
|
||||
@@ -321,17 +366,23 @@ class ManageWindow(QWidget):
|
||||
|
||||
def _begin_action(self, action_label: str):
|
||||
self.label_status.setText(action_label + "...")
|
||||
self.toolbar_search.setVisible(False)
|
||||
self.bt_upgrade.setEnabled(False)
|
||||
self.bt_refresh.setEnabled(False)
|
||||
self.checkbox_only_apps.setEnabled(False)
|
||||
self.table_apps.setEnabled(False)
|
||||
|
||||
def finish_action(self):
|
||||
def finish_action(self, clear_search: bool = True):
|
||||
self.bt_refresh.setEnabled(True)
|
||||
self.toolbar_search.setVisible(True)
|
||||
self.checkbox_only_apps.setEnabled(True)
|
||||
self.table_apps.setEnabled(True)
|
||||
self.input_search.setEnabled(True)
|
||||
self.label_status.setText('')
|
||||
|
||||
if clear_search:
|
||||
self.input_search.setText('')
|
||||
|
||||
def downgrade_app(self, app: dict):
|
||||
|
||||
self._check_flatpak_installed()
|
||||
@@ -387,3 +438,37 @@ class ManageWindow(QWidget):
|
||||
self.change_update_state()
|
||||
dialog_history = HistoryDialog(app, self.table_apps.get_selected_app_icon(), self.locale_keys)
|
||||
dialog_history.exec_()
|
||||
|
||||
def search(self):
|
||||
|
||||
word = self.input_search.text().strip()
|
||||
|
||||
if word and self._acquire_lock():
|
||||
self.textarea_output.clear()
|
||||
self.textarea_output.setVisible(False)
|
||||
self._begin_action(self.locale_keys['manage_window.status.searching'])
|
||||
self.thread_search.word = word
|
||||
self.thread_search.start()
|
||||
|
||||
def _finish_search(self, apps_found: List[dict]):
|
||||
|
||||
self._release_lock()
|
||||
self.finish_action(clear_search=False)
|
||||
self.update_apps(apps_found)
|
||||
|
||||
def install_app(self, app: dict):
|
||||
|
||||
self._check_flatpak_installed()
|
||||
|
||||
if self._acquire_lock():
|
||||
self._begin_action(self.locale_keys['manage_window.status.installing'])
|
||||
self._show_output()
|
||||
|
||||
self.thread_install.app = app
|
||||
self.thread_install.start()
|
||||
|
||||
def _finish_install(self):
|
||||
self.input_search.setText('')
|
||||
self.finish_action()
|
||||
self._release_lock()
|
||||
self.refresh(clear_output=False)
|
||||
|
||||
Reference in New Issue
Block a user