mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-01-17 19:47:00 +01:00
Jackify provides native Linux support for Wabbajack modlist installation and management with automated Steam integration and Proton configuration. Key Features: - Almost Native Linux implementation (texconv.exe run via proton) - Automated Steam shortcut creation and Proton prefix management - Both CLI and GUI interfaces, with Steam Deck optimization Supported Games: - Skyrim Special Edition - Fallout 4 - Fallout New Vegas - Oblivion, Starfield, Enderal, and diverse other games Technical Architecture: - Clean separation between frontend and backend services - Powered by jackify-engine 0.3.x for Wabbajack-matching modlist installation
180 lines
6.9 KiB
Python
180 lines
6.9 KiB
Python
"""
|
|
UIHandler module for managing user interface operations.
|
|
This module handles menus, prompts, and user interaction.
|
|
"""
|
|
|
|
import os
|
|
import logging
|
|
from typing import Optional, List, Dict, Tuple, Callable, Any
|
|
from pathlib import Path
|
|
|
|
class UIHandler:
|
|
def __init__(self):
|
|
self.logger = logging.getLogger(__name__)
|
|
|
|
def show_menu(self, title: str, options: List[Dict[str, Any]]) -> Optional[str]:
|
|
"""Display a menu and get user selection."""
|
|
try:
|
|
print(f"\n{title}")
|
|
print("=" * len(title))
|
|
|
|
for i, option in enumerate(options, 1):
|
|
print(f"{i}. {option['label']}")
|
|
|
|
while True:
|
|
try:
|
|
choice = input("\nEnter your choice (or 'q' to quit): ")
|
|
if choice.lower() == 'q':
|
|
return None
|
|
|
|
choice = int(choice)
|
|
if 1 <= choice <= len(options):
|
|
return options[choice - 1]['value']
|
|
else:
|
|
print("Invalid choice. Please try again.")
|
|
except ValueError:
|
|
print("Please enter a number.")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show menu: {e}")
|
|
return None
|
|
|
|
def show_progress(self, message: str, total: int = 100) -> None:
|
|
"""Display a progress indicator."""
|
|
try:
|
|
print(f"\n{message}")
|
|
print("[" + " " * 50 + "] 0%", end="\r")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show progress: {e}")
|
|
|
|
def update_progress(self, current: int, message: Optional[str] = None) -> None:
|
|
"""Update the progress indicator."""
|
|
try:
|
|
if message:
|
|
print(f"\n{message}")
|
|
progress = int(current / 2)
|
|
print("[" + "=" * progress + " " * (50 - progress) + f"] {current}%", end="\r")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to update progress: {e}")
|
|
|
|
def show_error(self, message: str, details: Optional[str] = None) -> None:
|
|
"""Display an error message."""
|
|
try:
|
|
print(f"\nError: {message}")
|
|
if details:
|
|
print(f"Details: {details}")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show error: {e}")
|
|
|
|
def show_success(self, message: str, details: Optional[str] = None) -> None:
|
|
"""Display a success message."""
|
|
try:
|
|
print(f"\n✓ Success: {message}")
|
|
if details:
|
|
print(f"Details: {details}")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show success: {e}")
|
|
|
|
def show_warning(self, message: str, details: Optional[str] = None) -> None:
|
|
"""Display a warning message."""
|
|
try:
|
|
print(f"\nWarning: {message}")
|
|
if details:
|
|
print(f"Details: {details}")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show warning: {e}")
|
|
|
|
def get_input(self, prompt: str, default: Optional[str] = None) -> str:
|
|
"""Get user input with optional default value."""
|
|
try:
|
|
if default:
|
|
user_input = input(f"{prompt} [{default}]: ")
|
|
return user_input if user_input else default
|
|
return input(f"{prompt}: ")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to get input: {e}")
|
|
return ""
|
|
|
|
def get_confirmation(self, message: str, default: bool = True) -> bool:
|
|
"""Get user confirmation for an action."""
|
|
try:
|
|
default_str = "Y/n" if default else "y/N"
|
|
while True:
|
|
response = input(f"{message} [{default_str}]: ").lower()
|
|
if not response:
|
|
return default
|
|
if response in ['y', 'yes']:
|
|
return True
|
|
if response in ['n', 'no']:
|
|
return False
|
|
print("Please enter 'y' or 'n'.")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to get confirmation: {e}")
|
|
return default
|
|
|
|
def show_list(self, title: str, items: List[str], selectable: bool = True) -> Optional[str]:
|
|
"""Display a list of items, optionally selectable."""
|
|
try:
|
|
print(f"\n{title}")
|
|
print("=" * len(title))
|
|
|
|
for i, item in enumerate(items, 1):
|
|
print(f"{i}. {item}")
|
|
|
|
if selectable:
|
|
while True:
|
|
try:
|
|
choice = input("\nEnter your choice (or 'q' to quit): ")
|
|
if choice.lower() == 'q':
|
|
return None
|
|
|
|
choice = int(choice)
|
|
if 1 <= choice <= len(items):
|
|
return items[choice - 1]
|
|
else:
|
|
print("Invalid choice. Please try again.")
|
|
except ValueError:
|
|
print("Please enter a number.")
|
|
return None
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show list: {e}")
|
|
return None
|
|
|
|
def show_table(self, title: str, headers: List[str], rows: List[List[str]]) -> None:
|
|
"""Display data in a table format."""
|
|
try:
|
|
print(f"\n{title}")
|
|
print("=" * len(title))
|
|
|
|
# Calculate column widths
|
|
widths = [len(h) for h in headers]
|
|
for row in rows:
|
|
for i, cell in enumerate(row):
|
|
widths[i] = max(widths[i], len(str(cell)))
|
|
|
|
# Print headers
|
|
header_str = " | ".join(f"{h:<{w}}" for h, w in zip(headers, widths))
|
|
print(header_str)
|
|
print("-" * len(header_str))
|
|
|
|
# Print rows
|
|
for row in rows:
|
|
print(" | ".join(f"{str(cell):<{w}}" for cell, w in zip(row, widths)))
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show table: {e}")
|
|
|
|
def show_help(self, topic: str) -> None:
|
|
"""Display help information for a topic."""
|
|
try:
|
|
# This would typically load help content from a file or database
|
|
print(f"\nHelp: {topic}")
|
|
print("=" * (len(topic) + 6))
|
|
print("Help content would be displayed here.")
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to show help: {e}")
|
|
|
|
def clear_screen(self) -> None:
|
|
"""Clear the terminal screen."""
|
|
try:
|
|
os.system('clear' if os.name == 'posix' else 'cls')
|
|
except Exception as e:
|
|
self.logger.error(f"Failed to clear screen: {e}") |