app suggenstions when no app is installed

This commit is contained in:
Vinicius Moreira
2019-08-05 22:06:37 -03:00
parent 193c8bc2bc
commit 3f01ba8c3b
10 changed files with 133 additions and 23 deletions

View File

@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- a confirmation popup is shown when the "install" / "upgrade all" button is clicked
- "About" button 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)
- minor GUI improvements
### Fixes:
- apps table not showing empty descriptions

View File

@@ -53,6 +53,7 @@ You can change some application settings via environment variables or arguments
- **FPAKMAN_SNAP**: enables / disables snap usage. Use **0** (disable) or **1** (enabled, 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 a specific packaging technology and don't want **fpakman** to deal with it, just disable it via the specific argument or environment variable. For instance, if I don't care
@@ -60,6 +61,7 @@ about **snaps**, I can initialize the application setting "snap=0" (**fpakman --
with the technology that I don't care every time an action is executed.
- 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

@@ -47,6 +47,7 @@ parser.add_argument('--flatpak', action="store", default=os.getenv('FPAKMAN_FLAT
parser.add_argument('--snap', action="store", default=os.getenv('FPAKMAN_SNAP', 1), choices=[0, 1], type=int, help='Enables / disables snap usage. Default: %(default)s')
parser.add_argument('-co', '--check-packaging-once', action="store", default=os.getenv('FPAKMAN_CHECK_PACKAGING_ONCE', 0), choices=[0, 1], type=int, 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:
@@ -78,6 +79,9 @@ if args.download_icons == 0:
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)
locale_keys = util.get_locale_keys(args.locale)
http_session = requests.Session()
@@ -122,7 +126,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=screen_size)
screen_size=screen_size,
suggestions=args.sugs)
if args.tray:
trayIcon = TrayIcon(locale_keys=locale_keys,

View File

@@ -90,6 +90,10 @@ class ApplicationManager(ABC):
def list_warnings(self) -> List[str]:
pass
@abstractmethod
def list_suggestions(self, limit: int) -> List[Application]:
pass
class GenericApplicationManager(ApplicationManager):
@@ -285,3 +289,11 @@ 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):
suggestions.extend(man.list_suggestions(5))
return suggestions

View File

@@ -46,7 +46,9 @@ class FlatpakManager(ApplicationManager):
if not api_data or expired_data:
if not app_json['runtime']:
disk_loader.add(app) # preloading cached disk data
if disk_loader:
disk_loader.add(app) # preloading cached disk data
FlatpakAsyncDataLoader(app=app, api_cache=self.api_cache, manager=self, http_session=self.http_session).start()
else:
@@ -181,3 +183,22 @@ class FlatpakManager(ApplicationManager):
def list_warnings(self) -> List[str]:
if not flatpak.has_remotes_set():
return [self.locale_keys['flatpak.notification.no_remotes']]
def list_suggestions(self, limit: int) -> List[FlatpakApplication]:
res = []
if limit != 0:
for app_id in ('com.spotify.Client', 'com.skype.Client', 'com.dropbox.Client', 'us.zoom.Zoom', 'com.visualstudio.code', 'org.inkscape.Inkscape', 'org.libretro.RetroArch', 'org.kde.kdenlive', 'org.videolan.VLC'):
app_json = flatpak.search(app_id, app_id=True)
if app_json:
res.append(self._map_to_model(app_json[0], False, None))
if len(res) == limit:
break
return res

View File

@@ -153,7 +153,7 @@ def get_app_commits_data(app_ref: str, origin: str) -> List[dict]:
return commits
def search(word: str) -> List[dict]:
def search(word: str, app_id: bool = False) -> List[dict]:
cli_version = get_version()
res = system.run_cmd('{} search {}'.format(BASE_CMD, word))
@@ -166,13 +166,17 @@ def search(word: str) -> List[dict]:
for info in split_res:
if info:
info_list = info.split('\t')
if cli_version >= '1.3.0':
id_ = info_list[2].strip()
if app_id and id_ != word:
continue
version = info_list[3].strip()
found.append({
app = {
'name': info_list[0].strip(),
'description': info_list[1].strip(),
'id': info_list[2].strip(),
'id': id_,
'version': version,
'latest_version': version,
'branch': info_list[4].strip(),
@@ -180,14 +184,19 @@ def search(word: str) -> List[dict]:
'runtime': False,
'arch': None, # unknown at this moment,
'ref': None # unknown at this moment
})
}
elif cli_version >= '1.2.0':
id_ = info_list[1].strip()
if app_id and id_ != word:
continue
desc = info_list[0].split('-')
version = info_list[2].strip()
found.append({
app = {
'name': desc[0].strip(),
'description': desc[1].strip(),
'id': info_list[1].strip(),
'id': id_,
'version': version,
'latest_version': version,
'branch': info_list[3].strip(),
@@ -195,13 +204,18 @@ def search(word: str) -> List[dict]:
'runtime': False,
'arch': None, # unknown at this moment,
'ref': None # unknown at this moment
})
}
else:
id_ = info_list[0].strip()
if app_id and id_ != word:
continue
version = info_list[1].strip()
found.append({
app = {
'name': '',
'description': info_list[4].strip(),
'id': info_list[0].strip(),
'id': id_,
'version': version,
'latest_version': version,
'branch': info_list[2].strip(),
@@ -209,7 +223,13 @@ def search(word: str) -> List[dict]:
'runtime': False,
'arch': None, # unknown at this moment,
'ref': None # unknown at this moment
})
}
found.append(app)
if app_id and len(found) > 0:
break
return found

View File

@@ -137,3 +137,18 @@ class SnapManager(ApplicationManager):
def list_warnings(self) -> List[str]:
if snap.get_snapd_version() == 'unavailable':
return [self.locale_keys['snap.notification.snapd_unavailable']]
def list_suggestions(self, limit: int) -> List[SnapApplication]:
suggestions = []
if limit != 0:
for name in ('whatsdesk', 'slack', 'yakyak', 'instagraph', 'eclipse', 'gimp', 'supertuxkart'):
res = snap.search(name, exact_name=True)
if res:
suggestions.append(self.map_json(res[0], installed=False, disk_loader=None))
if len(suggestions) == limit:
break
return suggestions

View File

@@ -86,7 +86,7 @@ def read_installed() -> List[dict]:
return apps
def search(word: str) -> List[dict]:
def search(word: str, exact_name: bool = False) -> List[dict]:
apps = []
res = system.run_cmd('{} find "{}"'.format(BASE_CMD, word), print_error=False)
@@ -98,6 +98,10 @@ def search(word: str) -> List[dict]:
for idx, app_str in enumerate(res):
if idx > 0 and app_str:
app_data = [word for word in app_str.split(' ') if word]
if exact_name and app_data[0] != word:
continue
apps.append({
'name': app_data[0],
'version': app_data[1],
@@ -109,6 +113,9 @@ def search(word: str) -> List[dict]:
'type': None
})
if exact_name and len(apps) > 0:
break
return apps

View File

@@ -335,3 +335,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

@@ -18,7 +18,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, SearchApps, InstallApp, AnimateProgress, VerifyModels, RefreshApp
GetAppHistory, SearchApps, InstallApp, AnimateProgress, VerifyModels, RefreshApp, FindSuggestions
from fpakman.view.qt.view_model import ApplicationView
DARK_ORANGE = '#FF4500'
@@ -27,7 +27,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
@@ -177,6 +177,9 @@ 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))
@@ -208,6 +211,7 @@ class ManageWindow(QWidget):
self._maximized = False
self.dialog_about = None
self.first_refresh = suggestions
def _show_about(self):
if self.dialog_about is None:
@@ -286,6 +290,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
@@ -457,8 +462,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)
@@ -626,16 +637,19 @@ class ManageWindow(QWidget):
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()