backend rewrite cont, rebrand
This commit is contained in:
@@ -6,66 +6,24 @@ import json
|
||||
import os
|
||||
import math
|
||||
|
||||
from pathlib import Path, cwd
|
||||
from dataclasses import dataclass
|
||||
|
||||
|
||||
from gi.repository import Gio, GLib, GObject
|
||||
|
||||
# pseudo struct that contains the profile data that gets serialized into the .json profile.
|
||||
@dataclass
|
||||
class Profile:
|
||||
# Dictionary that stores the ownership status of frames
|
||||
owned_frames: [str, bool]
|
||||
unique_frames_owned: int
|
||||
missing_basics: [str]
|
||||
missing_basics_count: int
|
||||
missing_primes: [str]
|
||||
missing_primes_count: int
|
||||
|
||||
|
||||
class Backend():
|
||||
|
||||
# warframe counts
|
||||
# TODO Update via API/wiki
|
||||
BASIC_WARFRAMES = 63
|
||||
PRIME_WARFRAMES = 49
|
||||
CURRENT_UPDATE = 41
|
||||
|
||||
# Profile
|
||||
profile: Profile
|
||||
|
||||
# tracks whether the onboarding dialogue should be shown
|
||||
fresh_install = True
|
||||
|
||||
def get_config_dir(app_id: str) -> Path:
|
||||
base = Path(GLib.get_user_config_dir())
|
||||
cfg_dir = base / app_id
|
||||
cfg_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cfg_dir
|
||||
|
||||
# helpers for profile loading
|
||||
APP_ID = "gay.valhrafnaz.Gnomeframe"
|
||||
CONFIG_DIR = get_config_dir(APP_ID)
|
||||
CONFIG_FILE = CONFIG_DIR / "profile.json"
|
||||
|
||||
|
||||
def __init__():
|
||||
loaded_profile: dict[str, bool] = Backend.load_profile()
|
||||
super().__init__()
|
||||
# load profile
|
||||
|
||||
|
||||
|
||||
def load_profile() -> dict[str, bool]:
|
||||
try:
|
||||
with Backend.CONFIG_FILE.open("r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return {k: bool(v) for k, v in data.items()}
|
||||
except FileNotFoundError:
|
||||
return {}
|
||||
except (json.JSONDecodeError, OSError) as exc:
|
||||
print(f"Could not load profile: {exc}")
|
||||
return {}
|
||||
|
||||
def save_profile(state: dict[str, bool]) -> None:
|
||||
try:
|
||||
Backend.CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
with Backend.CONFIG_FILE.open("w", encoding="utf-8") as f:
|
||||
json.dump(state, f, indent=2, sort_keys=True)
|
||||
except OSError as exc:
|
||||
print(f"Failed to write profile: {exc}")
|
||||
|
||||
123
src/gnomeframe/constants.py
Normal file
123
src/gnomeframe/constants.py
Normal file
@@ -0,0 +1,123 @@
|
||||
EXISTING_FRAMES_BASIC = [
|
||||
"ash",
|
||||
"atlas",
|
||||
"banshee",
|
||||
"baruuk",
|
||||
"caliban",
|
||||
"chroma",
|
||||
"citrine",
|
||||
"cyte09",
|
||||
"dagath",
|
||||
"dante",
|
||||
"ember",
|
||||
"equinox",
|
||||
"excalibur",
|
||||
"frost",
|
||||
"gara",
|
||||
"garuda",
|
||||
"gauss",
|
||||
"grendel",
|
||||
"gyre",
|
||||
"harrow",
|
||||
"hildryn",
|
||||
"hydroid",
|
||||
"inaros",
|
||||
"ivara",
|
||||
"jade",
|
||||
"khora",
|
||||
"koumei",
|
||||
"kullervo",
|
||||
"lavos",
|
||||
"limbo",
|
||||
"loki",
|
||||
"mag",
|
||||
"mesa",
|
||||
"mirage",
|
||||
"nekros",
|
||||
"nezha",
|
||||
"nidus",
|
||||
"nokko",
|
||||
"nova",
|
||||
"nyx",
|
||||
"oberon",
|
||||
"octavia",
|
||||
"oraxia",
|
||||
"protea",
|
||||
"qorvex",
|
||||
"revenant",
|
||||
"rhino",
|
||||
"saryn",
|
||||
"sevagoth",
|
||||
"styanax",
|
||||
"temple",
|
||||
"titania",
|
||||
"trinity",
|
||||
"uriel",
|
||||
"valkyr",
|
||||
"vauban",
|
||||
"volt",
|
||||
"voruna",
|
||||
"wisp",
|
||||
"wukong",
|
||||
"xaku",
|
||||
"yareli",
|
||||
"zephyr",
|
||||
]
|
||||
|
||||
EXISTING_FRAMES_PRIME = [
|
||||
"ash_prime",
|
||||
"atlas_prime",
|
||||
"banshee_prime",
|
||||
"baruuk_prime",
|
||||
"caliban_prime",
|
||||
"chroma_prime",
|
||||
"ember_prime",
|
||||
"equinox_prime",
|
||||
"excalibur_umbra",
|
||||
"frost_prime",
|
||||
"gara_prime",
|
||||
"garuda_prime",
|
||||
"gauss_prime",
|
||||
"grendel_prime",
|
||||
"gyre_prime",
|
||||
"harrow_prime",
|
||||
"hildryn_prime",
|
||||
"hydroid_prime",
|
||||
"inaros_prime",
|
||||
"ivara_prime",
|
||||
"khora_prime",
|
||||
"lavos_prime",
|
||||
"limbo_prime",
|
||||
"loki_prime",
|
||||
"mag_prime",
|
||||
"mesa_prime",
|
||||
"mirage_prime",
|
||||
"nekros_prime",
|
||||
"nezha_prime",
|
||||
"nidus_prime",
|
||||
"nova_prime",
|
||||
"nyx_prime",
|
||||
"oberon_prime",
|
||||
"octavia_prime",
|
||||
"protea_prime",
|
||||
"revenant_prime",
|
||||
"rhino_prime",
|
||||
"saryn_prime",
|
||||
"sevagoth_prime",
|
||||
"titania_prime",
|
||||
"trinity_prime",
|
||||
"valkyr_prime",
|
||||
"vauban_prime",
|
||||
"volt_prime",
|
||||
"wisp_prime",
|
||||
"wukong_prime",
|
||||
"xaku_prime",
|
||||
"yareli_prime",
|
||||
"zephyr_prime"
|
||||
]
|
||||
|
||||
# warframe counts
|
||||
# TODO Update via API/wiki
|
||||
BASIC_WARFRAMES = 63
|
||||
PRIME_WARFRAMES = 49
|
||||
CURRENT_UPDATE = 41
|
||||
@@ -1,6 +1,6 @@
|
||||
# main.py
|
||||
#
|
||||
# Copyright 2025 nihil
|
||||
# Copyright 2025 valhrafnaz
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
@@ -16,24 +16,57 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import sys
|
||||
import gi
|
||||
import os
|
||||
import json
|
||||
import math
|
||||
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
# local imports
|
||||
from .window import VoidManifestWindow
|
||||
from .profile import Profile
|
||||
from .constants import EXISTING_FRAMES_BASIC, EXISTING_FRAMES_PRIME, BASIC_WARFRAMES, PRIME_WARFRAMES, CURRENT_UPDATE
|
||||
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
|
||||
from gi.repository import Gtk, Gio, Adw, GLib
|
||||
from .window import GnomeframeWindow
|
||||
from gi.repository import Gtk, Gio, Adw, GLib, GObject # noqa: E402
|
||||
|
||||
def get_config_dir(app_id: str) -> Path:
|
||||
base = Path(GLib.get_user_config_dir())
|
||||
cfg_dir = base / app_id
|
||||
cfg_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cfg_dir
|
||||
|
||||
|
||||
class GnomeframeApplication(Adw.Application):
|
||||
|
||||
class VoidManifestApplication(Adw.Application):
|
||||
|
||||
# Profile
|
||||
profile: Profile
|
||||
|
||||
# tracks whether the onboarding dialogue should be shown
|
||||
fresh_install = True
|
||||
|
||||
def get_config_dir(app_id: str) -> Path:
|
||||
base = Path(GLib.get_user_config_dir())
|
||||
cfg_dir = base / app_id
|
||||
cfg_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cfg_dir
|
||||
|
||||
# helpers for profile loading
|
||||
APP_ID = "gay.valhrafnaz.VoidManifest"
|
||||
CONFIG_DIR = get_config_dir(APP_ID)
|
||||
CONFIG_FILE = CONFIG_DIR / "profile.json"
|
||||
|
||||
"""The main application singleton class."""
|
||||
def __init__(self):
|
||||
super().__init__(application_id='gay.valhrafnaz.Gnomeframe',
|
||||
super().__init__(application_id='gay.valhrafnaz.VoidManifest',
|
||||
flags=Gio.ApplicationFlags.DEFAULT_FLAGS,
|
||||
resource_base_path='/gay/valhrafnaz/Gnomeframe')
|
||||
resource_base_path='/gay/valhrafnaz/VoidManifest')
|
||||
|
||||
data_dir = GLib.get_system_data_dirs()[0]
|
||||
resource = Gio.resource_load(os.path.join(data_dir, 'gnomeframe', 'gnomeframe.gresource'))
|
||||
@@ -43,6 +76,10 @@ class GnomeframeApplication(Adw.Application):
|
||||
self.create_action('about', self.on_about_action)
|
||||
self.create_action('preferences', self.on_preferences_action)
|
||||
|
||||
self.CONFIG_DIR = get_config_dir(self.APP_ID)
|
||||
|
||||
self.profile = self.load_profile()
|
||||
|
||||
def do_activate(self):
|
||||
"""Called when the application is activated.
|
||||
|
||||
@@ -51,17 +88,17 @@ class GnomeframeApplication(Adw.Application):
|
||||
"""
|
||||
win = self.props.active_window
|
||||
if not win:
|
||||
win = GnomeframeWindow(application=self)
|
||||
win = VoidManifestWindow(application=self)
|
||||
win.present()
|
||||
|
||||
def on_about_action(self, *args):
|
||||
"""Callback for the app.about action."""
|
||||
about = Adw.AboutDialog(application_name='gnomeframe',
|
||||
application_icon='gay.valhrafnaz.Gnomeframe',
|
||||
application_icon='gay.valhrafnaz.VoidManifest',
|
||||
developer_name='valhrafnaz',
|
||||
version='0.1.0',
|
||||
developers=['valhrafnaz'],
|
||||
copyright='© 2025 nihil')
|
||||
copyright='© 2025 valhrafnaz')
|
||||
# Translators: Replace "translator-credits" with your name/username, and optionally an email or URL.
|
||||
about.set_translator_credits(_('translator-credits'))
|
||||
about.present(self.props.active_window)
|
||||
@@ -85,8 +122,69 @@ class GnomeframeApplication(Adw.Application):
|
||||
if shortcuts:
|
||||
self.set_accels_for_action(f"app.{name}", shortcuts)
|
||||
|
||||
def load_profile(self) -> Profile:
|
||||
try:
|
||||
with open(self.CONFIG_FILE, 'r') as f:
|
||||
data = json.load(f)
|
||||
return Profile(**data)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
return Profile() # Uses defaults
|
||||
|
||||
def save_profile(self, profile) -> None:
|
||||
self.refresh_profile()
|
||||
profile_path = self.CONFIG_FILE
|
||||
with open(profile_path, 'w') as f:
|
||||
json.dump(profile.to_dict(), f, indent=2)
|
||||
|
||||
def reset_frames(self, param):
|
||||
self.profile.owned_frames = {}
|
||||
button = self.checklist_page.btns_basic.get_first_child()
|
||||
while button is not None:
|
||||
if isinstance(button, Gtk.ToggleButton):
|
||||
button.set_active(False)
|
||||
button = button.get_next_sibling()
|
||||
button = self.checklist_page.btns_prime.get_first_child()
|
||||
while button is not None:
|
||||
if isinstance(button, Gtk.ToggleButton):
|
||||
button.set_active(False)
|
||||
button = button.get_next_sibling()
|
||||
self.save_profile(self.profile)
|
||||
|
||||
def refresh_profile(self):
|
||||
# count basics
|
||||
basic_count = 0
|
||||
missing_basics: list[str] = []
|
||||
for basic_frame in EXISTING_FRAMES_BASIC:
|
||||
if self.profile.owned_frames.get(basic_frame, False):
|
||||
basic_count = basic_count + 1
|
||||
else:
|
||||
missing_basics.append(basic_frame)
|
||||
# count primes
|
||||
prime_count = 0
|
||||
missing_primes: list[str] = []
|
||||
for prime_frame in EXISTING_FRAMES_PRIME:
|
||||
if self.profile.owned_frames.get(prime_frame, False):
|
||||
prime_count = prime_count + 1
|
||||
else:
|
||||
missing_primes.append(prime_frame)
|
||||
# count unique
|
||||
unique_frames: set[str] = set()
|
||||
for owned_frame, is_owned in self.profile.owned_frames.items():
|
||||
if is_owned:
|
||||
_name = owned_frame.removesuffix("_prime")
|
||||
_name = _name.removesuffix("_umbra")
|
||||
unique_frames.add(_name)
|
||||
|
||||
self.profile.missing_basics_count = len(missing_basics)
|
||||
self.profile.missing_primes_count = len(missing_primes)
|
||||
self.profile.unique_frames_owned = len(unique_frames)
|
||||
self.profile.missing_basics = missing_basics
|
||||
self.profile.missing_primes = missing_primes
|
||||
|
||||
|
||||
|
||||
|
||||
def main(version):
|
||||
"""The application's entry point."""
|
||||
app = GnomeframeApplication()
|
||||
app = VoidManifestApplication()
|
||||
return app.run(sys.argv)
|
||||
|
||||
@@ -1,168 +1,18 @@
|
||||
import json
|
||||
import os
|
||||
import math
|
||||
import gi
|
||||
from pathlib import Path
|
||||
from gi.repository import Gtk, Adw, GObject, GLib
|
||||
|
||||
def get_config_dir(app_id: str) -> Path:
|
||||
base = Path(GLib.get_user_config_dir())
|
||||
cfg_dir = base / app_id
|
||||
cfg_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cfg_dir
|
||||
from ..constants import BASIC_WARFRAMES, PRIME_WARFRAMES
|
||||
|
||||
APP_ID = "gay.valhrafnaz.Gnomeframe"
|
||||
CONFIG_DIR = get_config_dir(APP_ID)
|
||||
CONFIG_FILE = CONFIG_DIR / "profile.json"
|
||||
TOTAL_WARFRAMES=63 # post uriel, valid until whenever really
|
||||
TOTAL_PRIMES=49 # post gyre prime, valid until ca. may-2026
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
|
||||
from gi.repository import Gtk, Adw, GObject, GLib # noqa: E402
|
||||
|
||||
|
||||
def load_profile() -> dict[str, bool]:
|
||||
try:
|
||||
with CONFIG_FILE.open("r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return {k: bool(v) for k, v in data.items()}
|
||||
except FileNotFoundError:
|
||||
return {}
|
||||
except (json.JSONDecodeError, OSError) as exc:
|
||||
print(f"Could not load profile: {exc}")
|
||||
return {}
|
||||
|
||||
def save_profile(state: dict[str, bool]) -> None:
|
||||
try:
|
||||
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
with CONFIG_FILE.open("w", encoding="utf-8") as f:
|
||||
json.dump(state, f, indent=2, sort_keys=True)
|
||||
except OSError as exc:
|
||||
print(f"Failed to write profile: {exc}")
|
||||
|
||||
frame_button_ids = [
|
||||
"ash",
|
||||
"atlas",
|
||||
"banshee",
|
||||
"baruuk",
|
||||
"caliban",
|
||||
"chroma",
|
||||
"citrine",
|
||||
"cyte09",
|
||||
"dagath",
|
||||
"dante",
|
||||
"ember",
|
||||
"equinox",
|
||||
"exalibur",
|
||||
"frost",
|
||||
"gara",
|
||||
"garuda",
|
||||
"gauss",
|
||||
"grendel",
|
||||
"gyre",
|
||||
"harrow",
|
||||
"hildryn",
|
||||
"hydroid",
|
||||
"inaros",
|
||||
"ivara",
|
||||
"jade",
|
||||
"khora",
|
||||
"koumei",
|
||||
"kullervo",
|
||||
"lavos",
|
||||
"limbo",
|
||||
"loki",
|
||||
"mag",
|
||||
"mesa",
|
||||
"mirage" "nekros",
|
||||
"nezha",
|
||||
"nidus",
|
||||
"nokko",
|
||||
"nova",
|
||||
"nyx",
|
||||
"oberon",
|
||||
"octavia",
|
||||
"oraxia",
|
||||
"protea",
|
||||
"qorvex",
|
||||
"revenant",
|
||||
"rhino",
|
||||
"saryn",
|
||||
"sevagoth",
|
||||
"styanax",
|
||||
"temple",
|
||||
"titania",
|
||||
"trinity",
|
||||
"valkyr",
|
||||
"vauban",
|
||||
"volt",
|
||||
"voruna",
|
||||
"wisp",
|
||||
"wukong",
|
||||
"xaku",
|
||||
"yareli",
|
||||
"zephyr",
|
||||
"ash_prime",
|
||||
"atlas_prime",
|
||||
"banshee_prime",
|
||||
"baruuk_prime",
|
||||
"caliban_prime",
|
||||
"chroma_prime",
|
||||
"citrine_prime",
|
||||
"cyte09_prime",
|
||||
"dagath_prime",
|
||||
"dante_prime",
|
||||
"ember_prime",
|
||||
"equinox_prime",
|
||||
"exalibur_umbra",
|
||||
"frost_prime",
|
||||
"gara_prime",
|
||||
"garuda_prime",
|
||||
"gauss_prime",
|
||||
"grendel_prime",
|
||||
"gyre_prime",
|
||||
"harrow_prime",
|
||||
"hildryn_prime",
|
||||
"hydroid_prime",
|
||||
"inaros_prime",
|
||||
"ivara_prime",
|
||||
"jade_prime",
|
||||
"khora_prime",
|
||||
"koumei_prime",
|
||||
"kullervo_prime",
|
||||
"lavos_prime",
|
||||
"limbo_prime",
|
||||
"loki_prime",
|
||||
"mag_prime",
|
||||
"mesa_prime",
|
||||
"mirage_prime" "nekros_prime",
|
||||
"nezha_prime",
|
||||
"nidus_prime",
|
||||
"nokko_prime",
|
||||
"nova_prime",
|
||||
"nyx_prime",
|
||||
"oberon_prime",
|
||||
"octavia_prime",
|
||||
"oraxia_prime",
|
||||
"protea_prime",
|
||||
"qorvex_prime",
|
||||
"revenant_prime",
|
||||
"rhino_prime",
|
||||
"saryn_prime",
|
||||
"sevagoth_prime",
|
||||
"styanax_prime",
|
||||
"temple_prime",
|
||||
"titania_prime",
|
||||
"trinity_prime",
|
||||
"valkyr_prime",
|
||||
"vauban_prime",
|
||||
"volt_prime",
|
||||
"voruna_prime",
|
||||
"wisp_prime",
|
||||
"wukong_prime",
|
||||
"xaku_prime",
|
||||
"yareli_prime",
|
||||
"zephyr_prime",
|
||||
]
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/gay/valhrafnaz/Gnomeframe/ui/checklist.ui")
|
||||
@Gtk.Template(resource_path="/gay/valhrafnaz/VoidManifest/ui/checklist.ui")
|
||||
class ChecklistPage(Gtk.Box):
|
||||
__gtype_name__ = "ChecklistPage"
|
||||
|
||||
@@ -171,17 +21,21 @@ class ChecklistPage(Gtk.Box):
|
||||
btns_basic = Gtk.Template.Child()
|
||||
btns_prime = Gtk.Template.Child()
|
||||
basic_counter = Gtk.Template.Child()
|
||||
basic_max = Gtk.Template.Child()
|
||||
basic_percent = Gtk.Template.Child()
|
||||
prime_counter = Gtk.Template.Child()
|
||||
prime_max = Gtk.Template.Child()
|
||||
prime_percent = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, *, parent: Adw.ViewStack, window):
|
||||
super().__init__()
|
||||
self._parent_window = window
|
||||
self.app = self._parent_window.get_application()
|
||||
parent.add_titled(self, "checklist", "Checklist")
|
||||
wrapper = parent.get_page(self)
|
||||
wrapper.set_icon_name("check-round-outline2-symbolic")
|
||||
|
||||
self.basic_max.set_label(str(BASIC_WARFRAMES))
|
||||
self.prime_max.set_label(str(PRIME_WARFRAMES))
|
||||
self._connect_frame_btns()
|
||||
self._calc_frames()
|
||||
|
||||
@@ -190,14 +44,14 @@ class ChecklistPage(Gtk.Box):
|
||||
while button is not None:
|
||||
if isinstance(button, Gtk.ToggleButton):
|
||||
btn_id = button.get_name()
|
||||
button.set_active(self._parent_window._profile.get(btn_id, False))
|
||||
button.set_active(self.app.profile.owned_frames.get(btn_id, False))
|
||||
button.connect("toggled", self._on_button_toggled)
|
||||
button = button.get_next_sibling()
|
||||
button = self.btns_prime.get_first_child()
|
||||
while button is not None:
|
||||
if isinstance(button, Gtk.ToggleButton):
|
||||
btn_id = button.get_name()
|
||||
button.set_active(self._parent_window._profile.get(btn_id, False))
|
||||
button.set_active(self.app.profile.owned_frames.get(btn_id, False))
|
||||
button.connect("toggled", self._on_button_toggled)
|
||||
button = button.get_next_sibling()
|
||||
|
||||
@@ -223,9 +77,9 @@ class ChecklistPage(Gtk.Box):
|
||||
|
||||
def _calc_frames(self):
|
||||
basic_counter = self._count_basics()
|
||||
basic_percent = math.trunc(basic_counter / TOTAL_WARFRAMES * 100)
|
||||
basic_percent = math.trunc(basic_counter / BASIC_WARFRAMES * 100)
|
||||
prime_counter = self._count_primes()
|
||||
prime_percent = math.trunc(prime_counter / TOTAL_PRIMES * 100)
|
||||
prime_percent = math.trunc(prime_counter / PRIME_WARFRAMES * 100)
|
||||
self.basic_counter.set_label(str(basic_counter))
|
||||
self.basic_percent.set_label(str(basic_percent))
|
||||
self.prime_counter.set_label(str(prime_counter))
|
||||
@@ -236,8 +90,8 @@ class ChecklistPage(Gtk.Box):
|
||||
if btn_id == "GtkToggleButton":
|
||||
print("what")
|
||||
return
|
||||
self._parent_window._profile[btn_id] = btn.get_active()
|
||||
save_profile(self._parent_window._profile)
|
||||
self.app.profile.owned_frames[btn_id] = btn.get_active()
|
||||
self.app.save_profile(self.app.profile)
|
||||
self._calc_frames()
|
||||
|
||||
|
||||
|
||||
@@ -1,9 +1,23 @@
|
||||
from gi.repository import Gtk, Adw, GObject, GLib
|
||||
import gi
|
||||
|
||||
@Gtk.Template(resource_path="/gay/valhrafnaz/Gnomeframe/ui/home.ui")
|
||||
from ..constants import BASIC_WARFRAMES, PRIME_WARFRAMES
|
||||
|
||||
gi.require_version('Gtk', '4.0')
|
||||
gi.require_version('Adw', '1')
|
||||
|
||||
from gi.repository import Gtk, Adw, GObject, GLib # noqa: E402
|
||||
|
||||
|
||||
@Gtk.Template(resource_path="/gay/valhrafnaz/VoidManifest/ui/home.ui")
|
||||
class HomePage(Gtk.Box):
|
||||
__gtype_name__ = "HomePage"
|
||||
|
||||
owned_frames = Gtk.Template.Child()
|
||||
owned_basics = Gtk.Template.Child()
|
||||
missing_basics = Gtk.Template.Child()
|
||||
owned_primes = Gtk.Template.Child()
|
||||
missing_primes = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, *, parent: Adw.ViewStack):
|
||||
"""
|
||||
`parent` is the ViewStack that will host this page.
|
||||
@@ -14,3 +28,13 @@ class HomePage(Gtk.Box):
|
||||
parent.add_titled(self, "home", "Home")
|
||||
wrapper = parent.get_page(self)
|
||||
wrapper.set_icon_name("compass2-symbolic")
|
||||
self.app = self.get_root().get_application()
|
||||
self.app.profile._on_change = self.refresh
|
||||
self.refresh()
|
||||
|
||||
def refresh(self):
|
||||
self.owned_frames.set_label(str (self.app.profile.unique_frames_owned))
|
||||
self.owned_basics.set_label(str (BASIC_WARFRAMES - self.app.profile.missing_basics_count))
|
||||
self.owned_primes.set_label(str (PRIME_WARFRAMES - self.app.profile.missing_primes_count))
|
||||
self.missing_basics.set_label(str(self.app.profile.missing_basics_count))
|
||||
self.missing_primes.set_label(str(self.app.profile.missing_primes_count))
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from gi.repository import Gtk, Adw, GObject, GLib
|
||||
|
||||
@Gtk.Template(resource_path="/gay/valhrafnaz/Gnomeframe/ui/settings.ui")
|
||||
@Gtk.Template(resource_path="/gay/valhrafnaz/VoidManifest/ui/settings.ui")
|
||||
class SettingsPage(Gtk.Box):
|
||||
__gtype_name__ = "SettingsPage"
|
||||
|
||||
|
||||
29
src/gnomeframe/profile.py
Normal file
29
src/gnomeframe/profile.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from dataclasses import fields, field, dataclass
|
||||
from typing import Callable
|
||||
from .constants import BASIC_WARFRAMES, PRIME_WARFRAMES
|
||||
|
||||
# pseudo struct that contains the profile data that gets serialized into the .json profile.
|
||||
@dataclass
|
||||
class Profile:
|
||||
owned_frames: dict[str, bool] = field(default_factory=dict)
|
||||
unique_frames_owned: int = 0
|
||||
missing_basics: list[str] = field(default_factory=list)
|
||||
missing_basics_count: int = BASIC_WARFRAMES
|
||||
missing_primes: list[str] = field(default_factory=list)
|
||||
missing_primes_count: int = PRIME_WARFRAMES
|
||||
|
||||
_on_change: Callable | None = field(default=None, repr=False, compare=False)
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
super().__setattr__(name, value)
|
||||
# Notify on change (skip private attributes)
|
||||
if not name.startswith('_') and hasattr(self, '_on_change') and self._on_change:
|
||||
self._on_change()
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
"""Convert to dict, excluding private fields"""
|
||||
return {
|
||||
f.name: getattr(self, f.name)
|
||||
for f in fields(self)
|
||||
if not f.name.startswith('_')
|
||||
}
|
||||
@@ -29,85 +29,32 @@ from gi.repository import Adw
|
||||
from gi.repository import Gtk, Gio
|
||||
from gi.repository import GLib
|
||||
|
||||
def get_config_dir(app_id: str) -> Path:
|
||||
base = Path(GLib.get_user_config_dir())
|
||||
cfg_dir = base / app_id
|
||||
cfg_dir.mkdir(parents=True, exist_ok=True)
|
||||
return cfg_dir
|
||||
|
||||
APP_ID = "gay.valhrafnaz.Gnomeframe"
|
||||
CONFIG_DIR = get_config_dir(APP_ID)
|
||||
CONFIG_FILE = CONFIG_DIR / "profile.json"
|
||||
|
||||
|
||||
def load_profile() -> dict[str, bool]:
|
||||
try:
|
||||
with CONFIG_FILE.open("r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
return {k: bool(v) for k, v in data.items()}
|
||||
except FileNotFoundError:
|
||||
return {}
|
||||
except (json.JSONDecodeError, OSError) as exc:
|
||||
print(f"Could not load profile: {exc}")
|
||||
return {}
|
||||
|
||||
def save_profile(state: dict[str, bool]) -> None:
|
||||
try:
|
||||
CONFIG_DIR.mkdir(parents=True, exist_ok=True)
|
||||
with CONFIG_FILE.open("w", encoding="utf-8") as f:
|
||||
json.dump(state, f, indent=2, sort_keys=True)
|
||||
except OSError as exc:
|
||||
print(f"Failed to write profile: {exc}")
|
||||
|
||||
|
||||
|
||||
|
||||
@Gtk.Template(resource_path='/gay/valhrafnaz/Gnomeframe/ui/window.ui')
|
||||
class GnomeframeWindow(Adw.ApplicationWindow):
|
||||
__gtype_name__ = 'GnomeframeWindow'
|
||||
@Gtk.Template(resource_path='/gay/valhrafnaz/VoidManifest/ui/window.ui')
|
||||
class VoidManifestWindow(Adw.ApplicationWindow):
|
||||
__gtype_name__ = 'VoidManifestWindow'
|
||||
|
||||
viewstack = Gtk.Template.Child()
|
||||
btn_reset_profile = Gtk.Template.Child()
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self._profile: dict[str, bool] = load_profile()
|
||||
self.app = self.get_application()
|
||||
self._load_page_templates()
|
||||
|
||||
reset_action = Gio.SimpleAction.new("reset-selections", None)
|
||||
reset_action.connect("activate", self._reset_all)
|
||||
reset_action.connect("activate", self.app.reset_frames)
|
||||
self.get_application().add_action(reset_action)
|
||||
|
||||
self.btn_reset_profile.connect("clicked", self._reset_all)
|
||||
self.btn_reset_profile.connect("clicked", self.app.reset_frames)
|
||||
self.connect("close-request", self._on_close_request)
|
||||
|
||||
# self.settings = Gio.Settings(schema_id="gay.valhrafnaz.Gnomeframe")
|
||||
# self.settings.bind("window-width", self, "default-width", Gio.SettingsBindFlags.DEFAULT)
|
||||
# self.settings.bind("window-height", self, "default-height", Gio.SettingsBindFlags.DEFAULT)
|
||||
# self.settings.bind("window-maximized", self, "maximized", Gio.SettingsBindFlags.DEFAULT)
|
||||
|
||||
def _load_page_templates(self):
|
||||
self.home_page = HomePage(parent=self.viewstack)
|
||||
self.checklist_page = ChecklistPage(parent=self.viewstack, window=self)
|
||||
self.settings_page = SettingsPage(parent=self.viewstack)
|
||||
|
||||
def _reset_all(self, param):
|
||||
self._profile.clear()
|
||||
button = self.checklist_page.btns_basic.get_first_child()
|
||||
while button is not None:
|
||||
if isinstance(button, Gtk.ToggleButton):
|
||||
button.set_active(False)
|
||||
button = button.get_next_sibling()
|
||||
button = self.checklist_page.btns_prime.get_first_child()
|
||||
while button is not None:
|
||||
if isinstance(button, Gtk.ToggleButton):
|
||||
button.set_active(False)
|
||||
button = button.get_next_sibling()
|
||||
save_profile(self._profile)
|
||||
|
||||
def _on_close_request(self, *args):
|
||||
save_profile(self._profile)
|
||||
self.app.save_profile(self.app.profile)
|
||||
return False
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user