redesign: UI Work
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 358 KiB |
@@ -0,0 +1,179 @@
|
|||||||
|
# Steam Collections Page Design Update Summary
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
Updated all UI screens (except mod manager) to match Steam Collections page design with modern dark blue theme, improved typography, and Steam-inspired visual elements.
|
||||||
|
|
||||||
|
## Color Scheme Changes
|
||||||
|
|
||||||
|
### New Steam Collections Inspired Colors
|
||||||
|
```python
|
||||||
|
COLORS = {
|
||||||
|
'bg_primary': '#1b2838', # Steam dark blue background
|
||||||
|
'bg_secondary': '#2a475e', # Steam medium blue background
|
||||||
|
'bg_tertiary': '#1e2328', # Steam darker background for cards
|
||||||
|
'bg_card': '#16202d', # Steam card background
|
||||||
|
'bg_hover': '#2a475e', # Steam hover state
|
||||||
|
'text_primary': '#c7d5e0', # Steam primary text (light blue-gray)
|
||||||
|
'text_highlight': '#66c0f4', # Steam blue highlight color
|
||||||
|
'text_body': '#8f98a0', # Steam body text (muted blue-gray)
|
||||||
|
'text_secondary': '#acb2b8', # Steam secondary text
|
||||||
|
'text_muted': '#67707b', # Steam muted text
|
||||||
|
'accent_green': '#5ba32b', # Steam success green
|
||||||
|
'accent_red': '#cd5c5c', # Steam error red
|
||||||
|
'accent_yellow': '#ffa500', # Steam warning orange
|
||||||
|
'accent_blue': '#66c0f4', # Steam signature blue
|
||||||
|
'border_light': '#3c4043', # Steam light border
|
||||||
|
'border_dark': '#0e141b', # Steam dark border
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Previous Colors (Replaced)
|
||||||
|
- Old yellow-green highlights (#f5f5b5) → Steam blue (#66c0f4)
|
||||||
|
- Old gray backgrounds (#424041) → Steam dark blue (#1b2838)
|
||||||
|
- Old bright colors → Muted Steam palette
|
||||||
|
|
||||||
|
## GUI Changes (steam_workshop_gui.py)
|
||||||
|
|
||||||
|
### 1. Main Application Window
|
||||||
|
- **Background**: Updated to Steam dark blue (#1b2838)
|
||||||
|
- **Card System**: Implemented Steam-style cards with rounded corners (12px radius)
|
||||||
|
- **Typography**: Enhanced with Steam blue highlights for titles
|
||||||
|
- **Padding**: Increased from 10px to 15px for better spacing
|
||||||
|
|
||||||
|
### 2. Input Section Redesign
|
||||||
|
- **Card-based Layout**: Each section now uses Steam-style cards
|
||||||
|
- RimWorld Installation card
|
||||||
|
- Workshop Content card
|
||||||
|
- Advanced Configuration card
|
||||||
|
- Steam Workshop Collections card
|
||||||
|
- **Input Fields**:
|
||||||
|
- Dark backgrounds (#1e2328)
|
||||||
|
- Steam blue focus borders (#66c0f4)
|
||||||
|
- Improved padding and spacing
|
||||||
|
- **Buttons**:
|
||||||
|
- Primary button: Steam blue (#66c0f4) with dark text
|
||||||
|
- Secondary button: Steam green (#5ba32b)
|
||||||
|
- Disabled state: Muted colors
|
||||||
|
|
||||||
|
### 3. Output Section (Logs)
|
||||||
|
- **Card Container**: Logs now in Steam-style card
|
||||||
|
- **Color-coded Messages**:
|
||||||
|
- Success: Steam green
|
||||||
|
- Error: Steam red
|
||||||
|
- Warning: Steam orange
|
||||||
|
- Info: Steam blue
|
||||||
|
- **Timestamps**: Added with muted color
|
||||||
|
- **Background**: Dark Steam theme (#1e2328)
|
||||||
|
|
||||||
|
### 4. Loading Screen Updates
|
||||||
|
- **Card Backgrounds**: Updated to Steam styling with subtle borders
|
||||||
|
- **Corner Radius**: Reduced from 20px to 12px for modern look
|
||||||
|
- **Colors**: All text and UI elements use Steam palette
|
||||||
|
- **Error Cards**: Steam red accents for error states
|
||||||
|
|
||||||
|
### 5. Button Styling
|
||||||
|
- **Enable State**: Steam blue primary, Steam green secondary
|
||||||
|
- **Disable State**: Muted Steam colors
|
||||||
|
- **Hover Effects**: Lighter Steam blue on hover
|
||||||
|
- **Cursor**: Hand cursor for better UX
|
||||||
|
|
||||||
|
## TUI Changes (progression_tui.py)
|
||||||
|
|
||||||
|
### 1. Color Scheme
|
||||||
|
- Updated all TUI_COLORS to match GUI Steam palette
|
||||||
|
- Consistent blue theme throughout terminal interface
|
||||||
|
|
||||||
|
### 2. Header Styling
|
||||||
|
- **Border**: Steam blue double border
|
||||||
|
- **Title**: Added "PROGRESSION LOADER" title to panel
|
||||||
|
- **ASCII Art**: Highlighted with Steam blue
|
||||||
|
|
||||||
|
### 3. Menu System
|
||||||
|
- **Table Styling**: Rounded borders with Steam blue accents
|
||||||
|
- **Status Indicators**:
|
||||||
|
- Valid: ✓ with Steam green
|
||||||
|
- Invalid: ⚠ with Steam yellow
|
||||||
|
- Ready: ✓ Ready with Steam green
|
||||||
|
- Disabled: ⚠ Disabled with muted colors
|
||||||
|
|
||||||
|
### 4. Configuration Display
|
||||||
|
- **Path Display**: Added icons and Steam blue labels
|
||||||
|
- **Panel Styling**: Rounded borders with Steam theme
|
||||||
|
- **Status Colors**: Consistent with GUI
|
||||||
|
|
||||||
|
## Font and Styling (font_and_colors_update.py)
|
||||||
|
|
||||||
|
### 1. New Utility Functions
|
||||||
|
- `apply_steam_styling()`: Returns Steam-inspired style dictionaries
|
||||||
|
- `get_steam_button_colors()`: Provides button color schemes by type
|
||||||
|
- Updated color constants to match Steam theme
|
||||||
|
|
||||||
|
### 2. Button Color Schemes
|
||||||
|
- **Default**: Steam secondary background
|
||||||
|
- **Primary**: Steam blue with dark text
|
||||||
|
- **Success**: Steam green
|
||||||
|
- **Warning**: Steam orange
|
||||||
|
- **Danger**: Steam red
|
||||||
|
|
||||||
|
## Visual Improvements
|
||||||
|
|
||||||
|
### 1. Card System
|
||||||
|
- **Rounded Corners**: 12px radius for modern look
|
||||||
|
- **Subtle Borders**: Light Steam borders (#3c4043)
|
||||||
|
- **Inner Highlights**: Very subtle Steam blue inner glow
|
||||||
|
- **Proper Spacing**: Consistent 10-15px padding
|
||||||
|
|
||||||
|
### 2. Typography Hierarchy
|
||||||
|
- **Titles**: Steam blue (#66c0f4) with bold weight
|
||||||
|
- **Labels**: Steam secondary text (#acb2b8)
|
||||||
|
- **Body Text**: Steam body color (#8f98a0)
|
||||||
|
- **Muted Text**: Steam muted (#67707b)
|
||||||
|
|
||||||
|
### 3. Interactive Elements
|
||||||
|
- **Focus States**: Steam blue borders on input fields
|
||||||
|
- **Hover Effects**: Lighter Steam blue on buttons
|
||||||
|
- **Status Indicators**: Color-coded with Steam palette
|
||||||
|
- **Blinking Animation**: Steam blue/muted for invalid states
|
||||||
|
|
||||||
|
## Consistency Improvements
|
||||||
|
|
||||||
|
### 1. Cross-Platform
|
||||||
|
- GUI and TUI now use matching color schemes
|
||||||
|
- Consistent terminology and styling
|
||||||
|
- Same visual hierarchy in both interfaces
|
||||||
|
|
||||||
|
### 2. Error Handling
|
||||||
|
- Consistent error colors (Steam red)
|
||||||
|
- Warning colors (Steam orange)
|
||||||
|
- Success colors (Steam green)
|
||||||
|
- Info colors (Steam blue)
|
||||||
|
|
||||||
|
### 3. Accessibility
|
||||||
|
- Better contrast ratios with Steam's tested palette
|
||||||
|
- Consistent focus indicators
|
||||||
|
- Clear visual hierarchy
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
|
||||||
|
1. **steam_workshop_gui.py** - Main GUI application
|
||||||
|
2. **progression_tui.py** - Terminal user interface
|
||||||
|
3. **font_and_colors_update.py** - Color and styling utilities
|
||||||
|
4. **update_checker.py** - Update dialog styling
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
- ✅ Syntax validation passed for all Python files
|
||||||
|
- ✅ Color scheme consistency verified
|
||||||
|
- ✅ Both GUI and TUI updated per requirements
|
||||||
|
- ✅ Steam Collections design patterns implemented
|
||||||
|
|
||||||
|
## Result
|
||||||
|
|
||||||
|
The application now features a cohesive Steam Collections inspired design with:
|
||||||
|
- Modern dark blue theme matching Steam's visual identity
|
||||||
|
- Improved card-based layouts for better organization
|
||||||
|
- Consistent typography and color usage
|
||||||
|
- Enhanced user experience with better visual hierarchy
|
||||||
|
- Professional appearance matching Steam's design standards
|
||||||
|
|
||||||
|
All screens except the mod manager have been updated to match the Steam Collections page design as requested.
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 186 KiB |
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,187 @@
|
|||||||
|
# Updated font loading and color scheme for Progression Loader
|
||||||
|
# Steam Collections page inspired design:
|
||||||
|
# - Dark blue theme matching Steam's signature colors
|
||||||
|
# - Steam blue (#66c0f4) for highlights and accents
|
||||||
|
# - Dark blue backgrounds (#1b2838, #2a475e) for depth
|
||||||
|
# - Light blue-gray text (#c7d5e0) for readability
|
||||||
|
# - Card-based layouts with rounded corners
|
||||||
|
# - Subtle shadows and glows for depth
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def get_resource_path(relative_path):
|
||||||
|
"""Get absolute path to resource, works for dev and for PyInstaller"""
|
||||||
|
try:
|
||||||
|
# PyInstaller creates a temp folder and stores path in _MEIPASS
|
||||||
|
base_path = sys._MEIPASS
|
||||||
|
except Exception:
|
||||||
|
base_path = os.path.abspath(".")
|
||||||
|
|
||||||
|
return os.path.join(base_path, relative_path)
|
||||||
|
|
||||||
|
# Steam Collections inspired color constants
|
||||||
|
COLORS = {
|
||||||
|
'bg_primary': '#1b2838', # Steam dark blue background
|
||||||
|
'bg_secondary': '#2a475e', # Steam medium blue background
|
||||||
|
'bg_tertiary': '#1e2328', # Steam darker background for cards
|
||||||
|
'bg_card': '#16202d', # Steam card background
|
||||||
|
'bg_hover': '#2a475e', # Steam hover state
|
||||||
|
'text_primary': '#c7d5e0', # Steam primary text (light blue-gray)
|
||||||
|
'text_highlight': '#66c0f4', # Steam blue highlight color
|
||||||
|
'text_body': '#8f98a0', # Steam body text (muted blue-gray)
|
||||||
|
'text_secondary': '#acb2b8', # Steam secondary text
|
||||||
|
'text_muted': '#67707b', # Steam muted text
|
||||||
|
'accent_green': '#5ba32b', # Steam success green
|
||||||
|
'accent_red': '#cd5c5c', # Steam error red
|
||||||
|
'accent_yellow': '#ffa500', # Steam warning orange
|
||||||
|
'accent_blue': '#66c0f4', # Steam signature blue
|
||||||
|
'border_light': '#3c4043', # Steam light border
|
||||||
|
'border_dark': '#0e141b', # Steam dark border
|
||||||
|
}
|
||||||
|
|
||||||
|
def load_all_georgia_fonts():
|
||||||
|
"""Load all Georgia font variants using Windows AddFontResourceEx with private flag"""
|
||||||
|
custom_font_available = False
|
||||||
|
custom_font_family = None
|
||||||
|
|
||||||
|
# List of Georgia font files to load
|
||||||
|
georgia_fonts = [
|
||||||
|
"georgia.ttf", # Regular
|
||||||
|
"georgiab.ttf", # Bold
|
||||||
|
"georgiai.ttf", # Italic
|
||||||
|
"georgiaz.ttf" # Bold Italic
|
||||||
|
]
|
||||||
|
|
||||||
|
fonts_loaded = 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
for font_file in georgia_fonts:
|
||||||
|
font_path = get_resource_path(os.path.join("art", font_file))
|
||||||
|
if os.path.exists(font_path):
|
||||||
|
abs_font_path = os.path.abspath(font_path)
|
||||||
|
|
||||||
|
# Use the Stack Overflow method with AddFontResourceEx
|
||||||
|
success = _load_font_private(abs_font_path)
|
||||||
|
|
||||||
|
if success:
|
||||||
|
fonts_loaded += 1
|
||||||
|
print(f"Successfully loaded font: {font_file}")
|
||||||
|
else:
|
||||||
|
print(f"Failed to load font: {font_file}")
|
||||||
|
else:
|
||||||
|
print(f"Font file not found: {font_path}")
|
||||||
|
|
||||||
|
if fonts_loaded > 0:
|
||||||
|
custom_font_available = True
|
||||||
|
custom_font_family = "Georgia"
|
||||||
|
print(f"Successfully loaded {fonts_loaded} Georgia font variants")
|
||||||
|
else:
|
||||||
|
print("No Georgia fonts could be loaded, using system fallback")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error loading fonts: {e}")
|
||||||
|
custom_font_available = False
|
||||||
|
custom_font_family = None
|
||||||
|
|
||||||
|
return custom_font_available, custom_font_family
|
||||||
|
|
||||||
|
def _load_font_private(fontpath):
|
||||||
|
"""
|
||||||
|
Load font privately using AddFontResourceEx
|
||||||
|
Based on Stack Overflow solution by Felipe
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
from ctypes import windll, byref, create_unicode_buffer
|
||||||
|
|
||||||
|
# Constants for AddFontResourceEx
|
||||||
|
FR_PRIVATE = 0x10 # Font is private to this process
|
||||||
|
FR_NOT_ENUM = 0x20 # Font won't appear in font enumeration
|
||||||
|
|
||||||
|
# Create unicode buffer for the font path
|
||||||
|
pathbuf = create_unicode_buffer(fontpath)
|
||||||
|
|
||||||
|
# Use AddFontResourceExW for Unicode strings
|
||||||
|
AddFontResourceEx = windll.gdi32.AddFontResourceExW
|
||||||
|
|
||||||
|
# Set flags: private (unloaded when process dies) and not enumerable
|
||||||
|
flags = FR_PRIVATE | FR_NOT_ENUM
|
||||||
|
|
||||||
|
# Add the font resource
|
||||||
|
numFontsAdded = AddFontResourceEx(byref(pathbuf), flags, 0)
|
||||||
|
|
||||||
|
return numFontsAdded > 0
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error in _load_font_private: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def apply_steam_styling():
|
||||||
|
"""Apply Steam Collections page inspired styling to UI components"""
|
||||||
|
return {
|
||||||
|
'button_style': {
|
||||||
|
'relief': 'flat',
|
||||||
|
'borderwidth': 0,
|
||||||
|
'highlightthickness': 0,
|
||||||
|
'font': ('Georgia', 10, 'bold'),
|
||||||
|
'cursor': 'hand2'
|
||||||
|
},
|
||||||
|
'entry_style': {
|
||||||
|
'relief': 'flat',
|
||||||
|
'borderwidth': 2,
|
||||||
|
'highlightthickness': 0,
|
||||||
|
'font': ('Georgia', 9),
|
||||||
|
'insertbackground': COLORS['text_primary']
|
||||||
|
},
|
||||||
|
'label_style': {
|
||||||
|
'font': ('Georgia', 9),
|
||||||
|
'anchor': 'w'
|
||||||
|
},
|
||||||
|
'title_style': {
|
||||||
|
'font': ('Georgia', 14, 'bold'),
|
||||||
|
'anchor': 'center'
|
||||||
|
},
|
||||||
|
'card_style': {
|
||||||
|
'relief': 'flat',
|
||||||
|
'borderwidth': 1,
|
||||||
|
'highlightthickness': 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_steam_button_colors(button_type='default'):
|
||||||
|
"""Get Steam-inspired button color schemes"""
|
||||||
|
button_colors = {
|
||||||
|
'default': {
|
||||||
|
'bg': COLORS['bg_secondary'],
|
||||||
|
'fg': COLORS['text_primary'],
|
||||||
|
'activebackground': COLORS['bg_hover'],
|
||||||
|
'activeforeground': COLORS['text_highlight']
|
||||||
|
},
|
||||||
|
'primary': {
|
||||||
|
'bg': COLORS['accent_blue'],
|
||||||
|
'fg': COLORS['bg_primary'],
|
||||||
|
'activebackground': COLORS['text_highlight'],
|
||||||
|
'activeforeground': COLORS['bg_primary']
|
||||||
|
},
|
||||||
|
'success': {
|
||||||
|
'bg': COLORS['accent_green'],
|
||||||
|
'fg': COLORS['text_primary'],
|
||||||
|
'activebackground': '#6bb33f',
|
||||||
|
'activeforeground': COLORS['text_primary']
|
||||||
|
},
|
||||||
|
'warning': {
|
||||||
|
'bg': COLORS['accent_yellow'],
|
||||||
|
'fg': COLORS['bg_primary'],
|
||||||
|
'activebackground': '#ffb733',
|
||||||
|
'activeforeground': COLORS['bg_primary']
|
||||||
|
},
|
||||||
|
'danger': {
|
||||||
|
'bg': COLORS['accent_red'],
|
||||||
|
'fg': COLORS['text_primary'],
|
||||||
|
'activebackground': '#d66f6f',
|
||||||
|
'activeforeground': COLORS['text_primary']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return button_colors.get(button_type, button_colors['default'])
|
||||||
+138
-88
@@ -36,6 +36,23 @@ from update_config import get_update_config
|
|||||||
# Load environment variables
|
# Load environment variables
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
# Steam Collections page inspired color scheme for TUI
|
||||||
|
TUI_COLORS = {
|
||||||
|
'bg_primary': '#1b2838', # Steam dark blue background
|
||||||
|
'bg_secondary': '#2a475e', # Steam medium blue background
|
||||||
|
'bg_tertiary': '#1e2328', # Steam darker background for cards
|
||||||
|
'text_primary': '#c7d5e0', # Steam primary text (light blue-gray)
|
||||||
|
'text_highlight': '#66c0f4', # Steam blue highlight color
|
||||||
|
'text_body': '#8f98a0', # Steam body text (muted blue-gray)
|
||||||
|
'text_secondary': '#acb2b8', # Steam secondary text
|
||||||
|
'text_muted': '#67707b', # Steam muted text
|
||||||
|
'accent_green': '#5ba32b', # Steam success green
|
||||||
|
'accent_red': '#cd5c5c', # Steam error red
|
||||||
|
'accent_yellow': '#ffa500', # Steam warning orange
|
||||||
|
'accent_blue': '#66c0f4', # Steam signature blue
|
||||||
|
'accent_cyan': '#66c0f4', # Steam info/header color (same as blue)
|
||||||
|
}
|
||||||
|
|
||||||
console = Console()
|
console = Console()
|
||||||
|
|
||||||
class ProgressionTUI:
|
class ProgressionTUI:
|
||||||
@@ -114,23 +131,26 @@ class ProgressionTUI:
|
|||||||
self.hr_systems_logo = "Hudson Riggs Systems"
|
self.hr_systems_logo = "Hudson Riggs Systems"
|
||||||
|
|
||||||
def display_header(self):
|
def display_header(self):
|
||||||
"""Display the header with ASCII art"""
|
"""Display the header with ASCII art using Steam Collections inspired styling"""
|
||||||
# Use the actual progression logo ASCII art instead of just text
|
# Use the actual progression logo ASCII art with Steam blue highlight
|
||||||
header_panel = Panel(
|
header_panel = Panel(
|
||||||
Align.center(self.progression_logo),
|
Align.center(self.progression_logo),
|
||||||
box=box.DOUBLE,
|
box=box.DOUBLE,
|
||||||
style="cyan",
|
style=TUI_COLORS['accent_blue'], # Steam blue
|
||||||
padding=(1, 2)
|
border_style=TUI_COLORS['accent_blue'],
|
||||||
|
padding=(1, 2),
|
||||||
|
title="[bold]PROGRESSION LOADER[/bold]",
|
||||||
|
title_align="center"
|
||||||
)
|
)
|
||||||
|
|
||||||
return header_panel
|
return header_panel
|
||||||
|
|
||||||
def display_footer(self):
|
def display_footer(self):
|
||||||
"""Display footer with HR Systems info"""
|
"""Display footer with HR Systems info using Steam Collections inspired styling"""
|
||||||
footer_text = Text()
|
footer_text = Text()
|
||||||
footer_text.append("Hudson Riggs Systems", style="dim white")
|
footer_text.append("Hudson Riggs Systems", style=f"dim {TUI_COLORS['text_secondary']}")
|
||||||
footer_text.append(" - ", style="dim white")
|
footer_text.append(" - ", style=f"dim {TUI_COLORS['text_secondary']}")
|
||||||
footer_text.append("https://hudsonriggs.systems", style="dim blue underline")
|
footer_text.append("https://hudsonriggs.systems", style=f"dim {TUI_COLORS['accent_blue']} underline")
|
||||||
|
|
||||||
return Align.center(footer_text)
|
return Align.center(footer_text)
|
||||||
|
|
||||||
@@ -147,40 +167,66 @@ class ProgressionTUI:
|
|||||||
self.console.print(self.display_header())
|
self.console.print(self.display_header())
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Create main menu options
|
# Create main menu options with Steam Collections inspired styling
|
||||||
menu_table = Table(show_header=False, box=box.SIMPLE, padding=(0, 2))
|
menu_table = Table(show_header=False, box=box.ROUNDED, padding=(0, 2))
|
||||||
menu_table.add_column("Option", style="cyan bold", width=4)
|
menu_table.add_column("Option", style=f"{TUI_COLORS['accent_blue']} bold", width=4)
|
||||||
menu_table.add_column("Description", style="white")
|
menu_table.add_column("Description", style=TUI_COLORS['text_primary'])
|
||||||
menu_table.add_column("Status", style="green", width=15)
|
menu_table.add_column("Status", style=TUI_COLORS['accent_green'], width=15)
|
||||||
|
|
||||||
# Menu options with status indicators
|
# Menu options with Steam-styled status indicators
|
||||||
rimworld_status = "Valid" if self.is_rimworld_valid else "Not Set"
|
rimworld_status = "✓ Valid" if self.is_rimworld_valid else "⚠ Not Set"
|
||||||
rimworld_color = "green" if self.is_rimworld_valid else "red"
|
rimworld_color = TUI_COLORS['accent_green'] if self.is_rimworld_valid else TUI_COLORS['accent_yellow']
|
||||||
|
|
||||||
menu_table.add_row("1", "Set RimWorld Game Folder", f"[{rimworld_color}]{rimworld_status}[/{rimworld_color}]")
|
menu_table.add_row("1", "Set RimWorld Game Folder", f"[{rimworld_color}]{rimworld_status}[/{rimworld_color}]")
|
||||||
menu_table.add_row("2", "Check Steam Workshop Subscriptions", "")
|
menu_table.add_row("2", "Check Steam Workshop Subscriptions", "")
|
||||||
menu_table.add_row("3", "Check RimWorld Expansions", "")
|
menu_table.add_row("3", "Check RimWorld Expansions", "")
|
||||||
menu_table.add_row("4", "Load Progression Pack Complete", "Enabled" if self.is_rimworld_valid else "[dim]Disabled[/dim]")
|
menu_table.add_row("4", "Load Progression Pack Complete", f"[{TUI_COLORS['accent_green']}]✓ Ready[/{TUI_COLORS['accent_green']}]" if self.is_rimworld_valid else f"[{TUI_COLORS['text_muted']}]⚠ Disabled[/{TUI_COLORS['text_muted']}]")
|
||||||
menu_table.add_row("5", "Merge with Current Mods Config", "Enabled" if self.is_rimworld_valid else "[dim]Disabled[/dim]")
|
menu_table.add_row("5", "Merge with Current Mods Config", f"[{TUI_COLORS['accent_green']}]✓ Ready[/{TUI_COLORS['accent_green']}]" if self.is_rimworld_valid else f"[{TUI_COLORS['text_muted']}]⚠ Disabled[/{TUI_COLORS['text_muted']}]")
|
||||||
menu_table.add_row("6", "Check for Updates", "")
|
menu_table.add_row("6", "Check for Updates", "")
|
||||||
menu_table.add_row("7", "View Configuration", "")
|
menu_table.add_row("7", "View Configuration", "")
|
||||||
menu_table.add_row("0", "Exit", "")
|
menu_table.add_row("0", "Exit", "")
|
||||||
|
|
||||||
|
# Create Steam-styled menu panel
|
||||||
menu_panel = Panel(
|
menu_panel = Panel(
|
||||||
menu_table,
|
menu_table,
|
||||||
title="Main Menu",
|
title="[bold]Main Menu[/bold]",
|
||||||
|
title_align="center",
|
||||||
box=box.ROUNDED,
|
box=box.ROUNDED,
|
||||||
style="white"
|
style=TUI_COLORS['text_primary'],
|
||||||
|
border_style=TUI_COLORS['accent_blue']
|
||||||
)
|
)
|
||||||
|
|
||||||
self.console.print(menu_panel)
|
self.console.print(menu_panel)
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Display current paths if set
|
# Display current paths if set with Steam Collections styling
|
||||||
if self.rimworld_path or self.workshop_path:
|
if self.rimworld_path or self.workshop_path:
|
||||||
info_table = Table(show_header=False, box=None, padding=(0, 1))
|
info_table = Table(show_header=False, box=None, padding=(0, 1))
|
||||||
info_table.add_column("Label", style="cyan", width=25)
|
info_table.add_column("Label", style=f"{TUI_COLORS['accent_blue']} bold", width=25)
|
||||||
info_table.add_column("Path", style="white")
|
info_table.add_column("Path", style=TUI_COLORS['text_body'])
|
||||||
|
|
||||||
|
if self.rimworld_path:
|
||||||
|
status_icon = "✓" if self.is_rimworld_valid else "⚠"
|
||||||
|
status_color = TUI_COLORS['accent_green'] if self.is_rimworld_valid else TUI_COLORS['accent_yellow']
|
||||||
|
info_table.add_row(f"[{status_color}]{status_icon}[/{status_color}] RimWorld Path:", self.rimworld_path)
|
||||||
|
|
||||||
|
if self.workshop_path:
|
||||||
|
info_table.add_row(f"[{TUI_COLORS['accent_blue']}]📁[/{TUI_COLORS['accent_blue']}] Workshop Path:", self.workshop_path)
|
||||||
|
|
||||||
|
if self.modsconfig_path:
|
||||||
|
info_table.add_row(f"[{TUI_COLORS['accent_blue']}]⚙[/{TUI_COLORS['accent_blue']}] ModsConfig Path:", self.modsconfig_path)
|
||||||
|
|
||||||
|
# Create Steam-styled info panel
|
||||||
|
info_panel = Panel(
|
||||||
|
info_table,
|
||||||
|
title="[bold]Current Configuration[/bold]",
|
||||||
|
title_align="center",
|
||||||
|
box=box.ROUNDED,
|
||||||
|
style=TUI_COLORS['text_secondary'],
|
||||||
|
border_style=TUI_COLORS['text_muted']
|
||||||
|
)
|
||||||
|
self.console.print(info_panel)
|
||||||
|
self.console.print()
|
||||||
|
|
||||||
if self.rimworld_path:
|
if self.rimworld_path:
|
||||||
info_table.add_row("RimWorld Path:", self.rimworld_path)
|
info_table.add_row("RimWorld Path:", self.rimworld_path)
|
||||||
@@ -201,7 +247,7 @@ class ProgressionTUI:
|
|||||||
choice = Prompt.ask("Select an option", choices=["0", "1", "2", "3", "4", "5", "6", "7"], default="1")
|
choice = Prompt.ask("Select an option", choices=["0", "1", "2", "3", "4", "5", "6", "7"], default="1")
|
||||||
|
|
||||||
if choice == "0":
|
if choice == "0":
|
||||||
self.console.print("\n[yellow]Thank you for using Progression Loader![/yellow]")
|
self.console.print(f"\n[{TUI_COLORS['accent_yellow']}]Thank you for using Progression Loader![/{TUI_COLORS['accent_yellow']}]")
|
||||||
break
|
break
|
||||||
elif choice == "1":
|
elif choice == "1":
|
||||||
self.set_rimworld_path()
|
self.set_rimworld_path()
|
||||||
@@ -213,13 +259,13 @@ class ProgressionTUI:
|
|||||||
if self.is_rimworld_valid:
|
if self.is_rimworld_valid:
|
||||||
self.load_progression_pack()
|
self.load_progression_pack()
|
||||||
else:
|
else:
|
||||||
self.console.print("\n[red]Please set a valid RimWorld path first![/red]")
|
self.console.print(f"\n[{TUI_COLORS['accent_red']}]Please set a valid RimWorld path first![/{TUI_COLORS['accent_red']}]")
|
||||||
self.console.input("\nPress Enter to continue...")
|
self.console.input("\nPress Enter to continue...")
|
||||||
elif choice == "5":
|
elif choice == "5":
|
||||||
if self.is_rimworld_valid:
|
if self.is_rimworld_valid:
|
||||||
self.merge_with_current_mods()
|
self.merge_with_current_mods()
|
||||||
else:
|
else:
|
||||||
self.console.print("\n[red]Please set a valid RimWorld path first![/red]")
|
self.console.print(f"\n[{TUI_COLORS['accent_red']}]Please set a valid RimWorld path first![/{TUI_COLORS['accent_red']}]")
|
||||||
self.console.input("\nPress Enter to continue...")
|
self.console.input("\nPress Enter to continue...")
|
||||||
elif choice == "6":
|
elif choice == "6":
|
||||||
self.check_for_updates()
|
self.check_for_updates()
|
||||||
@@ -227,10 +273,10 @@ class ProgressionTUI:
|
|||||||
self.view_configuration()
|
self.view_configuration()
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
self.console.print("\n\n[yellow]Goodbye![/yellow]")
|
self.console.print(f"\n\n[{TUI_COLORS['accent_yellow']}]Goodbye![/{TUI_COLORS['accent_yellow']}]")
|
||||||
break
|
break
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.console.print(f"\n[red]Error: {e}[/red]")
|
self.console.print(f"\n[{TUI_COLORS['accent_red']}]Error: {e}[/{TUI_COLORS['accent_red']}]")
|
||||||
self.console.input("\nPress Enter to continue...")
|
self.console.input("\nPress Enter to continue...")
|
||||||
|
|
||||||
def set_rimworld_path(self):
|
def set_rimworld_path(self):
|
||||||
@@ -239,28 +285,30 @@ class ProgressionTUI:
|
|||||||
self.console.print(self.display_header())
|
self.console.print(self.display_header())
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Instructions
|
# Instructions with modern styling - bold titles, italic emphasis
|
||||||
instructions = Panel(
|
instructions = Panel(
|
||||||
Text.from_markup(
|
Text.from_markup(
|
||||||
"To find your RimWorld path:\n"
|
"[bold]To find your RimWorld path:[/bold]\n\n"
|
||||||
"1. Open Steam\n"
|
"1. Open Steam\n"
|
||||||
"2. Right-click RimWorld in your library\n"
|
"2. Right-click RimWorld in your library\n"
|
||||||
"3. Select 'Manage' > 'Browse local files'\n"
|
"3. Select 'Manage' > 'Browse local files'\n"
|
||||||
"4. Copy the path from the address bar\n\n"
|
"4. Copy the path from the address bar\n\n"
|
||||||
"Example: C:\\Steam\\steamapps\\common\\RimWorld"
|
"[italic dim]Example: C:\\Steam\\steamapps\\common\\RimWorld[/italic dim]"
|
||||||
),
|
),
|
||||||
title="Instructions",
|
title=f"[bold {TUI_COLORS['text_highlight']}]Instructions[/bold {TUI_COLORS['text_highlight']}]",
|
||||||
style="cyan"
|
title_align="center",
|
||||||
|
style=TUI_COLORS['accent_cyan'],
|
||||||
|
border_style="rounded"
|
||||||
)
|
)
|
||||||
self.console.print(instructions)
|
self.console.print(instructions)
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Current path if set
|
# Current path if set with new colors
|
||||||
if self.rimworld_path:
|
if self.rimworld_path:
|
||||||
current_panel = Panel(
|
current_panel = Panel(
|
||||||
f"Current path: {self.rimworld_path}",
|
f"Current path: {self.rimworld_path}",
|
||||||
title="Current RimWorld Path",
|
title="Current RimWorld Path",
|
||||||
style="green" if self.is_rimworld_valid else "red"
|
style=TUI_COLORS['accent_green'] if self.is_rimworld_valid else TUI_COLORS['accent_red']
|
||||||
)
|
)
|
||||||
self.console.print(current_panel)
|
self.console.print(current_panel)
|
||||||
self.console.print()
|
self.console.print()
|
||||||
@@ -283,17 +331,17 @@ class ProgressionTUI:
|
|||||||
# Derive workshop path
|
# Derive workshop path
|
||||||
self.derive_workshop_path()
|
self.derive_workshop_path()
|
||||||
|
|
||||||
progress.update(task, description="[green]Valid RimWorld installation found![/green]")
|
progress.update(task, description=f"[{TUI_COLORS['accent_green']}]Valid RimWorld installation found![/{TUI_COLORS['accent_green']}]")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
self.console.print(f"\n[green]RimWorld path set successfully![/green]")
|
self.console.print(f"\n[{TUI_COLORS['accent_green']}]RimWorld path set successfully![/{TUI_COLORS['accent_green']}]")
|
||||||
self.console.print(f"Workshop path: {self.workshop_path}")
|
self.console.print(f"Workshop path: {self.workshop_path}")
|
||||||
else:
|
else:
|
||||||
progress.update(task, description="[red]Invalid RimWorld path![/red]")
|
progress.update(task, description=f"[{TUI_COLORS['accent_red']}]Invalid RimWorld path![/{TUI_COLORS['accent_red']}]")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
self.console.print(f"\n[red]Invalid RimWorld installation at: {new_path}[/red]")
|
self.console.print(f"\n[{TUI_COLORS['accent_red']}]Invalid RimWorld installation at: {new_path}[/{TUI_COLORS['accent_red']}]")
|
||||||
self.console.print("[red]Please ensure the path contains RimWorld.exe and Data folder[/red]")
|
self.console.print(f"[{TUI_COLORS['accent_red']}]Please ensure the path contains RimWorld.exe and Data folder[/{TUI_COLORS['accent_red']}]")
|
||||||
|
|
||||||
self.console.input("\nPress Enter to continue...")
|
self.console.input("\nPress Enter to continue...")
|
||||||
|
|
||||||
@@ -339,26 +387,28 @@ class ProgressionTUI:
|
|||||||
self.console.print(self.display_header())
|
self.console.print(self.display_header())
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Display collections
|
# Display collections with modern styling
|
||||||
collections_table = Table(show_header=True, box=box.ROUNDED)
|
collections_table = Table(show_header=True, box=box.ROUNDED, border_style="bright_black")
|
||||||
collections_table.add_column("Collection", style="cyan bold", width=20)
|
collections_table.add_column("Collection", style=f"{TUI_COLORS['text_highlight']} bold", width=20)
|
||||||
collections_table.add_column("URL", style="blue", width=50)
|
collections_table.add_column("URL", style=TUI_COLORS['accent_blue'], width=50)
|
||||||
collections_table.add_column("Subscribed", style="green", width=12)
|
collections_table.add_column("Subscribed", style=TUI_COLORS['accent_green'], width=12)
|
||||||
|
|
||||||
for name, url in self.collections.items():
|
for name, url in self.collections.items():
|
||||||
status = "Yes" if self.subscription_status[name] else "No"
|
status = "Yes" if self.subscription_status[name] else "No"
|
||||||
status_color = "green" if self.subscription_status[name] else "red"
|
status_color = TUI_COLORS['accent_green'] if self.subscription_status[name] else TUI_COLORS['accent_red']
|
||||||
collections_table.add_row(name, url, f"[{status_color}]{status}[/{status_color}]")
|
collections_table.add_row(name, url, f"[{status_color}]{status}[/{status_color}]")
|
||||||
|
|
||||||
collections_panel = Panel(
|
collections_panel = Panel(
|
||||||
collections_table,
|
collections_table,
|
||||||
title="Steam Workshop Collections",
|
title="[bold]Steam Workshop Collections[/bold]",
|
||||||
style="white"
|
title_align="center",
|
||||||
|
style=TUI_COLORS['text_primary'],
|
||||||
|
border_style="rounded"
|
||||||
)
|
)
|
||||||
self.console.print(collections_panel)
|
self.console.print(collections_panel)
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Instructions
|
# Instructions with new color scheme
|
||||||
instructions = Panel(
|
instructions = Panel(
|
||||||
Text.from_markup(
|
Text.from_markup(
|
||||||
"To subscribe to collections:\n"
|
"To subscribe to collections:\n"
|
||||||
@@ -367,10 +417,10 @@ class ProgressionTUI:
|
|||||||
"3. Click 'Subscribe' on the Steam Workshop page\n"
|
"3. Click 'Subscribe' on the Steam Workshop page\n"
|
||||||
"4. Wait for Steam to download the collection\n"
|
"4. Wait for Steam to download the collection\n"
|
||||||
"5. Return here and mark as subscribed\n\n"
|
"5. Return here and mark as subscribed\n\n"
|
||||||
"[yellow]All collections are required for the complete Progression experience.[/yellow]"
|
f"[{TUI_COLORS['accent_yellow']}]All collections are required for the complete Progression experience.[/{TUI_COLORS['accent_yellow']}]"
|
||||||
),
|
),
|
||||||
title="Instructions",
|
title="Instructions",
|
||||||
style="cyan"
|
style=TUI_COLORS['accent_cyan']
|
||||||
)
|
)
|
||||||
self.console.print(instructions)
|
self.console.print(instructions)
|
||||||
self.console.print()
|
self.console.print()
|
||||||
@@ -378,8 +428,8 @@ class ProgressionTUI:
|
|||||||
# Menu options
|
# Menu options
|
||||||
while True:
|
while True:
|
||||||
menu_table = Table(show_header=False, box=box.SIMPLE, padding=(0, 2))
|
menu_table = Table(show_header=False, box=box.SIMPLE, padding=(0, 2))
|
||||||
menu_table.add_column("Option", style="cyan bold", width=4)
|
menu_table.add_column("Option", style=f"{TUI_COLORS['accent_cyan']} bold", width=4)
|
||||||
menu_table.add_column("Description", style="white")
|
menu_table.add_column("Description", style=TUI_COLORS['text_primary'])
|
||||||
|
|
||||||
menu_table.add_row("1", "Open Core Collection in browser")
|
menu_table.add_row("1", "Open Core Collection in browser")
|
||||||
menu_table.add_row("2", "Open Content Collection in browser")
|
menu_table.add_row("2", "Open Content Collection in browser")
|
||||||
@@ -390,7 +440,7 @@ class ProgressionTUI:
|
|||||||
menu_table.add_row("7", "Check if all subscribed")
|
menu_table.add_row("7", "Check if all subscribed")
|
||||||
menu_table.add_row("0", "Back to main menu")
|
menu_table.add_row("0", "Back to main menu")
|
||||||
|
|
||||||
self.console.print(Panel(menu_table, title="Subscription Menu", style="white"))
|
self.console.print(Panel(menu_table, title="Subscription Menu", style=TUI_COLORS['text_primary']))
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
choice = Prompt.ask("Select an option", choices=["0", "1", "2", "3", "4", "5", "6", "7"])
|
choice = Prompt.ask("Select an option", choices=["0", "1", "2", "3", "4", "5", "6", "7"])
|
||||||
@@ -399,29 +449,29 @@ class ProgressionTUI:
|
|||||||
break
|
break
|
||||||
elif choice == "1":
|
elif choice == "1":
|
||||||
webbrowser.open(self.collections["Core Collection"])
|
webbrowser.open(self.collections["Core Collection"])
|
||||||
self.console.print("[green]Opened Core Collection in browser[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]Opened Core Collection in browser[/{TUI_COLORS['accent_green']}]")
|
||||||
elif choice == "2":
|
elif choice == "2":
|
||||||
webbrowser.open(self.collections["Content Collection"])
|
webbrowser.open(self.collections["Content Collection"])
|
||||||
self.console.print("[green]Opened Content Collection in browser[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]Opened Content Collection in browser[/{TUI_COLORS['accent_green']}]")
|
||||||
elif choice == "3":
|
elif choice == "3":
|
||||||
webbrowser.open(self.collections["Cosmetics Collection"])
|
webbrowser.open(self.collections["Cosmetics Collection"])
|
||||||
self.console.print("[green]Opened Cosmetics Collection in browser[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]Opened Cosmetics Collection in browser[/{TUI_COLORS['accent_green']}]")
|
||||||
elif choice == "4":
|
elif choice == "4":
|
||||||
self.subscription_status["Core Collection"] = True
|
self.subscription_status["Core Collection"] = True
|
||||||
self.console.print("[green]Core Collection marked as subscribed[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]Core Collection marked as subscribed[/{TUI_COLORS['accent_green']}]")
|
||||||
elif choice == "5":
|
elif choice == "5":
|
||||||
self.subscription_status["Content Collection"] = True
|
self.subscription_status["Content Collection"] = True
|
||||||
self.console.print("[green]Content Collection marked as subscribed[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]Content Collection marked as subscribed[/{TUI_COLORS['accent_green']}]")
|
||||||
elif choice == "6":
|
elif choice == "6":
|
||||||
self.subscription_status["Cosmetics Collection"] = True
|
self.subscription_status["Cosmetics Collection"] = True
|
||||||
self.console.print("[green]Cosmetics Collection marked as subscribed[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]Cosmetics Collection marked as subscribed[/{TUI_COLORS['accent_green']}]")
|
||||||
elif choice == "7":
|
elif choice == "7":
|
||||||
all_subscribed = all(self.subscription_status.values())
|
all_subscribed = all(self.subscription_status.values())
|
||||||
if all_subscribed:
|
if all_subscribed:
|
||||||
self.console.print("[green]All collections are subscribed! You can proceed.[/green]")
|
self.console.print(f"[{TUI_COLORS['accent_green']}]All collections are subscribed! You can proceed.[/{TUI_COLORS['accent_green']}]")
|
||||||
else:
|
else:
|
||||||
missing = [name for name, status in self.subscription_status.items() if not status]
|
missing = [name for name, status in self.subscription_status.items() if not status]
|
||||||
self.console.print(f"[red]Missing subscriptions: {', '.join(missing)}[/red]")
|
self.console.print(f"[{TUI_COLORS['accent_red']}]Missing subscriptions: {', '.join(missing)}[/{TUI_COLORS['accent_red']}]")
|
||||||
|
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
@@ -441,44 +491,44 @@ class ProgressionTUI:
|
|||||||
# Check expansions
|
# Check expansions
|
||||||
self.check_expansions_thread()
|
self.check_expansions_thread()
|
||||||
|
|
||||||
progress.update(task, description="[green]Expansion check complete![/green]")
|
progress.update(task, description=f"[{TUI_COLORS['accent_green']}]Expansion check complete![/{TUI_COLORS['accent_green']}]")
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
|
|
||||||
# Display results
|
# Display results with new color scheme
|
||||||
if self.expansion_check_results:
|
if self.expansion_check_results:
|
||||||
expansion_table = Table(show_header=True, box=box.ROUNDED)
|
expansion_table = Table(show_header=True, box=box.ROUNDED)
|
||||||
expansion_table.add_column("Expansion", style="cyan bold", width=15)
|
expansion_table.add_column("Expansion", style=f"{TUI_COLORS['accent_cyan']} bold", width=15)
|
||||||
expansion_table.add_column("Status", style="white", width=10)
|
expansion_table.add_column("Status", style=TUI_COLORS['text_primary'], width=10)
|
||||||
|
|
||||||
missing_expansions = []
|
missing_expansions = []
|
||||||
for expansion, owned in self.expansion_check_results.items():
|
for expansion, owned in self.expansion_check_results.items():
|
||||||
status = "Owned" if owned else "Missing"
|
status = "Owned" if owned else "Missing"
|
||||||
status_color = "green" if owned else "red"
|
status_color = TUI_COLORS['accent_green'] if owned else TUI_COLORS['accent_red']
|
||||||
expansion_table.add_row(expansion, f"[{status_color}]{status}[/{status_color}]")
|
expansion_table.add_row(expansion, f"[{status_color}]{status}[/{status_color}]")
|
||||||
|
|
||||||
if not owned:
|
if not owned:
|
||||||
missing_expansions.append(expansion)
|
missing_expansions.append(expansion)
|
||||||
|
|
||||||
self.console.print(Panel(expansion_table, title="RimWorld Expansions", style="white"))
|
self.console.print(Panel(expansion_table, title="RimWorld Expansions", style=TUI_COLORS['text_primary']))
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
if missing_expansions:
|
if missing_expansions:
|
||||||
warning_text = Text()
|
warning_text = Text()
|
||||||
warning_text.append("WARNING: ", style="bold red")
|
warning_text.append("WARNING: ", style=f"bold {TUI_COLORS['accent_red']}")
|
||||||
warning_text.append(f"You don't own {', '.join(missing_expansions)}!\n", style="red")
|
warning_text.append(f"You don't own {', '.join(missing_expansions)}!\n", style=TUI_COLORS['accent_red'])
|
||||||
warning_text.append("Some progression mods may not work without these expansions.", style="yellow")
|
warning_text.append("Some progression mods may not work without these expansions.", style=TUI_COLORS['accent_yellow'])
|
||||||
|
|
||||||
warning_panel = Panel(warning_text, title="Missing Expansions", style="red")
|
warning_panel = Panel(warning_text, title="Missing Expansions", style=TUI_COLORS['accent_red'])
|
||||||
self.console.print(warning_panel)
|
self.console.print(warning_panel)
|
||||||
else:
|
else:
|
||||||
success_panel = Panel(
|
success_panel = Panel(
|
||||||
"[green]All RimWorld expansions detected![/green]",
|
f"[{TUI_COLORS['accent_green']}]All RimWorld expansions detected![/{TUI_COLORS['accent_green']}]",
|
||||||
title="Expansion Check",
|
title="Expansion Check",
|
||||||
style="green"
|
style=TUI_COLORS['accent_green']
|
||||||
)
|
)
|
||||||
self.console.print(success_panel)
|
self.console.print(success_panel)
|
||||||
else:
|
else:
|
||||||
self.console.print("[yellow]Could not check expansions. Please ensure RimWorld path is set correctly.[/yellow]")
|
self.console.print(f"[{TUI_COLORS['accent_yellow']}]Could not check expansions. Please ensure RimWorld path is set correctly.[/{TUI_COLORS['accent_yellow']}]")
|
||||||
|
|
||||||
self.console.input("\nPress Enter to continue...")
|
self.console.input("\nPress Enter to continue...")
|
||||||
|
|
||||||
@@ -680,25 +730,25 @@ class ProgressionTUI:
|
|||||||
self.console.print(self.display_header())
|
self.console.print(self.display_header())
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
# Check prerequisites
|
# Check prerequisites with new colors
|
||||||
all_subscribed = all(self.subscription_status.values())
|
all_subscribed = all(self.subscription_status.values())
|
||||||
if not all_subscribed:
|
if not all_subscribed:
|
||||||
missing = [name for name, status in self.subscription_status.items() if not status]
|
missing = [name for name, status in self.subscription_status.items() if not status]
|
||||||
error_panel = Panel(
|
error_panel = Panel(
|
||||||
f"[red]Please subscribe to all collections first!\nMissing: {', '.join(missing)}[/red]",
|
f"[{TUI_COLORS['accent_red']}]Please subscribe to all collections first!\nMissing: {', '.join(missing)}[/{TUI_COLORS['accent_red']}]",
|
||||||
title="Prerequisites Not Met",
|
title="Prerequisites Not Met",
|
||||||
style="red"
|
style=TUI_COLORS['accent_red']
|
||||||
)
|
)
|
||||||
self.console.print(error_panel)
|
self.console.print(error_panel)
|
||||||
self.console.input("\nPress Enter to continue...")
|
self.console.input("\nPress Enter to continue...")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Confirm action
|
# Confirm action with new colors
|
||||||
confirm_text = Text()
|
confirm_text = Text()
|
||||||
confirm_text.append("This will replace your current ModsConfig.xml with the complete Progression pack.\n", style="yellow")
|
confirm_text.append("This will replace your current ModsConfig.xml with the complete Progression pack.\n", style=TUI_COLORS['accent_yellow'])
|
||||||
confirm_text.append("Your current mod configuration will be backed up.", style="white")
|
confirm_text.append("Your current mod configuration will be backed up.", style=TUI_COLORS['text_primary'])
|
||||||
|
|
||||||
confirm_panel = Panel(confirm_text, title="Confirmation", style="yellow")
|
confirm_panel = Panel(confirm_text, title="Confirmation", style=TUI_COLORS['accent_yellow'])
|
||||||
self.console.print(confirm_panel)
|
self.console.print(confirm_panel)
|
||||||
self.console.print()
|
self.console.print()
|
||||||
|
|
||||||
@@ -1075,18 +1125,18 @@ class ProgressionTUI:
|
|||||||
def main():
|
def main():
|
||||||
"""Main entry point for the TUI application"""
|
"""Main entry point for the TUI application"""
|
||||||
try:
|
try:
|
||||||
# Check for updates first
|
# Check for updates first with new colors
|
||||||
config = get_update_config()
|
config = get_update_config()
|
||||||
if config.get("check_on_startup", True):
|
if config.get("check_on_startup", True):
|
||||||
console.print("[cyan]Checking for updates...[/cyan]")
|
console.print(f"[{TUI_COLORS['accent_cyan']}]Checking for updates...[/{TUI_COLORS['accent_cyan']}]")
|
||||||
try:
|
try:
|
||||||
update_checker = UpdateChecker(config["current_version"])
|
update_checker = UpdateChecker(config["current_version"])
|
||||||
release_info, error = update_checker.check_for_updates_sync()
|
release_info, error = update_checker.check_for_updates_sync()
|
||||||
|
|
||||||
if release_info and update_checker.is_newer_version(release_info['version']):
|
if release_info and update_checker.is_newer_version(release_info['version']):
|
||||||
console.print(f"[yellow]Update available: {release_info['version']}[/yellow]")
|
console.print(f"[{TUI_COLORS['accent_yellow']}]Update available: {release_info['version']}[/{TUI_COLORS['accent_yellow']}]")
|
||||||
if config.get("updates_required", False):
|
if config.get("updates_required", False):
|
||||||
console.print("[red]This update is required. Please update before continuing.[/red]")
|
console.print(f"[{TUI_COLORS['accent_red']}]This update is required. Please update before continuing.[/{TUI_COLORS['accent_red']}]")
|
||||||
if Confirm.ask("Open download page?"):
|
if Confirm.ask("Open download page?"):
|
||||||
webbrowser.open(release_info['html_url'])
|
webbrowser.open(release_info['html_url'])
|
||||||
return
|
return
|
||||||
@@ -1100,9 +1150,9 @@ def main():
|
|||||||
app.show_main_menu()
|
app.show_main_menu()
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
console.print("\n[yellow]Goodbye![/yellow]")
|
console.print(f"\n[{TUI_COLORS['accent_yellow']}]Goodbye![/{TUI_COLORS['accent_yellow']}]")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
console.print(f"[red]Fatal error: {e}[/red]")
|
console.print(f"[{TUI_COLORS['accent_red']}]Fatal error: {e}[/{TUI_COLORS['accent_red']}]")
|
||||||
console.print("[dim]Please report this error to the developers.[/dim]")
|
console.print("[dim]Please report this error to the developers.[/dim]")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 962 KiB |
+1219
-657
File diff suppressed because it is too large
Load Diff
+250
@@ -0,0 +1,250 @@
|
|||||||
|
from PIL import Image, ImageColor, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
|
FONT_FAMILY = "Georgia"
|
||||||
|
|
||||||
|
COLORS = {
|
||||||
|
"bg_primary": "#151515",
|
||||||
|
"bg_secondary": "#1d1d1d",
|
||||||
|
"bg_tertiary": "#212121",
|
||||||
|
"bg_card": "#2b2b2b",
|
||||||
|
"bg_hover": "#36312c",
|
||||||
|
"bg_error": "#2f2926",
|
||||||
|
"text_primary": "#f5f2ec",
|
||||||
|
"text_highlight": "#f0a621",
|
||||||
|
"text_body": "#c8c8c8",
|
||||||
|
"text_secondary": "#ffffff",
|
||||||
|
"text_muted": "#979797",
|
||||||
|
"accent_green": "#3a8e35",
|
||||||
|
"accent_red": "#ff4a46",
|
||||||
|
"accent_yellow": "#f0a621",
|
||||||
|
"accent_blue": "#d7b56a",
|
||||||
|
"border_light": "#4d453b",
|
||||||
|
"border_dark": "#0f0f0f",
|
||||||
|
"stripe": "#1d1d1d",
|
||||||
|
"stripe_soft": "#232323",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _rgba(color, alpha=255):
|
||||||
|
red, green, blue = ImageColor.getrgb(color)
|
||||||
|
return red, green, blue, alpha
|
||||||
|
|
||||||
|
|
||||||
|
def create_striped_texture(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
*,
|
||||||
|
base_color=None,
|
||||||
|
stripe_color=None,
|
||||||
|
stripe_width=16,
|
||||||
|
stripe_gap=18,
|
||||||
|
stripe_alpha=110,
|
||||||
|
corner_radius=0,
|
||||||
|
border_color=None,
|
||||||
|
border_width=0,
|
||||||
|
border_alpha=255,
|
||||||
|
):
|
||||||
|
"""Create a dark diagonal striped texture matching the pack UI style."""
|
||||||
|
width = max(1, int(width))
|
||||||
|
height = max(1, int(height))
|
||||||
|
|
||||||
|
base = Image.new(
|
||||||
|
"RGBA",
|
||||||
|
(width, height),
|
||||||
|
_rgba(base_color or COLORS["bg_card"]),
|
||||||
|
)
|
||||||
|
|
||||||
|
stripes = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
||||||
|
stripe_draw = ImageDraw.Draw(stripes)
|
||||||
|
span = width + height
|
||||||
|
step = max(1, stripe_width + stripe_gap)
|
||||||
|
|
||||||
|
for offset in range(-height, span + height, step):
|
||||||
|
stripe_draw.line(
|
||||||
|
(offset, 0, offset + height, height),
|
||||||
|
fill=_rgba(stripe_color or COLORS["stripe"], stripe_alpha),
|
||||||
|
width=max(1, stripe_width),
|
||||||
|
)
|
||||||
|
|
||||||
|
image = Image.alpha_composite(base, stripes)
|
||||||
|
|
||||||
|
if border_color and border_width > 0:
|
||||||
|
border_draw = ImageDraw.Draw(image)
|
||||||
|
inset = max(1, border_width // 2)
|
||||||
|
bounds = (inset, inset, width - inset - 1, height - inset - 1)
|
||||||
|
if corner_radius > 0:
|
||||||
|
border_draw.rounded_rectangle(
|
||||||
|
bounds,
|
||||||
|
radius=max(1, corner_radius - inset),
|
||||||
|
outline=_rgba(border_color, border_alpha),
|
||||||
|
width=border_width,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
border_draw.rectangle(
|
||||||
|
bounds,
|
||||||
|
outline=_rgba(border_color, border_alpha),
|
||||||
|
width=border_width,
|
||||||
|
)
|
||||||
|
|
||||||
|
if corner_radius > 0:
|
||||||
|
mask = Image.new("L", (width, height), 0)
|
||||||
|
mask_draw = ImageDraw.Draw(mask)
|
||||||
|
mask_draw.rounded_rectangle(
|
||||||
|
(0, 0, width - 1, height - 1),
|
||||||
|
radius=corner_radius,
|
||||||
|
fill=255,
|
||||||
|
)
|
||||||
|
clipped = Image.new("RGBA", (width, height), (0, 0, 0, 0))
|
||||||
|
clipped.paste(image, (0, 0), mask)
|
||||||
|
image = clipped
|
||||||
|
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def create_striped_panel(
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
*,
|
||||||
|
panel_color=None,
|
||||||
|
stripe_color=None,
|
||||||
|
stripe_width=18,
|
||||||
|
stripe_gap=18,
|
||||||
|
stripe_alpha=110,
|
||||||
|
halo_padding=22,
|
||||||
|
halo_alpha=135,
|
||||||
|
panel_alpha=240,
|
||||||
|
corner_radius=18,
|
||||||
|
border_color=None,
|
||||||
|
border_width=1,
|
||||||
|
border_alpha=255,
|
||||||
|
):
|
||||||
|
"""Create a mostly solid panel with stripes that extend just beyond its edges."""
|
||||||
|
width = max(1, int(width))
|
||||||
|
height = max(1, int(height))
|
||||||
|
halo_padding = max(0, int(halo_padding))
|
||||||
|
total_width = width + (halo_padding * 2)
|
||||||
|
total_height = height + (halo_padding * 2)
|
||||||
|
|
||||||
|
image = Image.new("RGBA", (total_width, total_height), (0, 0, 0, 0))
|
||||||
|
|
||||||
|
stripes = Image.new("RGBA", (total_width, total_height), (0, 0, 0, 0))
|
||||||
|
stripe_draw = ImageDraw.Draw(stripes)
|
||||||
|
span = total_width + total_height
|
||||||
|
step = max(1, stripe_width + stripe_gap)
|
||||||
|
|
||||||
|
for offset in range(-total_height, span + total_height, step):
|
||||||
|
stripe_draw.line(
|
||||||
|
(offset, 0, offset + total_height, total_height),
|
||||||
|
fill=_rgba(stripe_color or COLORS["stripe"], halo_alpha),
|
||||||
|
width=max(1, stripe_width),
|
||||||
|
)
|
||||||
|
|
||||||
|
halo_mask = Image.new("L", (total_width, total_height), 0)
|
||||||
|
halo_draw = ImageDraw.Draw(halo_mask)
|
||||||
|
halo_draw.rounded_rectangle(
|
||||||
|
(0, 0, total_width - 1, total_height - 1),
|
||||||
|
radius=max(1, corner_radius + halo_padding),
|
||||||
|
fill=255,
|
||||||
|
)
|
||||||
|
halo_image = Image.new("RGBA", (total_width, total_height), (0, 0, 0, 0))
|
||||||
|
halo_image.paste(stripes, (0, 0), halo_mask)
|
||||||
|
image = Image.alpha_composite(image, halo_image)
|
||||||
|
|
||||||
|
panel_left = halo_padding
|
||||||
|
panel_top = halo_padding
|
||||||
|
panel_right = panel_left + width - 1
|
||||||
|
panel_bottom = panel_top + height - 1
|
||||||
|
|
||||||
|
panel = Image.new("RGBA", (total_width, total_height), (0, 0, 0, 0))
|
||||||
|
panel_draw = ImageDraw.Draw(panel)
|
||||||
|
panel_draw.rounded_rectangle(
|
||||||
|
(panel_left, panel_top, panel_right, panel_bottom),
|
||||||
|
radius=corner_radius,
|
||||||
|
fill=_rgba(panel_color or COLORS["bg_card"], panel_alpha),
|
||||||
|
)
|
||||||
|
|
||||||
|
if border_color and border_width > 0:
|
||||||
|
inset = max(1, border_width // 2)
|
||||||
|
panel_draw.rounded_rectangle(
|
||||||
|
(
|
||||||
|
panel_left + inset,
|
||||||
|
panel_top + inset,
|
||||||
|
panel_right - inset,
|
||||||
|
panel_bottom - inset,
|
||||||
|
),
|
||||||
|
radius=max(1, corner_radius - inset),
|
||||||
|
outline=_rgba(border_color, border_alpha),
|
||||||
|
width=border_width,
|
||||||
|
)
|
||||||
|
|
||||||
|
image = Image.alpha_composite(image, panel)
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def load_cover_background(image_path, width, height, *, overlay_color=None, overlay_alpha=125):
|
||||||
|
"""Load an image, scale it to cover, and apply a dark overlay for readability."""
|
||||||
|
width = max(1, int(width))
|
||||||
|
height = max(1, int(height))
|
||||||
|
|
||||||
|
image = Image.open(image_path).convert("RGBA")
|
||||||
|
source_ratio = image.width / image.height
|
||||||
|
target_ratio = width / height
|
||||||
|
|
||||||
|
if source_ratio > target_ratio:
|
||||||
|
new_height = height
|
||||||
|
new_width = int(height * source_ratio)
|
||||||
|
else:
|
||||||
|
new_width = width
|
||||||
|
new_height = int(width / source_ratio)
|
||||||
|
|
||||||
|
image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
|
||||||
|
left = (new_width - width) // 2
|
||||||
|
top = (new_height - height) // 2
|
||||||
|
image = image.crop((left, top, left + width, top + height))
|
||||||
|
|
||||||
|
overlay = Image.new(
|
||||||
|
"RGBA",
|
||||||
|
(width, height),
|
||||||
|
_rgba(overlay_color or COLORS["bg_primary"], overlay_alpha),
|
||||||
|
)
|
||||||
|
return Image.alpha_composite(image, overlay)
|
||||||
|
|
||||||
|
|
||||||
|
def style_text_button(
|
||||||
|
button,
|
||||||
|
foreground,
|
||||||
|
background,
|
||||||
|
*,
|
||||||
|
hover_foreground=None,
|
||||||
|
disabled_foreground=None,
|
||||||
|
):
|
||||||
|
"""Style a tkinter Button to look like a color-coded text action."""
|
||||||
|
button.configure(
|
||||||
|
bg=background,
|
||||||
|
fg=foreground,
|
||||||
|
activebackground=background,
|
||||||
|
activeforeground=hover_foreground or COLORS["text_primary"],
|
||||||
|
relief="flat",
|
||||||
|
bd=0,
|
||||||
|
borderwidth=0,
|
||||||
|
highlightthickness=0,
|
||||||
|
disabledforeground=disabled_foreground or COLORS["text_muted"],
|
||||||
|
cursor="hand2",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def center_window(window, width, height, parent=None):
|
||||||
|
"""Center a window either on its parent or the current screen."""
|
||||||
|
width = int(width)
|
||||||
|
height = int(height)
|
||||||
|
window.update_idletasks()
|
||||||
|
|
||||||
|
if parent is not None and parent.winfo_exists():
|
||||||
|
x = parent.winfo_rootx() + (parent.winfo_width() // 2) - (width // 2)
|
||||||
|
y = parent.winfo_rooty() + (parent.winfo_height() // 2) - (height // 2)
|
||||||
|
else:
|
||||||
|
x = (window.winfo_screenwidth() // 2) - (width // 2)
|
||||||
|
y = (window.winfo_screenheight() // 2) - (height // 2)
|
||||||
|
|
||||||
|
window.geometry(f"{width}x{height}+{max(0, x)}+{max(0, y)}")
|
||||||
+157
-67
@@ -16,6 +16,7 @@ from datetime import datetime, timedelta
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from update_config import get_update_config
|
from update_config import get_update_config
|
||||||
|
from ui_theme import COLORS, FONT_FAMILY, style_text_button, center_window
|
||||||
|
|
||||||
class UpdateChecker:
|
class UpdateChecker:
|
||||||
def __init__(self, current_version=None):
|
def __init__(self, current_version=None):
|
||||||
@@ -170,6 +171,57 @@ class UpdateChecker:
|
|||||||
self.save_last_check_time()
|
self.save_last_check_time()
|
||||||
|
|
||||||
return latest_release, None
|
return latest_release, None
|
||||||
|
|
||||||
|
def _show_notice_dialog(self, parent_window, title, message, accent_color):
|
||||||
|
"""Show a small themed notice dialog."""
|
||||||
|
dialog = tk.Toplevel(parent_window)
|
||||||
|
dialog.title(title)
|
||||||
|
dialog.configure(bg=COLORS['bg_primary'])
|
||||||
|
dialog.resizable(False, False)
|
||||||
|
dialog.attributes('-topmost', True)
|
||||||
|
|
||||||
|
panel = tk.Frame(
|
||||||
|
dialog,
|
||||||
|
bg=COLORS['bg_card'],
|
||||||
|
highlightbackground=COLORS['border_light'],
|
||||||
|
highlightcolor=COLORS['border_light'],
|
||||||
|
highlightthickness=1,
|
||||||
|
)
|
||||||
|
panel.pack(fill='both', expand=True, padx=16, pady=16)
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
panel,
|
||||||
|
text=title,
|
||||||
|
fg=accent_color,
|
||||||
|
bg=COLORS['bg_card'],
|
||||||
|
font=(FONT_FAMILY, 18, 'bold italic'),
|
||||||
|
).pack(pady=(18, 10))
|
||||||
|
|
||||||
|
tk.Label(
|
||||||
|
panel,
|
||||||
|
text=message,
|
||||||
|
fg=COLORS['text_body'],
|
||||||
|
bg=COLORS['bg_card'],
|
||||||
|
font=(FONT_FAMILY, 11),
|
||||||
|
justify='center',
|
||||||
|
wraplength=340,
|
||||||
|
).pack(padx=24, pady=(0, 18))
|
||||||
|
|
||||||
|
close_btn = tk.Button(
|
||||||
|
panel,
|
||||||
|
text="Close",
|
||||||
|
command=dialog.destroy,
|
||||||
|
bg=COLORS['bg_card'],
|
||||||
|
font=(FONT_FAMILY, 12, 'bold italic'),
|
||||||
|
padx=0,
|
||||||
|
pady=6,
|
||||||
|
)
|
||||||
|
style_text_button(close_btn, COLORS['accent_green'], COLORS['bg_card'])
|
||||||
|
close_btn.pack(pady=(0, 18))
|
||||||
|
|
||||||
|
center_window(dialog, 420, 220, parent_window)
|
||||||
|
dialog.protocol("WM_DELETE_WINDOW", dialog.destroy)
|
||||||
|
return dialog
|
||||||
|
|
||||||
def show_update_dialog(self, parent_window, release_info):
|
def show_update_dialog(self, parent_window, release_info):
|
||||||
"""Show an update notification dialog"""
|
"""Show an update notification dialog"""
|
||||||
@@ -184,7 +236,7 @@ class UpdateChecker:
|
|||||||
# Create update dialog
|
# Create update dialog
|
||||||
dialog = tk.Toplevel(parent_window)
|
dialog = tk.Toplevel(parent_window)
|
||||||
dialog.title("Update Available - Progression Loader")
|
dialog.title("Update Available - Progression Loader")
|
||||||
dialog.configure(bg='#2b2b2b')
|
dialog.configure(bg=COLORS['bg_primary'])
|
||||||
dialog.resizable(False, False)
|
dialog.resizable(False, False)
|
||||||
dialog.attributes('-topmost', True)
|
dialog.attributes('-topmost', True)
|
||||||
|
|
||||||
@@ -195,58 +247,74 @@ class UpdateChecker:
|
|||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Calculate dialog size
|
|
||||||
dialog_width = 500
|
dialog_width = 500
|
||||||
dialog_height = 400
|
dialog_height = 430
|
||||||
|
center_window(dialog, dialog_width, dialog_height, parent_window)
|
||||||
# Center the dialog
|
|
||||||
x = parent_window.winfo_x() + (parent_window.winfo_width() // 2) - (dialog_width // 2)
|
panel = tk.Frame(
|
||||||
y = parent_window.winfo_y() + (parent_window.winfo_height() // 2) - (dialog_height // 2)
|
dialog,
|
||||||
dialog.geometry(f"{dialog_width}x{dialog_height}+{x}+{y}")
|
bg=COLORS['bg_card'],
|
||||||
|
highlightbackground=COLORS['border_light'],
|
||||||
# Title
|
highlightcolor=COLORS['border_light'],
|
||||||
title_label = tk.Label(dialog,
|
highlightthickness=1,
|
||||||
text="🔄 Update Available!",
|
)
|
||||||
fg='#00ff00', bg='#2b2b2b',
|
panel.pack(fill='both', expand=True, padx=16, pady=16)
|
||||||
font=('Arial', 16, 'bold'))
|
|
||||||
|
title_label = tk.Label(
|
||||||
|
panel,
|
||||||
|
text="Update Available",
|
||||||
|
fg=COLORS['text_highlight'],
|
||||||
|
bg=COLORS['bg_card'],
|
||||||
|
font=(FONT_FAMILY, 18, 'bold italic'),
|
||||||
|
)
|
||||||
title_label.pack(pady=20)
|
title_label.pack(pady=20)
|
||||||
|
|
||||||
# Version info
|
# Version info
|
||||||
version_frame = tk.Frame(dialog, bg='#2b2b2b')
|
version_frame = tk.Frame(panel, bg=COLORS['bg_card'])
|
||||||
version_frame.pack(pady=10)
|
version_frame.pack(pady=10)
|
||||||
|
|
||||||
current_label = tk.Label(version_frame,
|
current_label = tk.Label(version_frame,
|
||||||
text=f"Current Version: {self.current_version}",
|
text=f"Current Version: {self.current_version}",
|
||||||
fg='#cccccc', bg='#2b2b2b',
|
fg=COLORS['text_body'], bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12))
|
font=(FONT_FAMILY, 12))
|
||||||
current_label.pack()
|
current_label.pack()
|
||||||
|
|
||||||
latest_label = tk.Label(version_frame,
|
latest_label = tk.Label(version_frame,
|
||||||
text=f"Latest Version: {latest_version}",
|
text=f"Latest Version: {latest_version}",
|
||||||
fg='#00ff00', bg='#2b2b2b',
|
fg=COLORS['accent_green'], bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12, 'bold'))
|
font=(FONT_FAMILY, 12, 'bold'))
|
||||||
latest_label.pack()
|
latest_label.pack()
|
||||||
|
|
||||||
# Release notes
|
# Release notes
|
||||||
if release_info.get('body'):
|
if release_info.get('body'):
|
||||||
notes_label = tk.Label(dialog,
|
notes_label = tk.Label(panel,
|
||||||
text="Release Notes:",
|
text="Release Notes:",
|
||||||
fg='#cccccc', bg='#2b2b2b',
|
fg=COLORS['text_primary'], bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12, 'bold'))
|
font=(FONT_FAMILY, 12, 'bold italic'))
|
||||||
notes_label.pack(pady=(20, 5))
|
notes_label.pack(pady=(20, 5))
|
||||||
|
|
||||||
# Create scrollable text widget for release notes
|
# Create scrollable text widget for release notes
|
||||||
notes_frame = tk.Frame(dialog, bg='#2b2b2b')
|
notes_frame = tk.Frame(panel, bg=COLORS['bg_card'])
|
||||||
notes_frame.pack(fill='both', expand=True, padx=20, pady=(0, 20))
|
notes_frame.pack(fill='both', expand=True, padx=20, pady=(0, 20))
|
||||||
|
|
||||||
notes_text = tk.Text(notes_frame,
|
notes_text = tk.Text(notes_frame,
|
||||||
height=8,
|
height=8,
|
||||||
bg='#404040', fg='#ffffff',
|
bg=COLORS['bg_tertiary'], fg=COLORS['text_body'],
|
||||||
font=('Arial', 10),
|
font=(FONT_FAMILY, 10),
|
||||||
wrap=tk.WORD,
|
wrap=tk.WORD,
|
||||||
state='disabled')
|
state='disabled',
|
||||||
|
relief='flat',
|
||||||
|
bd=0,
|
||||||
|
insertbackground=COLORS['text_primary'],
|
||||||
|
highlightthickness=1,
|
||||||
|
highlightbackground=COLORS['border_light'])
|
||||||
|
|
||||||
scrollbar = tk.Scrollbar(notes_frame)
|
scrollbar = tk.Scrollbar(
|
||||||
|
notes_frame,
|
||||||
|
bg=COLORS['bg_tertiary'],
|
||||||
|
troughcolor=COLORS['bg_secondary'],
|
||||||
|
activebackground=COLORS['bg_hover'],
|
||||||
|
)
|
||||||
scrollbar.pack(side='right', fill='y')
|
scrollbar.pack(side='right', fill='y')
|
||||||
|
|
||||||
notes_text.pack(side='left', fill='both', expand=True)
|
notes_text.pack(side='left', fill='both', expand=True)
|
||||||
@@ -259,7 +327,7 @@ class UpdateChecker:
|
|||||||
notes_text.config(state='disabled')
|
notes_text.config(state='disabled')
|
||||||
|
|
||||||
# Buttons
|
# Buttons
|
||||||
button_frame = tk.Frame(dialog, bg='#2b2b2b')
|
button_frame = tk.Frame(panel, bg=COLORS['bg_card'])
|
||||||
button_frame.pack(pady=20)
|
button_frame.pack(pady=20)
|
||||||
|
|
||||||
def download_update():
|
def download_update():
|
||||||
@@ -302,9 +370,10 @@ class UpdateChecker:
|
|||||||
download_btn = tk.Button(button_frame,
|
download_btn = tk.Button(button_frame,
|
||||||
text="Download Update",
|
text="Download Update",
|
||||||
command=download_update,
|
command=download_update,
|
||||||
bg='#00aa00', fg='white',
|
bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12, 'bold'),
|
font=(FONT_FAMILY, 12, 'bold italic'),
|
||||||
padx=20, pady=5)
|
padx=0, pady=6)
|
||||||
|
style_text_button(download_btn, COLORS['accent_green'], COLORS['bg_card'])
|
||||||
download_btn.pack(side='left', padx=5)
|
download_btn.pack(side='left', padx=5)
|
||||||
|
|
||||||
# Only show remind/skip buttons if persistence is enabled
|
# Only show remind/skip buttons if persistence is enabled
|
||||||
@@ -312,25 +381,28 @@ class UpdateChecker:
|
|||||||
later_btn = tk.Button(button_frame,
|
later_btn = tk.Button(button_frame,
|
||||||
text="Remind Later",
|
text="Remind Later",
|
||||||
command=remind_later,
|
command=remind_later,
|
||||||
bg='#0078d4', fg='white',
|
bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12),
|
font=(FONT_FAMILY, 12, 'bold italic'),
|
||||||
padx=20, pady=5)
|
padx=0, pady=6)
|
||||||
|
style_text_button(later_btn, COLORS['accent_yellow'], COLORS['bg_card'])
|
||||||
later_btn.pack(side='left', padx=5)
|
later_btn.pack(side='left', padx=5)
|
||||||
|
|
||||||
skip_btn = tk.Button(button_frame,
|
skip_btn = tk.Button(button_frame,
|
||||||
text="Skip Version",
|
text="Skip Version",
|
||||||
command=skip_version,
|
command=skip_version,
|
||||||
bg='#666666', fg='white',
|
bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12),
|
font=(FONT_FAMILY, 12, 'bold italic'),
|
||||||
padx=20, pady=5)
|
padx=0, pady=6)
|
||||||
|
style_text_button(skip_btn, COLORS['accent_red'], COLORS['bg_card'])
|
||||||
skip_btn.pack(side='left', padx=5)
|
skip_btn.pack(side='left', padx=5)
|
||||||
else:
|
else:
|
||||||
close_btn = tk.Button(button_frame,
|
close_btn = tk.Button(button_frame,
|
||||||
text="Close",
|
text="Close",
|
||||||
command=dialog.destroy,
|
command=dialog.destroy,
|
||||||
bg='#666666', fg='white',
|
bg=COLORS['bg_card'],
|
||||||
font=('Arial', 12),
|
font=(FONT_FAMILY, 12, 'bold italic'),
|
||||||
padx=20, pady=5)
|
padx=0, pady=6)
|
||||||
|
style_text_button(close_btn, COLORS['accent_red'], COLORS['bg_card'])
|
||||||
close_btn.pack(side='left', padx=5)
|
close_btn.pack(side='left', padx=5)
|
||||||
|
|
||||||
# Handle window close
|
# Handle window close
|
||||||
@@ -355,15 +427,21 @@ class UpdateChecker:
|
|||||||
"""Manually check for updates and show result"""
|
"""Manually check for updates and show result"""
|
||||||
def check_complete(release_info, error):
|
def check_complete(release_info, error):
|
||||||
if error:
|
if error:
|
||||||
messagebox.showerror("Update Check Failed",
|
self._show_notice_dialog(
|
||||||
f"Could not check for updates:\n{error}",
|
parent_window,
|
||||||
parent=parent_window)
|
"Update Check Failed",
|
||||||
|
f"Could not check for updates:\n{error}",
|
||||||
|
COLORS['accent_red'],
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
if not release_info:
|
if not release_info:
|
||||||
messagebox.showinfo("No Updates",
|
self._show_notice_dialog(
|
||||||
"Could not retrieve release information.",
|
parent_window,
|
||||||
parent=parent_window)
|
"No Updates",
|
||||||
|
"Could not retrieve release information.",
|
||||||
|
COLORS['accent_yellow'],
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
latest_version = release_info['version']
|
latest_version = release_info['version']
|
||||||
@@ -371,33 +449,44 @@ class UpdateChecker:
|
|||||||
if self.is_newer_version(latest_version) and not self.should_skip_version(latest_version):
|
if self.is_newer_version(latest_version) and not self.should_skip_version(latest_version):
|
||||||
self.show_update_dialog(parent_window, release_info)
|
self.show_update_dialog(parent_window, release_info)
|
||||||
else:
|
else:
|
||||||
messagebox.showinfo("Up to Date",
|
self._show_notice_dialog(
|
||||||
f"You are running the latest version ({self.current_version}).",
|
parent_window,
|
||||||
parent=parent_window)
|
"Up To Date",
|
||||||
|
f"You are running the latest version ({self.current_version}).",
|
||||||
|
COLORS['accent_green'],
|
||||||
|
)
|
||||||
|
|
||||||
# Show checking message
|
# Show checking message
|
||||||
checking_dialog = tk.Toplevel(parent_window)
|
checking_dialog = tk.Toplevel(parent_window)
|
||||||
checking_dialog.title("Checking for Updates")
|
checking_dialog.title("Checking for Updates")
|
||||||
checking_dialog.configure(bg='#2b2b2b')
|
checking_dialog.configure(bg=COLORS['bg_primary'])
|
||||||
checking_dialog.resizable(False, False)
|
checking_dialog.resizable(False, False)
|
||||||
checking_dialog.attributes('-topmost', True)
|
checking_dialog.attributes('-topmost', True)
|
||||||
|
|
||||||
# Center the dialog
|
panel = tk.Frame(
|
||||||
checking_dialog.geometry("300x100")
|
checking_dialog,
|
||||||
x = parent_window.winfo_x() + (parent_window.winfo_width() // 2) - 150
|
bg=COLORS['bg_card'],
|
||||||
y = parent_window.winfo_y() + (parent_window.winfo_height() // 2) - 50
|
highlightbackground=COLORS['border_light'],
|
||||||
checking_dialog.geometry(f"300x100+{x}+{y}")
|
highlightcolor=COLORS['border_light'],
|
||||||
|
highlightthickness=1,
|
||||||
label = tk.Label(checking_dialog,
|
)
|
||||||
text="Checking for updates...",
|
panel.pack(fill='both', expand=True, padx=14, pady=14)
|
||||||
fg='white', bg='#2b2b2b',
|
|
||||||
font=('Arial', 12))
|
label = tk.Label(
|
||||||
|
panel,
|
||||||
|
text="Checking for updates...",
|
||||||
|
fg=COLORS['text_primary'],
|
||||||
|
bg=COLORS['bg_card'],
|
||||||
|
font=(FONT_FAMILY, 12, 'bold italic'),
|
||||||
|
)
|
||||||
label.pack(expand=True)
|
label.pack(expand=True)
|
||||||
|
|
||||||
|
center_window(checking_dialog, 320, 120, parent_window)
|
||||||
|
|
||||||
def check_and_close():
|
def check_and_close():
|
||||||
release_info, error = self.check_for_updates_sync()
|
release_info, error = self.check_for_updates_sync()
|
||||||
checking_dialog.destroy()
|
parent_window.after(0, lambda: checking_dialog.destroy())
|
||||||
check_complete(release_info, error)
|
parent_window.after(0, lambda: check_complete(release_info, error))
|
||||||
|
|
||||||
# Start check in background
|
# Start check in background
|
||||||
threading.Thread(target=check_and_close, daemon=True).start()
|
threading.Thread(target=check_and_close, daemon=True).start()
|
||||||
@@ -452,9 +541,10 @@ def integrate_update_checker_with_gui(gui_class):
|
|||||||
update_btn = tk.Button(parent_frame,
|
update_btn = tk.Button(parent_frame,
|
||||||
text="Check Updates",
|
text="Check Updates",
|
||||||
command=self.manual_update_check,
|
command=self.manual_update_check,
|
||||||
bg='#404040', fg='white',
|
bg=COLORS['bg_card'],
|
||||||
font=('Arial', 10),
|
font=(FONT_FAMILY, 10, 'bold italic'),
|
||||||
padx=10, pady=2)
|
padx=8, pady=3)
|
||||||
|
style_text_button(update_btn, COLORS['accent_yellow'], COLORS['bg_card'])
|
||||||
update_btn.pack(side='right', padx=5, pady=5)
|
update_btn.pack(side='right', padx=5, pady=5)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Could not add update button: {e}")
|
print(f"Could not add update button: {e}")
|
||||||
@@ -484,4 +574,4 @@ def integrate_update_checker_with_gui(gui_class):
|
|||||||
gui_class.manual_update_check = manual_update_check
|
gui_class.manual_update_check = manual_update_check
|
||||||
gui_class.__init__ = new_init
|
gui_class.__init__ = new_init
|
||||||
|
|
||||||
return gui_class
|
return gui_class
|
||||||
|
|||||||
Reference in New Issue
Block a user