add gpg public_key ipmort
This commit is contained in:
@ -4,6 +4,8 @@ from tkinter import ttk
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
from typing import Optional, List
|
||||
import hashlib
|
||||
import getpass
|
||||
from datetime import datetime
|
||||
import tempfile
|
||||
@ -18,8 +20,9 @@ from manager import (
|
||||
Image,
|
||||
AppManager,
|
||||
LxTools,
|
||||
Locale,
|
||||
)
|
||||
from network import NetworkChecker
|
||||
from network import NetworkChecker, GiteaUpdater, GPGManager
|
||||
from message import MessageDialog
|
||||
|
||||
|
||||
@ -34,6 +37,173 @@ class InstallationManager:
|
||||
self.system_manager = System()
|
||||
self.download_manager = DownloadManager()
|
||||
|
||||
def check_gpg(self) -> bool:
|
||||
if GPGManager.is_key_already_imported(
|
||||
LXToolsAppConfig.EXPECTED_FINGERPRINT[-8:]
|
||||
):
|
||||
return True
|
||||
|
||||
all_keys_valid: bool = True
|
||||
|
||||
# 1. Check reachability of OpenPGP keyserver and process key if reachable
|
||||
openpgp_reachable: bool = GPGManager.is_url_reachable(
|
||||
LXToolsAppConfig.KEY_URL_OPENPGP
|
||||
)
|
||||
if openpgp_reachable:
|
||||
self.log(LocaleStrings.MSGGPG["keyserver_reachable"])
|
||||
self.update_progress(LocaleStrings.MSGGPG["keyserver_reachable"])
|
||||
if not GPGManager.import_key_from_url(
|
||||
key_url=LXToolsAppConfig.KEY_URL_OPENPGP,
|
||||
expected_fingerprint=LXToolsAppConfig.EXPECTED_FINGERPRINT,
|
||||
filename="public_key1.asc",
|
||||
):
|
||||
all_keys_valid = False
|
||||
else:
|
||||
self.log(LocaleStrings.MSGGPG["keyserver_unreachable"])
|
||||
self.update_progress(LocaleStrings.MSGGPG["keyserver_unreachable"])
|
||||
|
||||
# 2. Always download and verify Git.ilunix public key
|
||||
if not GPGManager.import_key_from_url(
|
||||
key_url=LXToolsAppConfig.KEY_URL_GITILUNIX,
|
||||
expected_fingerprint=LXToolsAppConfig.EXPECTED_FINGERPRINT,
|
||||
filename="public_key2.asc",
|
||||
):
|
||||
all_keys_valid = False
|
||||
|
||||
# Final step: Proceed only if all fingerprints match or OpenPGP was unreachable
|
||||
if all_keys_valid:
|
||||
self.log(LocaleStrings.MSGGPG["all_keys_valid"])
|
||||
self.update_progress(LocaleStrings.MSGGPG["all_keys_valid"])
|
||||
key_id: str = LXToolsAppConfig.EXPECTED_FINGERPRINT[-8:]
|
||||
|
||||
if not GPGManager.update_gpg_trust_level(key_id, trust_level=5):
|
||||
self.log(LocaleStrings.MSGGPG["error_updating_trust_level"], key_id)
|
||||
self.update_progress(
|
||||
LocaleStrings.MSGGPG["error_updating_trust_level"], key_id
|
||||
)
|
||||
return False
|
||||
else:
|
||||
self.log(f"{LocaleStrings.MSGGPG['set_trust_level']}{key_id}.")
|
||||
self.update_progress(
|
||||
f"{LocaleStrings.MSGGPG['set_trust_level']}{key_id}."
|
||||
)
|
||||
return True
|
||||
|
||||
else:
|
||||
self.log(LocaleStrings.MSGGPG["not_all_keys_are_valid"])
|
||||
self.update_progress(LocaleStrings.MSGGPG["not_all_keys_are_valid"])
|
||||
|
||||
def check_appimage(self) -> bool | None | str:
|
||||
"""
|
||||
Checks the current version of the lxtools_installer AppImage by:
|
||||
|
||||
1. Downloading it from Gitea (with checksum and signature verification).
|
||||
2. Renaming and making it executable.
|
||||
3. Comparing its SHA-256 hash with an existing reference file at `/usr/local/bin/lxtools_installer`.
|
||||
4. Returns `True` if the hashes match, otherwise `False`.
|
||||
|
||||
Returns:
|
||||
bool: True if AppImages are identical; False if they differ or an error occurred.
|
||||
"""
|
||||
appimage_path: Optional[str] = GiteaUpdater.download_appimage(
|
||||
verify_checksum=True, verify_signature=True
|
||||
)
|
||||
|
||||
tests: List[str] = [
|
||||
"Checksum file not found",
|
||||
"Signature file not found",
|
||||
"Checksum mismatch",
|
||||
"Signature verification failed",
|
||||
]
|
||||
|
||||
if appimage_path is None or appimage_path in tests:
|
||||
print(f"{LocaleStrings.MSGA['error']}{appimage_path}")
|
||||
return None
|
||||
|
||||
else:
|
||||
try:
|
||||
if os.path.isfile(appimage_path):
|
||||
|
||||
new_filename = "/tmp/portinstaller/lxtools_installer"
|
||||
|
||||
result = subprocess.run(
|
||||
["mv", appimage_path, new_filename],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
self.update_progress(LocaleStrings.MSGA["appimage_renamed"])
|
||||
self.log(LocaleStrings.MSGA["appimage_renamed"])
|
||||
else:
|
||||
self.update_progress(
|
||||
f"{LocaleStrings.MSGA['appimage_rename_error']}{result.stderr}"
|
||||
)
|
||||
self.log(
|
||||
f"{LocaleStrings.MSGA['appimage_rename_error']}{result.stderr}"
|
||||
)
|
||||
|
||||
result = subprocess.run(
|
||||
["chmod", "+x", new_filename],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=False,
|
||||
)
|
||||
if result.returncode == 0:
|
||||
self.update_progress(
|
||||
LocaleStrings.MSGA["appimage_executable_success"]
|
||||
)
|
||||
self.log(LocaleStrings.MSGA["appimage_executable_success"])
|
||||
else:
|
||||
self.update_progress(
|
||||
f"{LocaleStrings.MSGA['appimage_executable_error']}{result.stderr}"
|
||||
)
|
||||
self.log(
|
||||
f"{LocaleStrings.MSGA['appimage_executable_error']}{result.stderr}"
|
||||
)
|
||||
|
||||
# Define reference path
|
||||
reference_appimage_path = "/usr/local/bin/lxtools_installer"
|
||||
if os.path.isfile(reference_appimage_path):
|
||||
|
||||
def calculate_sha256(file_path: str) -> str:
|
||||
"""
|
||||
Calculates the SHA-256 hash of a file.
|
||||
|
||||
Args:
|
||||
file_path (str): Path to the file.
|
||||
|
||||
Returns:
|
||||
str: Hexdigest of the SHA-256 hash.
|
||||
"""
|
||||
hash_obj = hashlib.sha256()
|
||||
with open(file_path, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
hash_obj.update(chunk)
|
||||
return hash_obj.hexdigest()
|
||||
|
||||
# Calculate hashes
|
||||
new_checksum = calculate_sha256(new_filename)
|
||||
reference_checksum = calculate_sha256(reference_appimage_path)
|
||||
|
||||
# Compare and decide action
|
||||
if new_checksum == reference_checksum:
|
||||
return "True" # String as a compatibility solution to network.py
|
||||
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
self.update_progress(LocaleStrings.MSGA["appimage_not_exist"])
|
||||
self.log(LocaleStrings.MSGA["appimage_not_exist"])
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
self.update_progress(f"Exception occurred: {str(e)}")
|
||||
self.log(f"Exception occurred: {str(e)}")
|
||||
return None
|
||||
|
||||
def install_project(self, project_key):
|
||||
"""Install or update project"""
|
||||
project_info = self.app_manager.get_project_info(project_key)
|
||||
@ -77,6 +247,13 @@ class InstallationManager:
|
||||
raise Exception(f"{LocaleStrings.MSGI['unknow_project']}{project_key}")
|
||||
|
||||
def _create_wirepy_install_script(self):
|
||||
gpg_checker = self.check_gpg()
|
||||
result_appimage = self.check_appimage()
|
||||
if not gpg_checker:
|
||||
print(gpg_checker)
|
||||
return
|
||||
if result_appimage is True or result_appimage is None:
|
||||
return
|
||||
detected_os = Detector.get_os()
|
||||
if detected_os == "Arch Linux":
|
||||
result_unzip = Detector.get_unzip()
|
||||
@ -90,13 +267,14 @@ class InstallationManager:
|
||||
"""Create Wire-Py installation script"""
|
||||
script = f"""#!/bin/bash
|
||||
set -e
|
||||
|
||||
echo "=== Wire-Py Installation ==="
|
||||
if [ "{result_appimage}" = "False" ]; then
|
||||
cp -f /tmp/portinstaller/lxtools_installer /usr/local/bin/lxtools_installer
|
||||
fi
|
||||
if [ "{detected_os}" = "Arch Linux" ]; then
|
||||
if [ "{result_unzip}" = "False" ]; then
|
||||
pacman -S --noconfirm unzip
|
||||
fi
|
||||
|
||||
|
||||
if [ "{result_wget}" = "False" ]; then
|
||||
pacman -S --noconfirm wget
|
||||
fi
|
||||
@ -215,13 +393,21 @@ fi
|
||||
|
||||
# Cleanup
|
||||
cd /tmp
|
||||
rm -rf wirepy_install
|
||||
rm -rf wirepy_install portinstaller
|
||||
|
||||
echo "Wire-Py installation completed!"
|
||||
"""
|
||||
return script
|
||||
|
||||
def _create_logviewer_install_script(self):
|
||||
gpg_checker = self.check_gpg()
|
||||
result_appimage = self.check_appimage()
|
||||
if not gpg_checker:
|
||||
print(gpg_checker)
|
||||
return
|
||||
|
||||
if result_appimage is True or result_appimage is None:
|
||||
return
|
||||
detected_os = Detector.get_os()
|
||||
if detected_os == "Arch Linux":
|
||||
result_unzip = Detector.get_unzip()
|
||||
@ -235,7 +421,10 @@ echo "Wire-Py installation completed!"
|
||||
script = f"""#!/bin/bash
|
||||
set -e
|
||||
{LXToolsAppConfig.TKINTER_INSTALL_COMMANDS[detected_os]} 2>&1 | grep -v "apt does not have a stable CLI interface"
|
||||
echo "=== LogViewer Installation ==="
|
||||
|
||||
if [ "{result_appimage}" = "False" ]; then
|
||||
cp -f /tmp/portinstaller/lxtools_installer /usr/local/bin/lxtools_installer
|
||||
fi
|
||||
if [ "{detected_os}" = "Arch Linux" ]; then
|
||||
if [ "{result_unzip}" = "False" ]; then
|
||||
pacman -S --noconfirm unzip
|
||||
@ -273,12 +462,12 @@ if [ ! -d "/usr/share/TK-Themes" ] || [ -z "$(ls -A /usr/share/TK-Themes 2>/dev/
|
||||
wget -q "{LXToolsAppConfig.WIREPY_URL}" -O wirepy.zip
|
||||
unzip -q wirepy.zip
|
||||
WIREPY_DIR=$(find . -name "Wire-Py" -type d | head -1)
|
||||
|
||||
|
||||
if [ -d "$WIREPY_DIR/TK-Themes" ]; then
|
||||
echo "Installing TK-Themes..."
|
||||
cp -rf "$WIREPY_DIR/TK-Themes"/* /usr/share/TK-Themes/
|
||||
fi
|
||||
|
||||
|
||||
# Also install icons from Wire-Py if not present
|
||||
if [ -d "$WIREPY_DIR/lx-icons" ] && [ ! -d "/usr/share/icons/lx-icons" ]; then
|
||||
echo "Installing icons from Wire-Py..."
|
||||
@ -315,7 +504,7 @@ fi
|
||||
|
||||
# Cleanup
|
||||
cd /tmp
|
||||
rm -rf logviewer_install
|
||||
rm -rf logviewer_install portinstaller
|
||||
|
||||
echo "LogViewer installation completed!"
|
||||
"""
|
||||
@ -344,7 +533,7 @@ echo "LogViewer installation completed!"
|
||||
|
||||
# Log output
|
||||
if result.stdout:
|
||||
self.log(f"STDOUT: {result.stdout}")
|
||||
self.log((result.stdout).strip("Log\n"))
|
||||
if result.stderr:
|
||||
self.log(f"STDERR: {result.stderr}")
|
||||
|
||||
@ -358,6 +547,7 @@ echo "LogViewer installation completed!"
|
||||
|
||||
except subprocess.TimeoutExpired:
|
||||
raise Exception(LocaleStrings.MSGI["install_timeout"])
|
||||
|
||||
except subprocess.CalledProcessError as e:
|
||||
raise Exception(f"{LocaleStrings.MSGI['install_script_failed']}{e}")
|
||||
|
||||
@ -476,12 +666,13 @@ if [ ! -f /usr/local/bin/logviewer ] || [ ! -L /usr/local/bin/logviewer ]; then
|
||||
echo "No other LX apps found, removing shared resources..."
|
||||
rm -rf /usr/share/icons/lx-icons
|
||||
rm -rf /usr/share/TK-Themes
|
||||
|
||||
rm -rf /usr/local/bin/lxtools_installer
|
||||
|
||||
# Remove shared libs
|
||||
for file in common_tools.py file_and_dir_ensure.py gitea.py __init__.py logview_app_config.py logviewer.py; do
|
||||
rm -f {LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/$file
|
||||
done
|
||||
|
||||
|
||||
# Try to remove shared_libs directory if empty
|
||||
rmdir {LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]} 2>/dev/null || true
|
||||
else
|
||||
@ -523,15 +714,16 @@ if [ ! -f /usr/local/bin/wirepy ] || [ ! -L /usr/local/bin/wirepy ]; then
|
||||
echo "No other LX apps found, removing shared resources..."
|
||||
rm -rf /usr/share/icons/lx-icons
|
||||
rm -rf /usr/share/TK-Themes
|
||||
|
||||
rm -rf /usr/local/bin/lxtools_installer
|
||||
|
||||
# Remove shared libs (but keep logviewer.py if we're only uninstalling logviewer)
|
||||
for file in common_tools.py file_and_dir_ensure.py gitea.py __init__.py logview_app_config.py; do
|
||||
rm -f {LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/$file
|
||||
done
|
||||
|
||||
|
||||
# Remove logviewer.py last
|
||||
rm -f {LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os]}/logviewer.py
|
||||
|
||||
|
||||
# Try to remove shared_libs directory if empty
|
||||
rmdir LXToolsAppConfig.SHARED_LIBS_DESTINATION[detected_os] 2>/dev/null || true
|
||||
else
|
||||
@ -568,7 +760,7 @@ echo "LogViewer uninstallation completed!"
|
||||
|
||||
# Log output
|
||||
if result.stdout:
|
||||
self.log(f"STDOUT: {result.stdout}")
|
||||
self.log(result.stdout)
|
||||
if result.stderr:
|
||||
self.log(f"STDERR: {result.stderr}")
|
||||
|
||||
@ -628,6 +820,8 @@ class LXToolsGUI:
|
||||
self.download_icon_label = None
|
||||
self.log_text = None
|
||||
self.selected_project = None
|
||||
self.polkit_ok = Detector.get_polkit()
|
||||
self.networkmanager_ok = Detector.get_networkmanager()
|
||||
self.project_frames = {}
|
||||
self.status_labels = {}
|
||||
self.version_labels = {}
|
||||
@ -661,7 +855,7 @@ class LXToolsGUI:
|
||||
def create_gui(self):
|
||||
"""Create the main GUI"""
|
||||
self.root = tk.Tk()
|
||||
self.root.title(f"{LXToolsAppConfig.APP_NAME} v{LXToolsAppConfig.VERSION}")
|
||||
self.root.title(f"{Locale.APP_NAME} v{LXToolsAppConfig.VERSION}")
|
||||
self.root.geometry(
|
||||
f"{LXToolsAppConfig.WINDOW_WIDTH}x{LXToolsAppConfig.WINDOW_HEIGHT}+100+100"
|
||||
)
|
||||
@ -677,6 +871,7 @@ class LXToolsGUI:
|
||||
self.root.iconphoto(False, icon)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.root.minsize(LXToolsAppConfig.WINDOW_WIDTH, LXToolsAppConfig.WINDOW_HEIGHT)
|
||||
Theme.apply_light_theme(self.root)
|
||||
# Create header
|
||||
@ -719,10 +914,25 @@ class LXToolsGUI:
|
||||
icon_text_frame = tk.Frame(left_side, bg="#2c3e50")
|
||||
icon_text_frame.pack(anchor="w")
|
||||
|
||||
# Tool-Icon
|
||||
tk.Label(
|
||||
icon_text_frame, text="🔧", font=("Helvetica", 18), bg="#2c3e50", fg="white"
|
||||
).pack(side="left", padx=(0, 8))
|
||||
# Tool-Icon (versuche echtes Icon, dann Fallback)
|
||||
try:
|
||||
icon = self.image_manager.load_image("header_image")
|
||||
if icon:
|
||||
# Resize icon für Header
|
||||
icon_label = tk.Label(icon_text_frame, image=icon, bg="#2c3e50")
|
||||
icon_label.image = icon # Referenz behalten
|
||||
icon_label.pack(side="left", padx=(0, 8))
|
||||
else:
|
||||
raise Exception("Kein Icon gefunden")
|
||||
except:
|
||||
# Fallback: Unicode-Symbol statt Emoji
|
||||
tk.Label(
|
||||
icon_text_frame,
|
||||
text="⚙",
|
||||
font=("Helvetica", 18),
|
||||
bg="#2c3e50",
|
||||
fg="white",
|
||||
).pack(side="left", padx=(0, 8))
|
||||
|
||||
# App Name and Version
|
||||
text_frame = tk.Frame(icon_text_frame, bg="#2c3e50")
|
||||
@ -774,40 +984,51 @@ class LXToolsGUI:
|
||||
|
||||
def check_ready_status(self):
|
||||
"""Check if system is ready for installation"""
|
||||
# Checks:
|
||||
polkit_ok = Detector.get_polkit()
|
||||
networkmanager_ok = Detector.get_networkmanager()
|
||||
|
||||
# Führe alle Checks durch
|
||||
internet_ok = NetworkChecker.check_internet_connection()
|
||||
repo_ok = NetworkChecker.check_repository_access()
|
||||
result = Detector.get_host_python_version()
|
||||
python_result = Detector.get_host_python_version()
|
||||
|
||||
if not polkit_ok:
|
||||
self.update_header_status(
|
||||
LocaleStrings.MSGO["polkit_check"], "#e74c3c"
|
||||
) # Red
|
||||
if not networkmanager_ok:
|
||||
self.update_header_status(
|
||||
LocaleStrings.MSGO["networkmanager_check"], "#e74c3c"
|
||||
) # Red
|
||||
# Sammle alle Probleme
|
||||
issues = []
|
||||
if not self.polkit_ok:
|
||||
issues.append(("PolicyKit", "#e74c3c", LocaleStrings.MSGO["polkit_check"]))
|
||||
if not self.networkmanager_ok:
|
||||
issues.append(
|
||||
(
|
||||
"NetworkManager",
|
||||
"#e74c3c",
|
||||
LocaleStrings.MSGO["networkmanager_check"],
|
||||
)
|
||||
)
|
||||
if not internet_ok:
|
||||
issues.append(("Internet", "#e74c3c", LocaleStrings.MSGO["no_internet"]))
|
||||
if not repo_ok:
|
||||
issues.append(
|
||||
("Repository", "#f39c12", LocaleStrings.MSGO["repo_unavailable"])
|
||||
)
|
||||
if python_result is None:
|
||||
issues.append(("Python", "#e74c3c", LocaleStrings.MSGO["python_check"]))
|
||||
|
||||
if internet_ok and repo_ok and result is not None:
|
||||
self.update_header_status(LocaleStrings.MSGO["ready"], "#1abc9c") # Green
|
||||
elif not internet_ok:
|
||||
self.update_header_status(
|
||||
LocaleStrings.MSGO["no_internet"], "#e74c3c"
|
||||
) # Red
|
||||
elif not repo_ok:
|
||||
self.update_header_status(
|
||||
LocaleStrings.MSGO["repo_unavailable"], "#f39c12"
|
||||
) # Orange
|
||||
elif result is None:
|
||||
self.update_header_status(
|
||||
LocaleStrings.MSGO["python_check"], "#e74c3c"
|
||||
) # Red
|
||||
# Bestimme Hauptstatus basierend auf Priorität
|
||||
if issues:
|
||||
# Zeige das wichtigste Problem (Internet > Python > Repository > Services)
|
||||
for priority_check in [
|
||||
"Internet",
|
||||
"Python",
|
||||
"Repository",
|
||||
"PolicyKit",
|
||||
"NetworkManager",
|
||||
]:
|
||||
for issue_name, color, message in issues:
|
||||
if issue_name == priority_check:
|
||||
print(f"DEBUG: Zeige Problem: {issue_name} - {message}")
|
||||
self.update_header_status(message, color)
|
||||
return
|
||||
else:
|
||||
self.update_header_status(
|
||||
LocaleStrings.MSGO["system_check"], "#3498db"
|
||||
) # Blue
|
||||
|
||||
self.update_header_status(LocaleStrings.MSGO["ready"], "#1abc9c") # Green
|
||||
|
||||
def _create_projects_tab(self):
|
||||
"""Create projects tab with project cards"""
|
||||
@ -1046,14 +1267,16 @@ class LXToolsGUI:
|
||||
clear_log_btn.pack(side="right", pady=(0, 10))
|
||||
|
||||
# Initial log message
|
||||
self.log_message(
|
||||
f"=== {LXToolsAppConfig.APP_NAME} v {LXToolsAppConfig.VERSION} ==="
|
||||
)
|
||||
self.log_message(f"=== {Locale.APP_NAME} v {LXToolsAppConfig.VERSION} ===")
|
||||
self.log_message(f"{LocaleStrings.MSGL['work_dir']}{LXToolsAppConfig.WORK_DIR}")
|
||||
self.log_message(
|
||||
f"{LocaleStrings.MSGL['icons_dir']}{LXToolsAppConfig.ICONS_DIR}"
|
||||
)
|
||||
self.log_message(f"{LocaleStrings.MSGL['detected_os']}{self.detected_os}")
|
||||
self.log_message(f"{LocaleStrings.MSGO['polkit_check_log']}{self.polkit_ok}")
|
||||
self.log_message(
|
||||
f"{LocaleStrings.MSGO['networkmanager_check_log']}{self.networkmanager_ok}"
|
||||
)
|
||||
self.log_message(f"{LocaleStrings.MSGO['ready']}...")
|
||||
|
||||
def _create_progress_section(self):
|
||||
@ -1089,58 +1312,87 @@ class LXToolsGUI:
|
||||
button_frame = tk.Frame(self.root, bg=self.colors["bg"])
|
||||
button_frame.pack(fill="x", padx=15, pady=(5, 10))
|
||||
|
||||
# Button style configuration
|
||||
style = ttk.Style()
|
||||
# Button style configuration (mit Error-Handling für Linux Mint)
|
||||
try:
|
||||
style = ttk.Style()
|
||||
|
||||
# Install button (green)
|
||||
style.configure("Install.TButton", foreground="#27ae60", font=("Helvetica", 11))
|
||||
style.map(
|
||||
"Install.TButton",
|
||||
foreground=[("active", "#14542f"), ("pressed", "#1e8449")],
|
||||
)
|
||||
# Install button (green)
|
||||
style.configure(
|
||||
"Install.TButton", foreground="#27ae60", font=("Helvetica", 11)
|
||||
)
|
||||
style.map(
|
||||
"Install.TButton",
|
||||
foreground=[("active", "#14542f"), ("pressed", "#1e8449")],
|
||||
)
|
||||
|
||||
# Uninstall button (red)
|
||||
style.configure(
|
||||
"Uninstall.TButton", foreground="#e74c3c", font=("Helvetica", 11)
|
||||
)
|
||||
style.map(
|
||||
"Uninstall.TButton",
|
||||
foreground=[("active", "#7d3b34"), ("pressed", "#c0392b")],
|
||||
)
|
||||
# Uninstall button (red)
|
||||
style.configure(
|
||||
"Uninstall.TButton", foreground="#e74c3c", font=("Helvetica", 11)
|
||||
)
|
||||
style.map(
|
||||
"Uninstall.TButton",
|
||||
foreground=[("active", "#7d3b34"), ("pressed", "#c0392b")],
|
||||
)
|
||||
# Refresh button (blue)
|
||||
style.configure(
|
||||
"Refresh.TButton", foreground="#3498db", font=("Helvetica", 11)
|
||||
)
|
||||
style.map(
|
||||
"Refresh.TButton",
|
||||
foreground=[("active", "#1e3747"), ("pressed", "#2980b9")],
|
||||
)
|
||||
except Exception as e:
|
||||
print(f"Style-Konfiguration fehlgeschlagen: {e}")
|
||||
# Fallback: verwende Standard-Styles
|
||||
|
||||
# Refresh button (blue)
|
||||
style.configure("Refresh.TButton", foreground="#3498db", font=("Helvetica", 11))
|
||||
style.map(
|
||||
"Refresh.TButton",
|
||||
foreground=[("active", "#1e3747"), ("pressed", "#2980b9")],
|
||||
)
|
||||
|
||||
# Create buttons
|
||||
install_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["install"],
|
||||
command=self.install_selected,
|
||||
style="Install.TButton",
|
||||
padding=8,
|
||||
)
|
||||
# Create buttons (mit Fallback für Style-Probleme)
|
||||
try:
|
||||
install_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["install"],
|
||||
command=self.install_selected,
|
||||
style="Install.TButton",
|
||||
padding=8,
|
||||
)
|
||||
except:
|
||||
install_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["install"],
|
||||
command=self.install_selected,
|
||||
)
|
||||
install_btn.pack(side="left", padx=(0, 10))
|
||||
|
||||
uninstall_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["uninstall"],
|
||||
command=self.uninstall_selected,
|
||||
style="Uninstall.TButton",
|
||||
padding=8,
|
||||
)
|
||||
try:
|
||||
uninstall_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["uninstall"],
|
||||
command=self.uninstall_selected,
|
||||
style="Uninstall.TButton",
|
||||
padding=8,
|
||||
)
|
||||
except:
|
||||
uninstall_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["uninstall"],
|
||||
command=self.uninstall_selected,
|
||||
)
|
||||
uninstall_btn.pack(side="left", padx=(0, 10))
|
||||
|
||||
refresh_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["refresh"],
|
||||
command=self.refresh_status,
|
||||
style="Refresh.TButton",
|
||||
padding=8,
|
||||
)
|
||||
try:
|
||||
refresh_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["refresh"],
|
||||
command=self.refresh_status,
|
||||
style="Refresh.TButton",
|
||||
width=30,
|
||||
padding=8,
|
||||
)
|
||||
except:
|
||||
refresh_btn = ttk.Button(
|
||||
button_frame,
|
||||
text=LocaleStrings.MSGB["refresh"],
|
||||
command=self.refresh_status,
|
||||
)
|
||||
refresh_btn.pack(side="right")
|
||||
|
||||
def update_download_icon(self, status):
|
||||
@ -1211,16 +1463,16 @@ class LXToolsGUI:
|
||||
if latest_version != "Unknown":
|
||||
if installed_version != f"v. {latest_version}":
|
||||
version_label.config(
|
||||
text=f"{LocaleStrings.MSGC['latest']}(v. {latest_version}) {LocaleStrings.MSGC['update_available']}",
|
||||
text=f"{LocaleStrings.MSGC['update_on']}(v. {latest_version}) {LocaleStrings.MSGC['available_lower']}",
|
||||
fg="orange",
|
||||
)
|
||||
self.log_message(
|
||||
f"{project_info['name']}: {LocaleStrings.MSGC['update_available']}(v. {latest_version})"
|
||||
f"{project_info['name']}: {LocaleStrings.MSGC['update_on']}(v. {latest_version} {LocaleStrings.MSGC['available_lower']})"
|
||||
)
|
||||
|
||||
else:
|
||||
version_label.config(
|
||||
text=f"{LocaleStrings.MSGC['latest']}: (v. {latest_version}) {LocaleStrings.MSGC['up_to_date']}",
|
||||
text=f"(v. {latest_version}) {LocaleStrings.MSGC['up_to_date']}",
|
||||
fg="green",
|
||||
)
|
||||
self.log_message(
|
||||
@ -1379,7 +1631,7 @@ class LXToolsGUI:
|
||||
|
||||
def main():
|
||||
"""Main function to start the application"""
|
||||
print(f"=== {LXToolsAppConfig.APP_NAME} v {LXToolsAppConfig.VERSION} ===")
|
||||
print(f"=== {Locale.APP_NAME} v {LXToolsAppConfig.VERSION} ===")
|
||||
print(f"{LocaleStrings.MSGL['working_dir']}{os.getcwd()}")
|
||||
|
||||
try:
|
||||
|
Reference in New Issue
Block a user