diff --git a/dzgui/data/CHANGELOG.md b/dzgui/data/CHANGELOG.md index 30c1729..8e1898e 100644 --- a/dzgui/data/CHANGELOG.md +++ b/dzgui/data/CHANGELOG.md @@ -1,4 +1,5 @@ ## Added +- Setup wizard - Changelog text wrapping and formatting - Changelog ships with source - Documentation ships with source diff --git a/dzgui/strings/wizard.py b/dzgui/strings/wizard.py index ffc34fa..e2c2e7d 100644 --- a/dzgui/strings/wizard.py +++ b/dzgui/strings/wizard.py @@ -38,11 +38,12 @@ config_new_button = "Create new DZGUI 7 config from scratch" config_new_box = "A new config file will be created. Proceed to the next step." ### APIValidationPage +entry_placeholder = "Enter API key here" api_success = "API key set successfully. Please proceed to the next step." heading_steam_api = "Steam Web API key" button_web_api = "Web API setup link" blurb_steam_api = """ -You will need to set up a Steam Web API key in order to browse the global server list. +You must set up a Steam Web API key in order to browse the global server list. \nIf you don't have one already, it can be set up via the page below. \nPlease refer to the DZGUI documentation for more instructions. """ @@ -52,7 +53,18 @@ by numeric ID on the web. For example, in the URL https://www.battlemetrics.net/ the ID would be 24819107. """ -entry_placeholder = "Enter API key here" +### PreferencesPage +heading_prefs = "User preferences" +blurb_prefs = """Here you can set up some basic settings. Additional preferences can be\n +configured via the Options menu once DZGUI launches. +""" +label_player = "Player name" +placeholder_player = "Set an in-game player name" +radio_km = "km (kilometers)" +radio_mi = "mi (miles)" +label_dist = "Distance display" +label_client = "Steam client" + ### Completion page heading_completion = "Setup complete" diff --git a/dzgui/views/components/misc.py b/dzgui/views/components/misc.py new file mode 100644 index 0000000..b959046 --- /dev/null +++ b/dzgui/views/components/misc.py @@ -0,0 +1,35 @@ +from dzgui.strings import options +from dzgui.const.constants import FLATPAK_RUN_CMD, FLATPAK_SANDBOX, STEAM_CMD + +import gi + +gi.require_version("Gtk", "3.0") +from gi.repository import Gtk # noqa + + +class ClientCombo(Gtk.ComboBox): + def __init__(self) -> None: + super().__init__() + + self.client_store = Gtk.ListStore(str, str) + clients = ( + ( + options.steam_combo, + STEAM_CMD, + ), + ( + options.flatpak_combo, + FLATPAK_RUN_CMD, + ), + ( + options.flatpak_container_combo, + FLATPAK_SANDBOX, + ), + ) + for client in clients: + self.client_store.append(client) + self.set_model(self.client_store) # Text() + renderer_text = Gtk.CellRendererText() + self.pack_start(renderer_text, True) + self.add_attribute(renderer_text, "text", 0) + self.set_active(0) diff --git a/dzgui/views/dialogs/wizard.py b/dzgui/views/dialogs/wizard.py index f49fbe6..46fd683 100644 --- a/dzgui/views/dialogs/wizard.py +++ b/dzgui/views/dialogs/wizard.py @@ -13,8 +13,8 @@ from dzgui.const.constants import ( HERO_PATH, LEGACY_CONFIG_PATH, ) +from dzgui.const.boilerplate import config_boilerplate from dzgui.const.endpoints import BM_API_SETUP, STEAM_API_SETUP - from dzgui.init.migrate import migrate_legacy_conf from dzgui.managers.threading import call_on_thread, StoredFunc, ThreadingManager from dzgui.strings import wizard @@ -23,14 +23,16 @@ from dzgui.util.open_links import open_link_by_url from dzgui.util.css import add_class from dzgui.views.components.buttons import WebButton from dzgui.views.components.entry import APIEntry +from dzgui.views.components.misc import ClientCombo import gi gi.require_version("Gtk", "3.0") -gi.require_version("Gdk", "3.0") from gi.repository import Gdk, Gtk, GLib, GObject, GdkPixbuf # noqa E402 +# TODO: currently unused, corresponds to linear index +# TODO: use of pagenum enum and page_type attribute is redundant class PageNum(Enum): INTRO = 1 HAS_CONFIG = 2 @@ -334,7 +336,7 @@ class ConfigMigrationPage(ScrolledWizardPage): EMITTER.emit("step_complete") EMITTER.emit("config", False) - def get_migrated(self) -> bool: + def is_migrated(self) -> bool: return self.migrated def _on_import_clicked(self, button: Gtk.Button) -> None: @@ -349,6 +351,67 @@ class ConfigMigrationPage(ScrolledWizardPage): EMITTER.emit("config", True) +class PreferencesPage(ScrolledWizardPage): + def __init__(self) -> None: + super().__init__( + enum=PageNum.USER_PREFS, + heading=wizard.heading_prefs, + description=wizard.blurb_prefs, + ) + self.page_type = Gtk.AssistantPageType.INTRO + + # TODO: widgets and strings are largely a reimplementation of options page, consolidate + name_label = Gtk.Label(label=wizard.label_player) + self.name_box = Gtk.Box( + orientation=Gtk.Orientation.HORIZONTAL, spacing=10, halign=Gtk.Align.CENTER + ) + self.name_entry = Gtk.Entry(placeholder_text=wizard.placeholder_player) + self.name_entry.connect("changed", self._on_entry_changed) + self.name_box.add(name_label) + self.name_box.add(self.name_entry) + + self.dist_box = Gtk.Box( + orientation=Gtk.Orientation.HORIZONTAL, spacing=10, halign=Gtk.Align.CENTER + ) + self.radio_km = Gtk.RadioButton.new_with_label(None, wizard.radio_km) + self.radio_miles = Gtk.RadioButton.new_with_label_from_widget( + self.radio_km, wizard.radio_mi + ) + dist_label = Gtk.Label(label=wizard.label_dist) + self.dist_box.add(dist_label) + self.dist_box.add(self.radio_km) + self.dist_box.add(self.radio_miles) + + client_label = Gtk.Label(label=wizard.label_client) + self.client_box = Gtk.Box( + orientation=Gtk.Orientation.HORIZONTAL, spacing=10, halign=Gtk.Align.CENTER + ) + self.client_combo = ClientCombo() + self.client_box.add(client_label) + self.client_box.add(self.client_combo) + + for el in self.name_box, self.dist_box, self.client_box: + self.add_start(el) + + def get_prefs(self) -> None: + name = self.name_entry.get_text().strip() + use_miles = self.radio_miles.get_active() + model = self.client_combo.get_model() + ind = self.client_combo.get_active() + client = model[ind][1] + print(name) + print(use_miles) + print(client) + return name, use_miles, client + + def _on_entry_changed(self, entry: Gtk.Entry) -> None: + text = entry.get_text() + if text.isspace(): + EMITTER.emit("step_pending") + return + EMITTER.emit("step_complete") + + class CompletionPage(ScrolledWizardPage): def __init__(self) -> None: super().__init__( @@ -356,7 +419,6 @@ class CompletionPage(ScrolledWizardPage): heading=wizard.heading_completion, description=wizard.blurb_completion, ) - # TODO: show collapsible config file tree self.page_type = Gtk.AssistantPageType.SUMMARY self.connect("map", lambda _: EMITTER.emit("step_complete")) @@ -371,8 +433,6 @@ class Assistant(Gtk.Assistant): self.set_default_size(1500, 900) self.config_path = config - # TODO: read in from boilerplate file - from dzgui.const.boilerplate import config_boilerplate self.config_values: dict[str, Any] = config_boilerplate @@ -381,16 +441,7 @@ class Assistant(Gtk.Assistant): self.page3 = SteamPathPage() self.page4 = SteamValidationPage() self.page5 = BMValidationPage() - - # self.page6 = PreferencesPage() - # contains name, miles, and steam client choice - # self.name = Gtk.Entry() - # self.miles = Gtk.RadioButton() - # TODO: use dual column model, recycle into options - # TODO: update client_combo in options page - # self.client = Gtk.ComboBox() - # TODO: write to config if not present - + self.page6 = PreferencesPage() self.page7 = CompletionPage() self.set_forward_page_func(self._advance_page) @@ -407,6 +458,7 @@ class Assistant(Gtk.Assistant): self.page3, self.page4, self.page5, + self.page6, self.page7, ): # NOTE: skip config migration page if no legacy config file @@ -420,9 +472,6 @@ class Assistant(Gtk.Assistant): self.show_all() def write_config(self) -> None: - # NOTE: implies that file was already migrated on page 3 - if self.has_legacy_config: - return write_json(self.config_values, self.config_path) def _advance_page(self, index: int) -> int: @@ -431,7 +480,7 @@ class Assistant(Gtk.Assistant): case self.page1: pass case self.page2: - if self.page2.get_migrated(): + if self.page2.is_migrated(): return self.get_n_pages() - 1 case self.page3: self.config_values["default_steam_path"] = page.get_path_from_radio() @@ -439,11 +488,15 @@ class Assistant(Gtk.Assistant): self.config_values["steam_api"] = page.get_api_key() case self.page5: self.config_values["bm_api"] = page.get_api_key() - # case self.page6: - # self.write_config() + # NOTE: collects config values before advancing to last page + case self.page6: + name, use_miles, client = self.page6.get_prefs() + self.config_values["name"] = name + self.config_values["use_miles"] = use_miles + self.config_values["client"] = client + self.write_config() case _: raise AttributeError("Trying to advance a non-canonical page") - print(self.config_values) return index + 1 def destroy_and_quit(self, widget: Self) -> None: diff --git a/dzgui/views/pages/options.py b/dzgui/views/pages/options.py index 83b03cd..e38d6ea 100644 --- a/dzgui/views/pages/options.py +++ b/dzgui/views/pages/options.py @@ -9,12 +9,9 @@ from dzgui.const.constants import ( APPID_DAYZ_EXP, APPNAME_DAYZ, APPNAME_DAYZ_EXP_HUMAN, - FLATPAK_RUN_CMD, - FLATPAK_SANDBOX, NO_EXPAND, NO_FILL, NO_PADDING, - STEAM_CMD, VIEW_CONCEAL, VIEW_REVEAL, ) @@ -27,6 +24,7 @@ from dzgui.views.components.labels import LeftLabel from dzgui.views.components.eventbox import InfoEventBox from dzgui.views.components.buttons import WebButton from dzgui.views.components.frame import HeadingFrame +from dzgui.views.components.misc import ClientCombo from dzgui.views.dialogs.generic import ExceptionDialog @@ -101,29 +99,7 @@ class Options(Gtk.Box): Preferences.WINDOW, ) - # TODO: make this an abstract class - client_store = Gtk.ListStore(str, str) - clients = ( - ( - options.steam_combo, - STEAM_CMD, - ), - ( - options.flatpak_combo, - FLATPAK_RUN_CMD, - ), - ( - options.flatpak_container_combo, - FLATPAK_SANDBOX, - ), - ) - for client in clients: - client_store.append(client) - self.client_combo = Gtk.ComboBox.new_with_model(client_store) # Text() - renderer_text = Gtk.CellRendererText() - self.client_combo.pack_start(renderer_text, True) - self.client_combo.add_attribute(renderer_text, "text", 0) - self.client_combo.set_active(0) + self.client_combo = ClientCombo() self.client_combo.connect("changed", self._on_client_changed) client_hbox = ShortHBox(self.client_combo)