Sync from development - prepare for v0.2.0.7

This commit is contained in:
Omni
2025-12-28 22:17:44 +00:00
parent 99fb369d5e
commit 5869a896a8
8 changed files with 46 additions and 25 deletions

View File

@@ -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

View File

@@ -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"

View File

@@ -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")

View File

@@ -205,7 +205,7 @@ 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)

View File

@@ -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()

View File

@@ -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"""<b>Somnium Post-Installation Required</b><br><br>
Due to Somnium's non-standard folder structure, you need to manually update the binary paths in ModOrganizer:<br><br>

View File

@@ -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"""<b>Somnium Post-Installation Required</b><br><br>
Due to Somnium's non-standard folder structure, you need to manually update the binary paths in ModOrganizer:<br><br>

View File

@@ -1509,18 +1509,19 @@ 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)
scroll_area = self.grid_widget.parent()
@@ -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