2025.03.16 01:08:36 (desktop)

This commit is contained in:
Christian Moser 2025-03-16 01:08:36 +01:00
parent c866419b30
commit f23aa75776
Failed to extract signature
6 changed files with 257 additions and 39 deletions

View File

@ -129,7 +129,7 @@ class Epic(GObject):
self.__ignored_apps[app.catalog_item_id] = app
self.__write_ignore_file()
def remove_ignored_apps(self,app:str|EpicIgnoredApp):
def remove_ignored_app(self,app:str|EpicIgnoredApp):
if isinstance(app,str):
item_id = app
elif isinstance(app,EpicIgnoredApp):

View File

@ -50,7 +50,11 @@ from ..steam import Steam
from ..epic import Epic
from ._epic import (
EpicNewAppsDialog,
EpicNoIgnoredAppsDialog,
EpicNoNewAppsDialog,
EpicIgnoredAppsDialog,
)
from ._backupdialog import BackupSingleDialog,BackupManyDialog
from ..archiver import ArchiverManager
from ._dialogs import (
@ -416,18 +420,11 @@ class GameView(Gtk.Box):
def _on_new_epic_games_button_clicked(self,button):
epic = Epic()
if not epic.find_new_apps():
dialog = Gtk.MessageDialog(
transient_for=self.get_root(),
message="No new Epic-Games applications found!",
buttons=Gtk.ButtonsType.OK,
modal=False
)
dialog.connect('response',lambda d,r: d.destroy())
dialog.present()
return
dialog = EpicNewAppsDialog(self.get_root())
dialog.connect_after('response',self._on_new_apps_dialog_response)
dialog = EpicNewAppsDialog(self.get_root())
else:
dialog = EpicNewAppsDialog(self.get_root())
dialog.connect_after('response',self._on_new_apps_dialog_response)
dialog.present()
def _on_backup_active_live_button_clicked(self,button):
@ -449,10 +446,18 @@ class GameView(Gtk.Box):
choices.append(item.name)
item.fuzzy_match = 0.0
result = rapidfuzz.process.extract(query=search_name,
if settings.search_case_sensitive:
processor=None
query=search_name
else:
processor=lambda s: s.lower()
query=search_name.lower()
result = rapidfuzz.process.extract(query=query,
choices=choices,
limit=settings.search_max_results,
scorer=rapidfuzz.fuzz.WRatio)
scorer=rapidfuzz.fuzz.WRatio,
processor=processor)
for name,match,pos in result:
@ -1572,18 +1577,24 @@ class Application(Gtk.Application):
def _on_action_epic_new_apps(self,action,param):
epic = Epic()
if not epic.find_new_apps():
### TODO #####################################
return
dialog = EpicNoNewAppsDialog(self.appwindow)
else:
dialog = EpicNewAppsDialog(self.appwindow)
dialog.connect_after("response",lambda d,r: self.appwindow.refresh())
dialog.connect_after('response',lambda d,r: self.appwindow.refresh())
dialog.present()
def _on_action_epic_manage_ignore(self,action,param):
### TODO ##########################################
pass
epic = Epic()
if not epic.ignored_apps:
dialog = EpicNoIgnoredAppsDialog(self.appwindow)
else:
dialog = EpicIgnoredAppsDialog(self.appwindow)
dialog.connect_after('response',lambda d,r: self.appwindow.refresh())
dialog.present()
def new_settings_dialog(self)->SettingsDialog:
"""
new_settings_dialog Create a new `SettingsDialog`.

View File

@ -27,6 +27,35 @@ from ..utility import PLATFORM_WINDOWS
from ._gamedialog import GameDialog
class EpicNoNewAppsDialog(Gtk.MessageDialog):
def __init__(self,parent:Gtk.Window|None):
Gtk.MessageDialog.__init__(self,
transient_for=parent,
buttons=Gtk.ButtonsType.OK,
text=_("There were no new Epic-Games apps found!"),
use_markup=False,
modal=True)
def do_response(self,response):
self.hide()
self.destroy()
class EpicNoIgnoredAppsDialog(Gtk.MessageDialog):
def __init__(self,parent:Gtk.Window|None):
Gtk.MessageDialog.__init__(self,
transient_for=parent,
buttons=Gtk.ButtonsType.OK,
text=_("There are no ignored Epic-Games apps!"),
use_markup=False,
modal=True)
def do_response(self,response):
self.hide()
self.destroy()
### EpicLookupGamesDialog #####################################################
class EpicLookupGamesDialog(GameSearchDialog):
def __init__(self,parent:Gtk.Window|None=None,info:EpicGameInfo|None=None):
GameSearchDialog.__init__(self,parent,info.name if info else None)
@ -272,3 +301,147 @@ class EpicNewAppsDialog(Gtk.Dialog):
for gameinfo in epic.find_new_apps():
self.__liststore.append(gameinfo)
#### EpicIgnoreAppsDialog ##########################################################
class EpicIgnoredAppsDialogSorter(Gtk.Sorter):
def do_compare(self,item1:EpicIgnoredApp,item2:EpicIgnoredApp):
name1=item1.name.lower()
name2=item2.name.lower()
if name1 < name2:
return Gtk.Ordering.SMALLER
elif name1 > name2:
return Gtk.Ordering.LARGER
return Gtk.Ordering.EQUAL
class EpicIgnoredAppsDialog(Gtk.Dialog):
def __init__(self,parent:Gtk.Window|None=None):
Gtk.Dialog.__init__(self,transient_for=parent)
self.set_default_size(640,480)
epic = Epic()
self.__liststore = Gio.ListStore.new(EpicIgnoredApp)
for ignored in epic.ignored_apps.values():
self.__liststore.append(ignored)
sort_model = Gtk.SortListModel(model=self.__liststore,sorter=EpicIgnoredAppsDialogSorter())
selection = Gtk.SingleSelection(model=sort_model)
factory = Gtk.SignalListItemFactory()
factory.connect('setup',self._on_listview_item_setup)
factory.connect('bind',self._on_listview_item_bind)
self.__listview = Gtk.ListView(model=selection,
factory=factory,
hexpand=True,
vexpand=True)
scrolled = Gtk.ScrolledWindow(hexpand=True,
vexpand=True)
scrolled.set_child(self.__listview)
self.get_content_area().append(scrolled)
self.add_button("Close",Gtk.ResponseType.OK)
def _on_listview_item_setup(self,factory,item):
child = Gtk.Grid(hexpand=True,column_spacing=4,row_spacing=2)
child.name_label = Gtk.Label(use_markup=True,xalign=0.0,hexpand=True)
child.attach(child.name_label,1,0,1,1)
label = Gtk.Label(label=_("CatalogItemId:"),use_markup=False,xalign=0.0,hexpand=False)
child.catalogitemid_label = Gtk.Label(use_markup=False,xalign=0.0,hexpand=True)
child.attach(label,0,1,1,1)
child.attach(child.catalogitemid_label,1,1,1,1)
label = Gtk.Label(label=_("Reason:"),use_markup=False,xalign=0.0,hexpand=False)
child.reason_label = Gtk.Label(use_markup=True,xalign=0.0,hexpand=True)
child.attach(label,0,2,1,1)
child.attach(child.reason_label,1,2,1,1)
action_grid = Gtk.Grid(column_spacing=2,row_spacing=2)
icon = Gtk.Image.new_from_icon_name("document-new-symbolic")
icon.set_pixel_size(16)
child.new_game_button = Gtk.Button()
child.new_game_button.set_child(icon)
child.new_game_button.set_tooltip_text("Add ignored SteamApp as a new game.")
action_grid.attach(child.new_game_button,0,0,1,1)
icon = Gtk.Image.new_from_icon_name("list-remove-symbolic")
icon.set_pixel_size(16)
child.remove_button = Gtk.Button()
child.remove_button.set_child(icon)
child.remove_button.set_tooltip_text("Remove ignored SteamApp from the list.")
action_grid.attach(child.remove_button,0,1,1,1)
child.attach(action_grid,2,0,1,3)
item.set_child(child)
def _on_listview_item_bind(self,factory,item):
child = item.get_child()
data = item.get_item()
child.name_label.set_markup("<span size='large' weight='bold'>{}</span>".format(
GLib.markup_escape_text(data.name)))
child.catalogitemid_label.set_text(data.catalog_item_id)
child.reason_label.set_markup("<i>{}</i>".format(GLib.markup_escape_text(data.reason)))
if hasattr(child.new_game_button,"_signal_clicked_connector"):
child.new_game_button.disconnect(child.new_game_button._signal_clicked_connector)
child.new_game_button._signal_clicked_connector = child.new_game_button.connect('clicked',
self._on_listitem_new_game_button_clicked,
data)
if hasattr(child.remove_button,'_signal_clicked_connector'):
child.remove_button.disconnect(child.remove_button._signal_clicked_connector)
child.remove_button._signal_clicked_connector = child.remove_button.connect('clicked',
self._on_listitem_remove_button_clicked,
data)
def __remove_ignored_app(self,data:EpicIgnoredApp):
epic = Epic()
epic.remove_ignored_app(data)
for i in range(self.__liststore.get_n_items()):
item = self.__liststore.get_item(i)
if item.catalog_item_id == data.catalog_item_id:
self.__liststore.remove(i)
break
def _on_listitem_new_game_button_clicked(self,button,data:EpicIgnoredApp):
def on_dialog_response(self,dialog,response,data):
if response == Gtk.ResponseType.APPLY:
self.__remove_item(data)
game = Game("",data.name,"")
epic = Epic()
game_info = epic.find_apps()[data.catalog_item_id]
if PLATFORM_WINDOWS:
windows = EpicWindowsData("","",installdir=game_info.installdir)
else:
windows = None
game.epic = EpicGameData(data.catalog_item_id,windows)
parent = self.get_transient_for()
dialog=GameDialog(parent=parent,game=game)
dialog.connect_after('response',on_dialog_response,data)
self.hide()
dialog.present()
def _on_listitem_remove_button_clicked(self,button,data:EpicIgnoredApp):
epic = Epic()
self.__remove_ignored_app(data)
def do_response(self,response):
self.hide()
self.destroy()

View File

@ -514,10 +514,10 @@ class GameDialog(Gtk.Dialog):
grid.attach(page.installdir_entry,1,2,1,1)
vbox.append(grid)
page.filematch = self.__create_filematch_widget(_('Match Files'))
page.filematch = self.__create_file_matcher()
vbox.append(page.filematch)
page.ignorematch = self.__create_filematch_widget(_('Ignore Files'))
page.ignorematch = self.__create_ignore_matcher()
vbox.append(page.ignorematch)
page.lookup_regkeys = self.__create_registry_key_widget(_("Lookup Registry keys"))
@ -564,10 +564,10 @@ class GameDialog(Gtk.Dialog):
grid.attach(page.binary_entry,1,2,1,1)
vbox.append(grid)
page.filematch = self.__create_filematch_widget('Match Files')
page.filematch = self.__create_file_matcher()
vbox.append(page.filematch)
page.ignorematch = self.__create_filematch_widget('Ignore Files')
page.ignorematch = self.__create_ignore_matcher()
vbox.append(page.ignorematch)
page.variables = self.__create_variables_widget()
@ -607,10 +607,10 @@ class GameDialog(Gtk.Dialog):
grid.attach(page.binary_entry,1,2,1,1)
vbox.append(grid)
page.filematch = self.__create_filematch_widget('Match Files')
page.filematch = self.__create_file_matcher()
vbox.append(page.filematch)
page.ignorematch = self.__create_filematch_widget('Ignore Files')
page.ignorematch = self.__create_ignore_matcher()
vbox.append(page.ignorematch)
page.variables = self.__create_variables_widget()
@ -659,10 +659,10 @@ class GameDialog(Gtk.Dialog):
nbvbox.append(nbgrid)
nbpage.filematch = self.__create_filematch_widget('Match Files')
nbpage.filematch = self.__create_file_matcher()
nbvbox.append(nbpage.filematch)
nbpage.ignorematch = self.__create_filematch_widget('Ignore Files')
nbpage.ignorematch = self.__create_ignore_matcher()
nbvbox.append(nbpage.ignorematch)
nbpage.variables = self.__create_variables_widget()
@ -741,10 +741,10 @@ class GameDialog(Gtk.Dialog):
nbvbox.append(nbgrid)
nbpage.filematch = self.__create_filematch_widget('Match Files')
nbpage.filematch = self.__create_file_matcher()
nbvbox.append(nbpage.filematch)
nbpage.ignorematch = self.__create_filematch_widget('Ignore Files')
nbpage.ignorematch = self.__create_ignore_matcher()
nbvbox.append(nbpage.ignorematch)
nbpage.variables = self.__create_variables_widget()
@ -786,7 +786,10 @@ class GameDialog(Gtk.Dialog):
widget.set_margin_bottom(margin)
def __create_variables_widget(self):
widget = Gtk.Frame.new("Variables")
widget = Gtk.Frame()
widget.set_label_widget(
Gtk.Label(label="<span weight='bold'>{}</span>".format(GLib.markup_escape_text(_('Variables'))),
use_markup=True))
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,0)
model = Gio.ListStore.new(GameVariableData)
@ -824,11 +827,11 @@ class GameDialog(Gtk.Dialog):
widget.columnview)
widget.actions.pack_start(widget.remove_button)
name_column = Gtk.ColumnViewColumn.new("Name",self.__variable_name_factory)
name_column = Gtk.ColumnViewColumn.new(_("Name"),self.__variable_name_factory)
name_column.set_expand(True)
widget.columnview.append_column(name_column)
value_column = Gtk.ColumnViewColumn.new("Value",self.__variable_value_factory)
value_column = Gtk.ColumnViewColumn.new(_("Value"),self.__variable_value_factory)
value_column.set_expand(True)
widget.columnview.append_column(value_column)
@ -854,7 +857,10 @@ class GameDialog(Gtk.Dialog):
return dropdown
def __create_filematch_widget(self,title:str):
widget = Gtk.Frame.new(title)
widget = Gtk.Frame()
widget.set_label_widget(
Gtk.Label(label="<span weight='bold'>{}</span>".format(GLib.markup_escape_text(title)),
use_markup=True))
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
widget.actions = Gtk.ActionBar()
@ -891,8 +897,17 @@ class GameDialog(Gtk.Dialog):
return widget
def __create_file_matcher(self):
return self.__create_filematch_widget(_("Match Files"))
def __create_ignore_matcher(self):
return self.__create_filematch_widget(_("Match Files to ignore"))
def __create_registry_key_widget(self,title):
widget = Gtk.Frame.new(title)
widget = Gtk.Frame()
widget.set_label_widget(
Gtk.Label(label="<span weight='bold'>{}</span>".format(GLib.markup_escape_text(title)),
use_markup=True))
vbox=Gtk.Box.new(Gtk.Orientation.VERTICAL,2)
widget.actions = Gtk.ActionBar()

View File

@ -225,19 +225,29 @@ class SettingsDialog(Gtk.Dialog):
search_frame = self.create_frame('Search Settings')
search_grid = self.create_grid()
label = self.create_label("Case sensitive search:")
page.search_casesensitive_switch = Gtk.Switch()
page.search_casesensitive_switch.set_active(settings.search_case_sensitive)
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL,0)
hbox.append(Gtk.Label(hexpand=True))
hbox.append(page.search_casesensitive_switch)
hbox.set_hexpand(True)
search_grid.attach(label,0,0,1,1)
search_grid.attach(hbox,1,0,1,1)
label = self.create_label("Minimum Characters:")
page.search_minchars_spinbutton = Gtk.SpinButton.new_with_range(1,32,1)
page.search_minchars_spinbutton.set_value(settings.search_min_chars)
page.search_minchars_spinbutton.set_hexpand(True)
search_grid.attach(label,0,0,1,1)
search_grid.attach(page.search_minchars_spinbutton,1,0,1,1)
search_grid.attach(label,0,1,1,1)
search_grid.attach(page.search_minchars_spinbutton,1,1,1,1)
label = self.create_label("Maximum Results:")
page.search_maxresults_spinbutton = Gtk.SpinButton.new_with_range(1,100,1)
page.search_maxresults_spinbutton.set_value(settings.search_max_results)
page.search_maxresults_spinbutton.set_hexpand(True)
search_grid.attach(label,0,1,1,1)
search_grid.attach(page.search_maxresults_spinbutton,1,1,1,1)
search_grid.attach(label,0,2,1,1)
search_grid.attach(page.search_maxresults_spinbutton,1,2,1,1)
search_frame.set_child(search_grid)
vbox.append(search_frame)
@ -487,6 +497,7 @@ class SettingsDialog(Gtk.Dialog):
settings.archiver = self.general_page.archiver_dropdown.get_selected_item().key
settings.gui_autoclose_backup_dialog = self.general_page.gui_autoclose_backup_dialog_switch.get_active()
settings.gui_autoclose_restore_dialog = self.general_page.gui_autoclose_restore_dialog_switch.get_active()
settings.search_case_sensitive = self.general_page.search_casesensitive_switch.get_active()
settings.search_min_chars = self.general_page.search_minchars_spinbutton.get_value_as_int()
settings.search_max_results = self.general_page.search_maxresults_spinbutton.get_value_as_int()
settings.zipfile_compression = self.archiver_page.zf_compressor_dropdown.get_selected_item().compressor

View File

@ -359,6 +359,14 @@ class Settings(GObject.GObject):
@search_min_chars.setter
def search_min_chars(self,min_chars:int):
self.set_integer('search','minChars',min_chars)
@GObject.Property(type=bool,default=False)
def search_case_sensitive(self)->bool:
return self.get_boolean('search','caseSensitive',False)
@search_case_sensitive.setter
def search_case_sensitive(self,case_sensitive):
self.set_boolean('search','caseSensitive',bool(case_sensitive))
@GObject.Property(type=bool,default=False)
def gui_autoclose_backup_dialog(self)->bool: