diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a1efc0..d026bb5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,16 +1,31 @@ # Jackify Changelog +## v0.2.0.7 - Critical Auth Fix +**Release Date:** 2025-12-28 + +### Critical Bug Fixes +- **OAuth Token Loss**: Fixed version comparison bug that was deleting OAuth tokens every time settings were saved (affects users on v0.2.0.4+) +- Fixed internal import paths for improved stability + +--- + ## v0.2.0.6 - Premium Detection and Engine Update **Release Date:** 2025-12-28 +**IMPORTANT:** If you are on v0.2.0.5, automatic updates will not work. You must manually download and install v0.2.0.6. + ### Engine Updates - **jackify-engine 0.4.4**: Latest engine version with improvements ### Critical Bug Fixes +- **Auto-Update System**: Fixed broken update dialog import that prevented automatic updates - **Premium Detection**: Fixed false Premium errors caused by overly-broad detection pattern triggering on jackify-engine 0.4.3's userinfo JSON output - **Custom Data Directory**: Fixed AppImage always creating ~/Jackify on startup, even when user configured a custom jackify_data_dir - **Proton Auto-Selection**: Fixed auto-selection writing invalid "auto" string to config on detection failure +### Quality Improvements +- Added pre-build import validator to prevent broken imports from reaching production + --- ## v0.2.0.5 - Emergency OAuth Fix diff --git a/jackify/__init__.py b/jackify/__init__.py index 20fe8c0..c8e98d5 100644 --- a/jackify/__init__.py +++ b/jackify/__init__.py @@ -5,4 +5,4 @@ This package provides both CLI and GUI interfaces for managing Wabbajack modlists natively on Linux systems. """ -__version__ = "0.2.0.6" +__version__ = "0.2.0.7" diff --git a/jackify/backend/handlers/config_handler.py b/jackify/backend/handlers/config_handler.py index 376642a..f2764f3 100644 --- a/jackify/backend/handlers/config_handler.py +++ b/jackify/backend/handlers/config_handler.py @@ -157,7 +157,8 @@ class ConfigHandler: # Migration: v0.0.x -> v0.2.0 # Encryption changed from cryptography (Fernet) to pycryptodome (AES-GCM) # Old encrypted API keys cannot be decrypted, must be re-entered - if current_version < "0.2.0": + from packaging import version + if version.parse(current_version) < version.parse("0.2.0"): # Clear old encrypted credentials if self.settings.get("nexus_api_key"): logger.warning("Clearing saved API key due to encryption format change") diff --git a/jackify/backend/handlers/shortcut_handler.py b/jackify/backend/handlers/shortcut_handler.py index f3f3819..4ebfe51 100644 --- a/jackify/backend/handlers/shortcut_handler.py +++ b/jackify/backend/handlers/shortcut_handler.py @@ -205,8 +205,8 @@ class ShortcutHandler: time.sleep(1) # Give some time for the install to complete # Now import it - import steam_vdf - + import vdf as steam_vdf + with open(shortcuts_file, 'rb') as f: shortcuts_data = steam_vdf.load(f) diff --git a/jackify/frontends/gui/main.py b/jackify/frontends/gui/main.py index 9bb53d4..8de945b 100644 --- a/jackify/frontends/gui/main.py +++ b/jackify/frontends/gui/main.py @@ -1562,7 +1562,7 @@ class JackifyMainWindow(QMainWindow): # Show update dialog after a short delay to ensure GUI is fully loaded def show_update_dialog(): - from ..dialogs.update_dialog import UpdateDialog + from .dialogs.update_dialog import UpdateDialog dialog = UpdateDialog(update_info, self.update_service, self) dialog.exec() diff --git a/jackify/frontends/gui/screens/install_modlist.py b/jackify/frontends/gui/screens/install_modlist.py index 46eb6a9..1bc858a 100644 --- a/jackify/frontends/gui/screens/install_modlist.py +++ b/jackify/frontends/gui/screens/install_modlist.py @@ -4358,7 +4358,7 @@ class InstallModlistScreen(QWidget): def _show_somnium_post_install_guidance(self): """Show guidance popup for Somnium post-installation steps""" - from ..widgets.message_service import MessageService + from ..services.message_service import MessageService guidance_text = f"""Somnium Post-Installation Required

Due to Somnium's non-standard folder structure, you need to manually update the binary paths in ModOrganizer:

diff --git a/jackify/frontends/gui/screens/install_ttw.py b/jackify/frontends/gui/screens/install_ttw.py index 82da3ef..0a3b12a 100644 --- a/jackify/frontends/gui/screens/install_ttw.py +++ b/jackify/frontends/gui/screens/install_ttw.py @@ -3494,7 +3494,7 @@ class InstallTTWScreen(QWidget): def _show_somnium_post_install_guidance(self): """Show guidance popup for Somnium post-installation steps""" - from ..widgets.message_service import MessageService + from ..services.message_service import MessageService guidance_text = f"""Somnium Post-Installation Required

Due to Somnium's non-standard folder structure, you need to manually update the binary paths in ModOrganizer:

diff --git a/jackify/frontends/gui/screens/modlist_gallery.py b/jackify/frontends/gui/screens/modlist_gallery.py index 57e5533..7901446 100644 --- a/jackify/frontends/gui/screens/modlist_gallery.py +++ b/jackify/frontends/gui/screens/modlist_gallery.py @@ -1509,17 +1509,18 @@ class ModlistGalleryDialog(QDialog): try: # Remove all cards from layout - # CRITICAL FIX: Properly remove widgets to prevent overlapping and orphaned windows - # We need to explicitly remove widgets from the layout before taking items - # to ensure they're fully cleaned up, but we don't setParent(None) because - # widgets are immediately re-added to the grid (Qt will reparent them). - while self.grid_layout.count(): - item = self.grid_layout.takeAt(0) + # CRITICAL FIX: Properly remove all widgets to prevent overlapping + # Iterate backwards to avoid index shifting issues + for i in range(self.grid_layout.count() - 1, -1, -1): + item = self.grid_layout.takeAt(i) widget = item.widget() if item else None if widget: - # Explicitly remove widget from layout to prevent overlapping - self.grid_layout.removeWidget(widget) + # Hide widget during removal to prevent visual artifacts + widget.hide() del item + + # Force layout update to ensure all widgets are removed + self.grid_layout.update() # Calculate number of columns based on available width # Get the scroll area width (accounting for filter panel ~280px + margins) @@ -1558,16 +1559,20 @@ class ModlistGalleryDialog(QDialog): card = self.all_cards.get(modlist.machineURL) if card: - # Ensure widget is not already in the layout (prevent overlapping) - # If it is, remove it first (shouldn't happen after takeAt, but safety check) - if card.parent() == self.grid_widget: - # Widget is already a child of grid_widget, check if it's in layout - for i in range(self.grid_layout.count()): - item = self.grid_layout.itemAt(i) - if item and item.widget() == card: - # Already in layout, remove it first - self.grid_layout.removeWidget(card) - break + # Safety check: ensure widget is not already in the layout + # (shouldn't happen after proper removal above, but defensive programming) + already_in_layout = False + for i in range(self.grid_layout.count()): + item = self.grid_layout.itemAt(i) + if item and item.widget() == card: + # Widget is already in layout - this shouldn't happen, but handle it + already_in_layout = True + self.grid_layout.removeWidget(card) + break + + # Ensure widget is visible and add to grid + if not already_in_layout or card.isHidden(): + card.show() self.grid_layout.addWidget(card, row, col) # Set column stretch - don't stretch card columns, but add a spacer column