Merge branch 'staging' into modules

# Conflicts:
#	CHANGELOG.md
#	fpakman/__init__.py
#	fpakman/app.py
#	fpakman/core/flatpak/controller.py
#	fpakman/core/flatpak/flatpak.py
#	fpakman/core/flatpak/model.py
#	fpakman/core/snap/controller.py
#	fpakman/core/snap/snap.py
#	fpakman/resources/locale/en
#	fpakman/resources/locale/es
#	fpakman/resources/locale/pt
#	fpakman/view/qt/apps_table.py
#	fpakman/view/qt/window.py
This commit is contained in:
Vinicius Moreira
2019-08-06 18:18:36 -03:00
25 changed files with 683 additions and 421 deletions

View File

@@ -4,19 +4,30 @@ 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/).
## [0.5.0]
## [1.0.0]
### Improvements
- the app is now modularized: **fpakman** (GUI), **fpakman_api** (set of abstraction classes to extend), **fpakman_flatpak** (adds support for Flatpaks), **fpakman_snap** (adds support for Snaps)
### Comments
- env variables / arguments FPAKMAN_SNAP / FPAKMAN_FLATPAK were removed. To disable a supported type, just uninstall its module.
## [0.4.3]
## [0.5.1]
### Fixes:
- flatpak dependency
## [0.5.0] - 2019-08-06
### Improvements
- new environment variable / argument to enable / disable the tray icon and update-check daemon: FPAKMAN_TRAY (--tray)
- search results sorting takes an average of 35% less time, reaching 60% in some scenarios
- app boot takes an average of 80% less time
- showing a warning popup after initialization when no Flatpak remotes are set
- installed / uninstalled icons replaced by install / uninstall button
- check update button design changed
- app information is now available through an "Info" button
- app extra actions are now available through a "Settings" button instead of a right-click
- a confirmation popup is shown when the "install" / "upgrade all" button is clicked
- "About" icon added to the manage panel
- "Updates" icon left-aligned
- show application suggestions when no app is installed. Can be enabled / disabled through the environment variable / parameter FPAKMAN_SUGGESTIONS (--sugs)
- showing a warning popup after initialization when no Flatpak remotes are set
- new environment variable / argument to enable / disable the tray icon and update-check daemon: FPAKMAN_TRAY (--tray)
- minor GUI improvements
### Fixes:
- apps table not showing empty descriptions

View File

@@ -1,4 +1,4 @@
Copyright (c) 2017-2019 Philip Rebohle
Copyright (c) 2017-2019 Vinícius Moreira
zlib/libpng license
@@ -18,4 +18,4 @@ freely, subject to the following restrictions:
Altered source versions must be plainly marked as such, and must not
be misrepresented as being the original software.
This notice may not be removed or altered from any source distribution.
This notice may not be removed or altered from any source distribution.

View File

@@ -68,10 +68,12 @@ You can change some application settings via environment variables or arguments
- **FPAKMAN_DOWNLOAD_ICONS**: Enables / disables app icons download. It may improve the application speed depending on how applications data are being retrieved. Use **0** (disable) or **1** (enable, default).
- **FPAKMAN_CHECK_PACKAGING_ONCE**: If the available supported packaging types should be checked ONLY once. It improves the application speed if enabled, but can generate errors if you uninstall any packaging technology while using it, and every time a supported packaging type is installed it will only be available after a restart. Use **0** (disable, default) or **1** (enable).
- **FPAKMAN_TRAY**: If the tray icon and update-check daemon should be created. Use **0** (disable) or **1** (enable, default).
- **FPAKMAN_SUGGESTIONS**: If application suggestions should be displayed if no app is installed (runtimes do not count as apps). Use **0** (disable) or **1** (enable, default).
### How to improve the application performance
- If you don't care about restarting **fpakman** every time a new supported packaging technology is installed, set "check-packaging-once=1" (**fpakman --check-packaging-once=1**). This can reduce the application response time up to 80% in some scenarios, since it won't need to recheck if the packaging type is available for every action you request.
- If you don't mind to see the applications icons, you can set "download-icons=0" (**fpakman --download-icons=0**). The application may have a slight response improvement, since it will reduce the parallelism within it.
- If you don't mind app suggestions, disable it (**fpakman --sugs=0**)
### Roadmap
- Support for other packaging technologies

View File

@@ -1,29 +0,0 @@
# Generates a .desktop file based on the current python version. Used for AUR installation
import os
import sys
from pathlib import Path
desktop_file = """
[Desktop Entry]
Type = Application
Name = fpakman{desc}
Categories = System;
Comment = Manage your Flatpak / Snap applications
Exec = /usr/bin/fpakman{param}
Icon = /usr/lib/python{version}/site-packages/fpakman/resources/img/logo.svg
"""
py_version = "{}.{}".format(sys.version_info.major, sys.version_info.minor)
with open('fpakman.desktop', 'w+') as f:
f.write(desktop_file.format(desc='', version=py_version, param=' --tray 0'))
with open('fpakman_tray.desktop', 'w+') as f:
f.write(desktop_file.format(desc=' ( tray )', version=py_version, param=''))
# cleaning the old fpakman.desktop entry model -> the following lines will be removed for the next releases
desktop_file_path = '{}/.local/share/applications/fpakman.desktop'.format(str(Path.home()))
if os.path.exists(desktop_file_path):
os.remove(desktop_file_path)

17
aur/panel_entry.py Normal file
View File

@@ -0,0 +1,17 @@
# Generates a .desktop file based on the current python version. Used for AUR installation
import sys
desktop_file = """
[Desktop Entry]
Type = Application
Name = fpakman
Categories = System;
Comment = Manage your Flatpak / Snap applications
Exec = /usr/bin/fpakman --tray=0
Icon = /usr/lib/python{version}/site-packages/fpakman/resources/img/logo.svg
"""
py_version = "{}.{}".format(sys.version_info.major, sys.version_info.minor)
with open('fpakman.desktop', 'w+') as f:
f.write(desktop_file.format(version=py_version))

17
aur/tray_entry.py Normal file
View File

@@ -0,0 +1,17 @@
# Generates a .desktop file based on the current python version. Used for AUR installation
import sys
desktop_file = """
[Desktop Entry]
Type = Application
Name = fpakman ( tray )
Categories = System;
Comment = Manage your Flatpak / Snap applications
Exec = /usr/bin/fpakman
Icon = /usr/lib/python{version}/site-packages/fpakman/resources/img/logo.svg
"""
py_version = "{}.{}".format(sys.version_info.major, sys.version_info.minor)
with open('fpakman_tray.desktop', 'w+') as f:
f.write(desktop_file.format(version=py_version))

View File

@@ -1,4 +1,4 @@
__version__ = '0.5.0'
__version__ = '1.0.0'
__app_name__ = 'fpakman'
import os

View File

@@ -45,7 +45,8 @@ manage_window = ManageWindow(locale_keys=locale_keys,
icon_cache=icon_cache,
disk_cache=args.disk_cache,
download_icons=bool(args.download_icons),
screen_size=app.primaryScreen().size())
screen_size=app.primaryScreen().size(),
suggestions=args.sugs)
if args.tray:
trayIcon = TrayIcon(locale_keys=locale_keys,

View File

@@ -41,6 +41,7 @@ def read() -> Namespace:
help='If the available supported packaging types should be checked ONLY once. It improves the application speed if enabled, but can generate errors if you uninstall any packaging technology while using it, and every time a supported packaging type is installed it will only be available after a restart. Default: %(default)s')
parser.add_argument('--tray', action="store", default=os.getenv('FPAKMAN_TRAY', 1), choices=[0, 1], type=int,
help='If the tray icon and update-check daemon should be created. Default: %(default)s')
parser.add_argument('--sugs', action="store", default=os.getenv('FPAKMAN_SUGGESTIONS', 1), choices=[0, 1], type=int, help='If app suggestions should be displayed if no app is installed (runtimes do not count as apps). Default: %(default)s')
args = parser.parse_args()
if args.cache_exp < 0:
@@ -66,4 +67,7 @@ def read() -> Namespace:
if args.check_packaging_once == 1:
log_msg("'check-packaging-once' is enabled", Fore.YELLOW)
if args.sugs == 0:
log_msg("suggestions are disabled", Fore.YELLOW)
return args

View File

@@ -9,6 +9,8 @@ from fpakman_api.util.system import FpakmanProcess
from fpakman import ROOT_DIR
SUGGESTIONS_LIMIT = 6
class GenericApplicationManager(ApplicationManager):
@@ -207,3 +209,14 @@ class GenericApplicationManager(ApplicationManager):
warnings.extend(man_warnings)
return warnings
def list_suggestions(self, limit: int) -> List[Application]:
if self.managers:
suggestions = []
for man in self.managers:
if self._is_enabled(man):
man_suggestions = man.list_suggestions(SUGGESTIONS_LIMIT)
if man_suggestions:
man_suggestions = man_suggestions[0:SUGGESTIONS_LIMIT] if len(man_suggestions) > SUGGESTIONS_LIMIT else man_suggestions
suggestions.extend(man_suggestions)
return suggestions

142
fpakman/resources/img/about.svg Executable file
View File

@@ -0,0 +1,142 @@
<?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="23.99629"
height="24.016451"
viewBox="0 0 23.99629 24.016451"
xml:space="preserve"
sodipodi:docname="about.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"><metadata
id="metadata933"><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="defs931"><linearGradient
inkscape:collect="always"
id="linearGradient1618"><stop
style="stop-color:#0088aa;stop-opacity:1;"
offset="0"
id="stop1614" /><stop
style="stop-color:#0088aa;stop-opacity:0;"
offset="1"
id="stop1616" /></linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient1618"
id="linearGradient1620"
x1="-22.25"
y1="-4.4919429"
x2="-28.25"
y2="9.7580566"
gradientUnits="userSpaceOnUse" /></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="namedview929"
showgrid="false"
showborder="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="0.50000001"
inkscape:cx="-197.75436"
inkscape:cy="-20.194417"
inkscape:window-x="0"
inkscape:window-y="432"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g898"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g900"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g902"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g904"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g906"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g908"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g910"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g912"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g914"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g916"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g918"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g920"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g922"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g924"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g926"
transform="translate(239.5083,-10.347359)">
</g>
<g
id="g1624"
transform="matrix(1.4998882,0,0,1.5002743,1.245458e-5,-1.4011516e-5)"><ellipse
ry="7.9742656"
rx="7.969605"
cy="8.0040293"
cx="7.999351"
id="path939"
style="fill:url(#linearGradient1620);fill-opacity:1;stroke:#4d4d4d;stroke-width:0.05950872" /><path
d="m 7.8854557,3.7948064 c 1.4552891,0 2.8880403,0.6706192 2.8880403,2.2746822 0,1.479228 -1.6940807,2.0480998 -2.057903,2.5826085 C 8.442458,9.04969 8.5336818,9.6083603 7.7832313,9.6083603 c -0.4888527,0 -0.7276446,-0.3978613 -0.7276446,-0.7618964 0,-1.3546614 1.9892172,-1.6612455 1.9892172,-2.7767069 0,-0.6139735 -0.408361,-0.9780086 -1.0909303,-0.9780086 -1.4552891,0 -0.887018,1.5012419 -1.9892171,1.5012419 -0.3978971,0 -0.73945,-0.2389316 -0.73945,-0.6937069 -2.683e-4,-1.1157299 1.2728414,-2.104477 2.6602492,-2.104477 z M 7.8288432,10.3469 c 0.5108538,0 0.9323617,0.420413 0.9323617,0.933176 0,0.512763 -0.420703,0.933175 -0.9323617,0.933175 -0.5116586,0 -0.9326299,-0.419875 -0.9326299,-0.933175 0,-0.512495 0.4209713,-0.933176 0.9326299,-0.933176 z"
id="path894"
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke-width:0.26838395" /></g></svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Generator: Adobe Illustrator 19.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="Layer_1"
x="0px"
y="0px"
viewBox="0 0 10.048382 24.046875"
xml:space="preserve"
sodipodi:docname="info3.svg"
width="10.048382"
height="24.046875"
inkscape:version="0.92.4 5da689c313, 2019-01-14"><metadata
id="metadata856"><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="defs854" /><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="namedview852"
showgrid="false"
showborder="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="4.2578125"
inkscape:cx="72.471146"
inkscape:cy="14.340367"
inkscape:window-x="0"
inkscape:window-y="432"
inkscape:window-maximized="1"
inkscape:current-layer="Layer_1" />
<g
id="g819"
transform="matrix(0.04838117,0,0,0.046875,-7.3613885,0.0234375)"
style="fill:#ffffff;stroke:#333333">
<circle
style="fill:#ffffff;stroke:#333333"
cx="255.99899"
cy="75.469002"
r="75.469002"
id="circle815" />
<path
style="fill:#ffffff;stroke:#333333"
d="M 359.345,230.952 V 185.078 H 152.654 v 45.874 c 15.395,0 27.874,12.479 27.874,27.873 v 179.426 c 0,15.394 -12.48,27.874 -27.874,27.874 V 512 h 206.692 v -45.873 c -15.395,0 -27.874,-12.48 -27.874,-27.874 V 258.825 c -10e-4,-15.394 12.479,-27.873 27.873,-27.873 z"
id="path817"
inkscape:connector-curvature="0" />
</g>
<g
id="g821"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g823"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g825"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g827"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g829"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g831"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g833"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g835"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g837"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g839"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g841"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g843"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g845"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g847"
transform="translate(-152.62981,-487.97656)">
</g>
<g
id="g849"
transform="translate(-152.62981,-487.97656)">
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@@ -0,0 +1,63 @@
<?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"
version="1.1"
id="svg1069"
width="23.995125"
height="24.004246"
viewBox="0 0 23.995125 24.004246"
sodipodi:docname="settings_3svg.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14">
<metadata
id="metadata1075">
<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="defs1073" />
<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="namedview1071"
showgrid="false"
showborder="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:zoom="3.6875"
inkscape:cx="-9.476931"
inkscape:cy="-2.2075679"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="svg1069" />
<path
style="opacity:0.95;fill:#ffffff;fill-opacity:1;stroke:#333333;stroke-width:0.18215948;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 12.037667,0.09769312 c -0.72043,0.0637 -1.845694,-0.17097 -2.124115,0.73052 -0.08137,0.50962998 0.01515,1.11913998 -0.387221,1.48686998 -0.15736,0.21026 -0.218698,0.60361 -0.5623,0.63599 -0.231156,0.1825 -0.482289,0.4504 -0.805519,0.37943 -0.33519,0.2264 -0.769547,0.14283 -1.104717,-0.0131 -0.637006,0.0746 -1.03032,-0.57076 -1.534985,-0.83449 -0.885643,-0.28862 -1.407803,0.72336 -2.066783,1.10551 -0.25976,0.24133 -0.32452,0.57765 -0.62658,0.79417 -0.43543,0.45528 -0.40057,1.2532 0.17952,1.56982 0.43169,0.5212 0.62511,1.299 0.50516,1.9344 -0.16048,0.28253 -0.0479,0.67728 -0.35903,0.91801 -0.26574,0.43697 -0.71175,0.56803 -1.12615,0.76234 -0.49764,0.39004 -1.38447003,0.0415 -1.77627003,0.5985699 -0.25861,0.96381 -0.12396,2.0252 -0.10444,3.02506 0.0509,0.34442 0.16638,0.76134 0.54628,0.8123 0.39988003,0.23671 0.91536003,0.015 1.32806003,0.27835 1.07706,0.33161 1.66943,1.62912 1.41067,2.66993 -0.16334,0.19954 -0.0658,0.46544 -0.29147,0.64159 -0.17812,0.26318 -0.30377,0.55768 -0.54204,0.80265 -0.47979,0.64849 0.33827,1.30054 0.7343,1.74015 0.54098,0.48923 1.03633,1.14605 1.70793,1.42206 0.23833,-0.12983 0.561824,-0.003 0.682754,-0.29128 0.406567,-0.31367 0.790035,-0.72877 1.343883,-0.71643 0.670515,-0.32887 1.506075,0.0717 2.058292,0.51022 0.156853,0.14124 0.119739,0.39965 0.359038,0.4728 0.497527,0.61075 0.0069,1.60837 0.705143,2.08371 0.874823,0.43838 1.919873,0.26337 2.864969,0.24421 0.659557,0.0141 1.164474,-0.57496 1.060705,-1.22434 0.136064,-0.91849 0.774338,-1.93921 1.77666,-2.0214 0.363739,-0.22429 0.812774,-0.0589 1.166487,0.0473 0.759153,0.0202 1.164413,1.0138 1.994591,0.87519 0.4616,-0.16783 0.782731,-0.57119 1.168225,-0.87538 0.50432,-0.48329 1.01909,-0.97579 1.28636,-1.62094 0.144599,-0.71118 -0.730744,-1.06353 -0.890067,-1.70137 -0.100989,-0.22757 -0.0049,-0.49343 -0.179905,-0.69117 -0.04673,-0.84613 0.412368,-1.65862 1.11958,-2.10125 0.305264,0.0339 0.411929,-0.37354 0.763246,-0.3152 0.591382,0.0245 1.440793,-0.10369 1.514329,-0.83661 0.05748,-1.0154 0.169703,-2.08796 -0.111765,-3.07367 -0.246291,-0.5252799 -0.897473,-0.31832 -1.285587,-0.5717499 -0.232806,0.0157 -0.388499,-0.16382 -0.634686,-0.13137 -0.42064,-0.20941 -0.754834,-0.56503 -0.952802,-0.96218 -0.424334,-0.53524 -0.424871,-1.41725 -0.12354,-1.9942 0.231967,-0.27004 0.338997,-0.6292 0.631791,-0.88078 0.499512,-0.69929 -0.151216,-1.47883 -0.657434,-1.94804 -0.499489,-0.48119 -0.952777,-1.06089 -1.592345,-1.33975 -0.659633,-0.16168 -0.98362,0.57179 -1.534211,0.74575 -0.125378,0.13168 -0.358502,0.0285 -0.45652,0.20544 -0.334935,-0.0571 -0.579653,0.23864 -0.92597,0.071 -0.681696,-0.0739 -1.347245,-0.54339 -1.630535,-1.13561 -0.102377,-0.27247 -0.348146,-0.49327 -0.331433,-0.83892 0.03397,-0.5178 -0.09363,-1.33088998 -0.748962,-1.35222998 -0.449202,-0.1603 -0.970143,-0.0669 -1.440591,-0.0918 z m 7.358542,2.90314998 c 0.09152,-0.13657 0.180927,-0.13633 0,0 z m -7.380163,5.3821 c 0.391366,-0.0266 0.744155,0.13023 1.08889,0.2282 0.620271,0.0714 1.143014,0.59122 1.609108,0.96643 0.332946,0.16294 0.165699,0.5772199 0.500916,0.7067799 0.221257,0.23884 0.09768,0.58093 0.319466,0.79533 0.07607,1.0594 0.150917,2.20776 -0.611329,3.06518 -0.47404,0.62985 -1.178494,1.1764 -1.950002,1.33815 -0.35881,3e-5 -0.689909,0.20436 -1.078465,0.1302 -0.307061,0.0394 -0.57734,-0.14573 -0.847792,-0.16049 -0.201682,-0.11921 -0.435966,-0.0458 -0.596853,-0.26311 -0.569432,-0.0889 -0.972318,-0.61227 -1.328054,-1.03395 -0.01774,-0.31189 -0.432129,-0.39167 -0.438374,-0.75366 -0.338183,-0.85301 -0.406908,-1.899 0.01158,-2.72529 0.246346,-0.36263 0.317564,-0.8099699 0.679663,-1.1234499 0.674731,-0.73941 1.661428,-1.11848 2.641244,-1.17032 z m -1.846149,6.8379199 c 6.6e-4,-0.004 0.01304,-0.006 0,0 z m -0.08223,0.13213 c -0.0079,-0.0194 0.04552,-0.0747 0,0 z m 1.435381,0.35725 c 0.0025,0.0119 -0.0022,-0.007 0,0 z m -8.415191,2.52892 c -0.003,0.003 -0.0212,-0.009 0,0 z m 17.973515,1.20852 c 0.08741,0.13502 -0.194278,-0.16337 0,0 z m -5.019582,0.98456 c -0.01137,0.0188 0.01702,-0.0484 0,0 z"
id="path1626"
inkscape:connector-curvature="0" />
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View File

@@ -0,0 +1,76 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
viewBox="0 0 48.000008 47.999886"
enable-background="new 0 0 26 26"
id="svg8"
sodipodi:docname="update_white.svg"
inkscape:version="0.92.4 5da689c313, 2019-01-14"
width="48.000008"
height="47.999886">
<metadata
id="metadata14">
<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="defs12" />
<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="namedview10"
showgrid="false"
showborder="false"
inkscape:zoom="3.2091769"
inkscape:cx="11.492348"
inkscape:cy="-1.3206439"
inkscape:window-x="0"
inkscape:window-y="432"
inkscape:window-maximized="1"
inkscape:current-layer="svg8"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0" />
<g
id="g6"
transform="matrix(1.8424663,0,0,1.9956679,0.04794249,-1.943739)"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.05204165">
<path
d="m 25,17 h -2 c -0.6,0 -1,0.4 -1,1 v 2.5 C 22,20.8 21.8,21 21.5,21 H 4.5 C 4.2,21 4,20.8 4,20.5 V 18 C 4,17.4 3.6,17 3,17 H 1 c -0.6,0 -1,0.4 -1,1 v 6 c 0,0.6 0.4,1 1,1 h 24 c 0.6,0 1,-0.4 1,-1 v -6 c 0,-0.6 -0.4,-1 -1,-1 z"
id="path2"
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.05204165" />
<path
d="m 12.3,16.7 c 0.2,0.2 0.5,0.3 0.7,0.3 0.2,0 0.5,-0.1 0.7,-0.3 l 6,-6 C 19.9,10.5 20,10.3 20,10 20,9.7 19.9,9.5 19.7,9.3 L 18.3,7.9 C 18.1,7.7 17.9,7.6 17.6,7.6 c -0.3,0 -0.5,0.1 -0.7,0.3 l -1,1 C 15.6,9.2 15,9 15,8.5 V 2 C 15,1.4 14.6,1 14,1 H 12 C 11.4,1 11,1.4 11,2 V 8.6 C 11,9 10.5,9.3 10.1,9 L 9.1,8 C 8.9,7.8 8.7,7.7 8.4,7.7 8.1,7.7 7.9,7.8 7.7,8 L 6.3,9.4 C 6.1,9.6 6,9.8 6,10.1 c 0,0.3 0.1,0.5 0.3,0.7 z"
id="path4"
inkscape:connector-curvature="0"
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.05204165" />
</g>
<g
transform="matrix(3.7795276,0,0,3.7795276,668.44512,-480.86859)"
id="layer1"
inkscape:label="Layer 1" />
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@@ -1,155 +0,0 @@
<?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="24"
height="24"
viewBox="0 0 24 24"
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="703"
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="143.59281"
inkscape:cy="26.740827"
inkscape:window-x="0"
inkscape:window-y="260"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g93"
transform="translate(0,-414.534)">
</g>
<g
id="g95"
transform="translate(0,-414.534)">
</g>
<g
id="g97"
transform="translate(0,-414.534)">
</g>
<g
id="g99"
transform="translate(0,-414.534)">
</g>
<g
id="g101"
transform="translate(0,-414.534)">
</g>
<g
id="g103"
transform="translate(0,-414.534)">
</g>
<g
id="g105"
transform="translate(0,-414.534)">
</g>
<g
id="g107"
transform="translate(0,-414.534)">
</g>
<g
id="g109"
transform="translate(0,-414.534)">
</g>
<g
id="g111"
transform="translate(0,-414.534)">
</g>
<g
id="g113"
transform="translate(0,-414.534)">
</g>
<g
id="g115"
transform="translate(0,-414.534)">
</g>
<g
id="g117"
transform="translate(0,-414.534)">
</g>
<g
id="g119"
transform="translate(0,-414.534)">
</g>
<g
id="g121"
transform="translate(0,-414.534)">
</g>
<g
id="g96"
transform="scale(0.50000002)"><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>

Before

Width:  |  Height:  |  Size: 5.6 KiB

View File

@@ -1,69 +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="24"
height="24"
viewBox="0 0 6.35 6.35"
version="1.1"
id="svg8"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="toggle_off.svg">
<defs
id="defs2" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.35"
inkscape:cx="398.57142"
inkscape:cy="-80.000033"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
showborder="false"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1366"
inkscape:window-height="703"
inkscape:window-x="0"
inkscape:window-y="260"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<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(198.05952,-121.31665)">
<circle
style="fill:#b3b3b3;stroke-width:0.02469599"
id="path10"
cx="-194.88452"
cy="124.49165"
r="3.175" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -1,93 +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: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"
width="24"
height="24"
viewBox="0 0 6.35 6.35"
version="1.1"
id="svg8"
inkscape:version="0.92.3 (2405546, 2018-03-11)"
sodipodi:docname="toggle_on.svg">
<defs
id="defs2">
<linearGradient
inkscape:collect="always"
id="linearGradient66">
<stop
style="stop-color:#55d400;stop-opacity:1;"
offset="0"
id="stop62" />
<stop
style="stop-color:#55d400;stop-opacity:0;"
offset="1"
id="stop64" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient66"
id="linearGradient68"
x1="-210.35391"
y1="112.4323"
x2="-215.96657"
y2="126.86485"
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.53333336,0,0,0.53333336,-92.427766,59.577773)" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.98994949"
inkscape:cx="185.81986"
inkscape:cy="20.785442"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
showborder="false"
units="px"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1366"
inkscape:window-height="703"
inkscape:window-x="0"
inkscape:window-y="260"
inkscape:window-maximized="1" />
<metadata
id="metadata5">
<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(198.05951,-121.31666)">
<circle
style="fill:url(#linearGradient68);fill-opacity:1;stroke-width:0.02469597"
id="path10"
cx="-194.88451"
cy="124.49166"
r="3.175" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@@ -3,11 +3,10 @@ manage_window.columns.latest_version=Latest Version
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.popup.title=Uninstall
manage_window.apps_table.row.actions.uninstall.popup.body=Remove {} ?
manage_window.apps_table.row.actions.uninstall.popup.body=Remove {} from your computer ?
manage_window.apps_table.row.actions.install.popup.title=Installation
manage_window.apps_table.row.actions.install.popup.body=Do you wish to install {} ?
manage_window.apps_table.row.actions.install.popup.body=Install {} on your computer ?
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
@@ -79,3 +78,8 @@ app.name=application name
warning=warning
install=install
uninstall=uninstall
bt.app_upgrade=Upgrade
bt.app_not_upgrade=Don't upgrade
manage_window.upgrade_all.popup.title=Upgrade
manage_window.upgrade_all.popup.body=Upgrade all selected applications ?
manage_window.bt_about.tooltip=About

View File

@@ -6,9 +6,9 @@ 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
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 {} de tu ordenador?
manage_window.apps_table.row.actions.install.popup.title=Instalación
manage_window.apps_table.row.actions.install.popup.body=Desea instalar {} ?
manage_window.apps_table.row.actions.install.popup.body=¿Instalar {} en tu ordenador?
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
@@ -80,3 +80,8 @@ app.name=nombre del aplicativo
warning=aviso
install=instalar
uninstall=desinstalar
bt.app_upgrade=Actualizar
bt.app_not_upgrade=No actualizar
manage_window.upgrade_all.popup.title=Actualizar
manage_window.upgrade_all.popup.body=¿Actualizar todos los aplicativos seleccionados?
manage_window.bt_about.tooltip=Sobre

View File

@@ -6,9 +6,9 @@ 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.popup.title=Desinstalação
manage_window.apps_table.row.actions.uninstall.popup.body=Remover {} ?
manage_window.apps_table.row.actions.uninstall.popup.body=Remover {} do seu computador ?
manage_window.apps_table.row.actions.install.popup.title=Instalação
manage_window.apps_table.row.actions.install.popup.body=Deseja instalar {} ?
manage_window.apps_table.row.actions.install.popup.body=Instalar {} no seu computador ?
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
@@ -80,3 +80,8 @@ app.name=nome do aplicativo
warning=aviso
install=instalar
uninstall=desinstalar
bt.app_upgrade=Atualizar
bt.app_not_upgrade=Não atualizar
manage_window.upgrade_all.popup.title=Atualizar
manage_window.upgrade_all.popup.body=Atualizar todos os aplicativos selecionados ?
manage_window.bt_about.tooltip=Sobre

View File

@@ -6,7 +6,7 @@ from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QPixmap, QIcon, QCursor
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest
from PyQt5.QtWidgets import QTableWidget, QTableView, QMenu, QAction, QTableWidgetItem, QToolButton, QWidget, \
QHeaderView, QLabel, QHBoxLayout, QPushButton
QHeaderView, QLabel, QHBoxLayout, QPushButton, QToolBar
from fpakman_api.abstract.model import ApplicationStatus
from fpakman.core import resource
@@ -16,29 +16,59 @@ from fpakman.util import util
from fpakman.view.qt import dialog
from fpakman.view.qt.view_model import ApplicationView, ApplicationViewStatus
INSTALL_BT_STYLE = 'background: {back}; color: white; font-size: 9px; font-weight: bold'
INSTALL_BT_STYLE = 'background: {back}; color: white; font-size: 10px; font-weight: bold'
class UpdateToggleButton(QToolButton):
class IconButton(QWidget):
def __init__(self, icon_path: str, action, background: str = None, align: int = Qt.AlignCenter, tooltip: str = None):
super(IconButton, self).__init__()
self.bt = QToolButton()
self.bt.setIcon(QIcon(icon_path))
self.bt.clicked.connect(action)
if background:
self.bt.setStyleSheet('QToolButton { color: white; background: ' + background + '}')
if tooltip:
self.bt.setToolTip(tooltip)
layout = QHBoxLayout()
layout.setContentsMargins(0, 0, 0, 0)
layout.setAlignment(align)
layout.addWidget(self.bt)
self.setLayout(layout)
class UpdateToggleButton(QWidget):
def __init__(self, app_view: ApplicationView, root: QWidget, locale_keys: dict, checked: bool = True):
super(UpdateToggleButton, self).__init__()
self.app_view = app_view
self.root = root
self.setCheckable(True)
self.clicked.connect(self.change_state)
self.icon_on = QIcon(resource.get_path('img/toggle_on.svg'))
self.icon_off = QIcon(resource.get_path('img/toggle_off.svg'))
self.setIcon(self.icon_on)
self.setStyleSheet('QToolButton { border: 0px; }')
layout = QHBoxLayout()
layout.setContentsMargins(2, 2, 2, 0)
layout.setAlignment(Qt.AlignCenter)
self.setLayout(layout)
self.bt = QToolButton()
self.bt.setCheckable(True)
self.bt.clicked.connect(self.change_state)
self.bt.setIcon(QIcon(resource.get_path('img/app_update.svg')))
self.bt.setStyleSheet('QToolButton { background: #4EC306 } ' +
'QToolButton:checked { background: gray }')
layout.addWidget(self.bt)
self.setToolTip(locale_keys['manage_window.apps_table.upgrade_toggle.tooltip'])
if not checked:
self.click()
self.bt.click()
def change_state(self, not_checked: bool):
self.app_view.update_checked = not not_checked
self.setIcon(self.icon_on if not not_checked else self.icon_off)
self.root.change_update_state(change_filters=False)
@@ -50,12 +80,7 @@ class AppsTable(QTableWidget):
self.window = parent
self.disk_cache = disk_cache
self.download_icons = download_icons
self.column_names = [parent.locale_keys[key].capitalize() for key in ['name',
'version',
'description',
'type',
'installed',
'manage_window.columns.update']]
self.column_names = ['' for _ in range(7)]
self.setColumnCount(len(self.column_names))
self.setFocusPolicy(Qt.NoFocus)
self.setShowGrid(False)
@@ -73,35 +98,46 @@ class AppsTable(QTableWidget):
self.icon_cache = icon_cache
self.lock_async_data = Lock()
def contextMenuEvent(self, QContextMenuEvent): # selected row right click event
app = self.get_selected_app()
def has_any_settings(self, app_v: ApplicationView):
return app_v.model.can_be_refreshed() or \
app_v.model.has_history() or \
app_v.model.can_be_downgraded()
def show_app_settings(self, app: ApplicationView):
menu_row = QMenu()
if app.model.has_info():
action_info = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.info"])
action_info.setIcon(QIcon(resource.get_path('img/info.svg')))
action_info.triggered.connect(self._get_app_info)
menu_row.addAction(action_info)
if app.model.installed:
if app.model.can_be_refreshed():
action_history = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.refresh"])
action_history.setIcon(QIcon(resource.get_path('img/refresh.svg')))
action_history.triggered.connect(self._refresh_app)
def refresh():
self.window.refresh(app)
action_history.triggered.connect(refresh)
menu_row.addAction(action_history)
if app.model.has_history():
action_history = QAction(self.window.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)
def show_history():
self.window.get_app_history(app)
action_history.triggered.connect(show_history)
menu_row.addAction(action_history)
if app.model.can_be_downgraded():
action_downgrade = QAction(self.window.locale_keys["manage_window.apps_table.row.actions.downgrade"])
action_downgrade.triggered.connect(self._downgrade_app)
def downgrade():
if dialog.ask_confirmation(
title=self.window.locale_keys['manage_window.apps_table.row.actions.downgrade'],
body=self.window.locale_keys['manage_window.apps_table.row.actions.downgrade.popup.body'].format(app.model.base_data.name),
locale_keys=self.window.locale_keys):
self.window.downgrade_app(app)
action_downgrade.triggered.connect(downgrade)
action_downgrade.setIcon(QIcon(resource.get_path('img/downgrade.svg')))
menu_row.addAction(action_downgrade)
@@ -182,6 +218,7 @@ class AppsTable(QTableWidget):
icon_was_cached = False
pixmap = QPixmap()
pixmap.loadFromData(icon_bytes)
icon = QIcon(pixmap)
icon_data = {'icon': icon, 'bytes': icon_bytes}
@@ -208,12 +245,14 @@ class AppsTable(QTableWidget):
self._set_col_type(idx, app_v)
self._set_col_installed(idx, app_v)
self._set_col_settings(idx, app_v)
col_update = None
if update_check_enabled and app_v.model.update:
col_update = UpdateToggleButton(app_v, self.window, self.window.locale_keys, app_v.model.update)
self.setCellWidget(idx, 5, col_update)
self.setCellWidget(idx, 6, col_update)
def _gen_row_button(self, text: str, style: str, callback) -> QWidget:
col = QWidget()
@@ -223,7 +262,7 @@ class AppsTable(QTableWidget):
col_bt.clicked.connect(callback)
layout = QHBoxLayout()
layout.setContentsMargins(3, 3, 3, 3)
layout.setContentsMargins(2, 2, 2, 0)
layout.setAlignment(Qt.AlignCenter)
layout.addWidget(col_bt)
col.setLayout(layout)
@@ -246,7 +285,7 @@ class AppsTable(QTableWidget):
elif app_v.model.can_be_installed():
def install():
self._install_app(app_v)
col = self._gen_row_button(self.window.locale_keys['install'].capitalize(), INSTALL_BT_STYLE.format(back='green'), install)
col = self._gen_row_button(self.window.locale_keys['install'].capitalize(), INSTALL_BT_STYLE.format(back='#088A08'), install)
else:
col = None
@@ -254,7 +293,7 @@ class AppsTable(QTableWidget):
def _set_col_type(self, idx: int, app_v: ApplicationView):
col_type = QLabel()
pixmap = QPixmap(app_v.model.get_type_icon_path())
pixmap = QPixmap(app_v.model.get_default_icon_path())
col_type.setPixmap(pixmap.scaled(16, 16, Qt.KeepAspectRatio, Qt.SmoothTransformation))
col_type.setAlignment(Qt.AlignCenter)
col_type.setToolTip('{}: {}'.format(self.window.locale_keys['type'], app_v.model.get_type()))
@@ -274,7 +313,7 @@ class AppsTable(QTableWidget):
tooltip = self.window.locale_keys['version.unknown']
if app_v.model.update:
label_version.setStyleSheet("color: #45ab27")
label_version.setStyleSheet("color: #4EC306; font-weight: bold")
tooltip = self.window.locale_keys['version.installed_outdated']
if app_v.model.base_data.version and app_v.model.base_data.latest_version and app_v.model.base_data.version < app_v.model.base_data.latest_version:
@@ -326,6 +365,25 @@ class AppsTable(QTableWidget):
self.setItem(idx, 2, col)
def _set_col_settings(self, idx: int, app_v: ApplicationView):
tb = QToolBar()
if app_v.model.has_info():
def get_info():
self.window.get_app_info(app_v)
tb.addWidget(IconButton(icon_path=resource.get_path('img/app_info.svg'), action=get_info, background='#2E68D3'))
def handle_click():
self.show_app_settings(app_v)
if self.has_any_settings(app_v):
bt = IconButton(icon_path=resource.get_path('img/app_settings.svg'), action=handle_click, background='#12ABAB')
tb.addWidget(bt)
self.setCellWidget(idx, 5, tb)
def change_headers_policy(self, policy: QHeaderView = QHeaderView.ResizeToContents):
header_horizontal = self.horizontalHeader()
for i in range(self.columnCount()):

View File

@@ -2,17 +2,17 @@ import operator
from functools import reduce
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon, QColor
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QTableWidget, QTableWidgetItem, QHeaderView
from fpakman_api.util.cache import Cache
class HistoryDialog(QDialog):
def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict):
def __init__(self, app: dict, icon_cache: Cache, locale_keys: dict):
super(HistoryDialog, self).__init__()
self.setWindowTitle('{} - {} '.format(locale_keys['popup.history.title'], app['model'].base_data.name))
self.setWindowIcon(app_icon)
layout = QVBoxLayout()
self.setLayout(layout)
@@ -52,3 +52,8 @@ class HistoryDialog(QDialog):
new_width = reduce(operator.add, [table_history.columnWidth(i) for i in range(table_history.columnCount())])
self.resize(new_width, table_history.height())
icon_data = icon_cache.get(app['model'].base_data.icon_url)
if icon_data and icon_data.get('icon'):
self.setWindowIcon(icon_data.get('icon'))

View File

@@ -1,17 +1,18 @@
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QIcon
from PyQt5.QtWidgets import QDialog, QVBoxLayout, QFormLayout, QGroupBox, \
QLineEdit, QLabel
from fpakman_api.util.cache import Cache
from fpakman.util import util
IGNORED_ATTRS = {'name', '__app__'}
class InfoDialog(QDialog):
def __init__(self, app: dict, app_icon: QIcon, locale_keys: dict, app_type: str, screen_size: QSize()):
def __init__(self, app: dict, icon_cache: Cache, locale_keys: dict, screen_size: QSize()):
super(InfoDialog, self).__init__()
self.setWindowTitle(app['name'])
self.setWindowIcon(app_icon)
self.screen_size = screen_size
layout = QVBoxLayout()
self.setLayout(layout)
@@ -23,8 +24,13 @@ class InfoDialog(QDialog):
layout.addWidget(gbox_info)
icon_data = icon_cache.get(app['__app__'].model.base_data.icon_url)
if icon_data and icon_data.get('icon'):
self.setWindowIcon(icon_data.get('icon'))
for attr in sorted(app.keys()):
if attr != 'name' and app[attr]:
if attr not in IGNORED_ATTRS and app[attr]:
val = app[attr]
text = QLineEdit()
text.setToolTip(val)
@@ -41,7 +47,7 @@ class InfoDialog(QDialog):
text.setStyleSheet("width: 400px")
text.setReadOnly(True)
label = QLabel("{}: ".format(locale_keys.get(app_type + '.info.' + attr, attr)).capitalize())
label = QLabel("{}: ".format(locale_keys.get(app['__app__'].model.get_type() + '.info.' + attr, attr)).capitalize())
label.setStyleSheet("font-weight: bold")
gbox_info_layout.addRow(label, text)

View File

@@ -158,7 +158,9 @@ class GetAppInfo(QThread):
def run(self):
if self.app:
self.signal_finished.emit(self.manager.get_info(self.app.model))
info = {'__app__': self.app}
info.update(self.manager.get_info(self.app.model))
self.signal_finished.emit(info)
self.app = None
@@ -332,3 +334,16 @@ class RefreshApp(AsyncAction):
finally:
self.app = None
self.signal_finished.emit(success)
class FindSuggestions(AsyncAction):
signal_finished = pyqtSignal(list)
def __init__(self, man: ApplicationManager):
super(FindSuggestions, self).__init__()
self.man = man
def run(self):
self.signal_finished.emit(self.man.list_suggestions(limit=-1))

View File

@@ -2,7 +2,7 @@ import operator
from functools import reduce
from typing import List, Set
from PyQt5.QtCore import QEvent, Qt
from PyQt5.QtCore import QEvent, Qt, QSize
from PyQt5.QtGui import QIcon, QWindowStateChangeEvent, QPixmap
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QApplication, QCheckBox, QHeaderView, QToolButton, QToolBar, \
QSizePolicy, QLabel, QPlainTextEdit, QLineEdit, QProgressBar, QHBoxLayout
@@ -12,12 +12,14 @@ from fpakman_api.util.cache import Cache
from fpakman.core import resource
from fpakman.core.controller import ApplicationManager
from fpakman.util import util
from fpakman.view.qt import dialog
from fpakman.view.qt.about import AboutDialog
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.thread import UpdateSelectedApps, RefreshApps, UninstallApp, DowngradeApp, GetAppInfo, \
GetAppHistory, SearchApps, InstallApp, AnimateProgress, VerifyModels, RefreshApp
GetAppHistory, SearchApps, InstallApp, AnimateProgress, VerifyModels, RefreshApp, FindSuggestions
from fpakman.view.qt.view_model import ApplicationView
DARK_ORANGE = '#FF4500'
@@ -26,7 +28,7 @@ DARK_ORANGE = '#FF4500'
class ManageWindow(QWidget):
__BASE_HEIGHT__ = 400
def __init__(self, locale_keys: dict, icon_cache: Cache, manager: ApplicationManager, disk_cache: bool, download_icons: bool, screen_size, tray_icon=None):
def __init__(self, locale_keys: dict, icon_cache: Cache, manager: ApplicationManager, disk_cache: bool, download_icons: bool, screen_size, suggestions: bool, tray_icon=None):
super(ManageWindow, self).__init__()
self.locale_keys = locale_keys
self.manager = manager
@@ -176,7 +178,14 @@ class ManageWindow(QWidget):
self.thread_refresh_app.signal_finished.connect(self._finish_refresh)
self.thread_refresh_app.signal_output.connect(self._update_action_output)
self.thread_suggestions = FindSuggestions(man=self.manager)
self.thread_suggestions.signal_finished.connect(self._finish_search)
self.toolbar_bottom = QToolBar()
self.toolbar_bottom.setIconSize(QSize(16, 16))
self.label_updates = QLabel()
self.ref_label_updates = self.toolbar_bottom.addWidget(self.label_updates)
self.toolbar_bottom.addWidget(self._new_spacer())
@@ -186,8 +195,12 @@ class ManageWindow(QWidget):
self.toolbar_bottom.addWidget(self._new_spacer())
self.label_updates = QLabel()
self.ref_label_updates = self.toolbar_bottom.addWidget(self.label_updates)
bt_about = QToolButton()
bt_about.setStyleSheet('QToolButton { border: 0px; }')
bt_about.setIcon(QIcon(resource.get_path('img/about.svg')))
bt_about.clicked.connect(self._show_about)
bt_about.setToolTip(self.locale_keys['manage_window.bt_about.tooltip'])
self.ref_bt_about = self.toolbar_bottom.addWidget(bt_about)
self.layout.addWidget(self.toolbar_bottom)
@@ -198,6 +211,15 @@ class ManageWindow(QWidget):
self.filter_updates = False
self._maximized = False
self.dialog_about = None
self.first_refresh = suggestions
def _show_about(self):
if self.dialog_about is None:
self.dialog_about = AboutDialog(self.locale_keys)
self.dialog_about.show()
def _handle_updates_filter(self, status: int):
self.filter_updates = status == 2
self.apply_filters()
@@ -269,6 +291,7 @@ class ManageWindow(QWidget):
self.ref_checkbox_only_apps.setVisible(True)
self.ref_bt_upgrade.setVisible(True)
self.update_apps(apps)
self.first_refresh = False
def uninstall_app(self, app: ApplicationView):
pwd = None
@@ -289,7 +312,7 @@ class ManageWindow(QWidget):
def refresh(self, app: ApplicationView):
pwd = None
requires_root = self.manager.requires_root('refresh', self.table_apps.get_selected_app().model)
requires_root = self.manager.requires_root('refresh', app.model)
if not is_root() and requires_root:
pwd, ok = ask_root_password(self.locale_keys)
@@ -440,8 +463,14 @@ class ManageWindow(QWidget):
self.apps.append(app_model)
if napps == 0:
self.checkbox_only_apps.setChecked(False)
self.checkbox_only_apps.setCheckable(False)
if self.first_refresh:
self._begin_search('')
self.thread_suggestions.start()
return
else:
self.checkbox_only_apps.setChecked(False)
self.checkbox_only_apps.setCheckable(False)
else:
self.checkbox_only_apps.setCheckable(True)
self.checkbox_only_apps.setChecked(True)
@@ -496,7 +525,9 @@ class ManageWindow(QWidget):
if self.manager.requires_root('update', app_v.model):
requires_root = True
if to_update:
if to_update and dialog.ask_confirmation(title=self.locale_keys['manage_window.upgrade_all.popup.title'],
body=self.locale_keys['manage_window.upgrade_all.popup.body'],
locale_keys=self.locale_keys):
pwd = None
if not is_root() and requires_root:
@@ -533,6 +564,7 @@ class ManageWindow(QWidget):
self.textarea_output.appendPlainText(output)
def _begin_action(self, action_label: str, keep_search: bool = False, clear_filters: bool = False):
self.ref_bt_about.setVisible(False)
self.ref_label_updates.setVisible(False)
self.thread_animate_progress.stop = False
self.thread_animate_progress.start()
@@ -556,6 +588,7 @@ class ManageWindow(QWidget):
self.extra_filters.setEnabled(False)
def finish_action(self):
self.ref_bt_about.setVisible(True)
self.ref_progress_bar.setVisible(False)
self.ref_label_updates.setVisible(True)
self.thread_animate_progress.stop = True
@@ -603,30 +636,35 @@ class ManageWindow(QWidget):
def _finish_get_info(self, app_info: dict):
self.finish_action()
dialog_info = InfoDialog(app_info, self.table_apps.get_selected_app_icon(), self.locale_keys, self.table_apps.get_selected_app().model.get_type(), self.screen_size)
self.change_update_state(change_filters=False)
dialog_info = InfoDialog(app=app_info, icon_cache=self.icon_cache, locale_keys=self.locale_keys, screen_size=self.screen_size)
dialog_info.exec_()
def _finish_get_history(self, app: dict):
self.finish_action()
self.change_update_state(change_filters=False)
if app.get('error'):
self._handle_console_option(True)
self.textarea_output.appendPlainText(app['error'])
self.checkbox_console.setChecked(True)
else:
dialog_history = HistoryDialog(app, self.table_apps.get_selected_app_icon(), self.locale_keys)
dialog_history = HistoryDialog(app, self.icon_cache, self.locale_keys)
dialog_history.exec_()
def _begin_search(self, word):
self._handle_console_option(False)
self.ref_checkbox_only_apps.setVisible(False)
self.ref_checkbox_updates.setVisible(False)
self.filter_updates = False
self._begin_action('{}{}'.format(self.locale_keys['manage_window.status.searching'], '"{}"'.format(word) if word else ''), clear_filters=True)
def search(self):
word = self.input_search.text().strip()
if word:
self._handle_console_option(False)
self.ref_checkbox_only_apps.setVisible(False)
self.ref_checkbox_updates.setVisible(False)
self.filter_updates = False
self._begin_action('{} "{}"'.format(self.locale_keys['manage_window.status.searching'], word), clear_filters=True)
self._begin_search(word)
self.thread_search.word = word
self.thread_search.start()