Polish UI with modern card layout and refined dark theme
Some checks are pending
Build and Release / build (push) Waiting to run
Some checks are pending
Build and Release / build (push) Waiting to run
This commit is contained in:
parent
c3c81c21ab
commit
56e4355d6b
@ -58,7 +58,7 @@ MANIFEST_FILE = Path(__file__).with_name("rd_download_manifest.json")
|
|||||||
LOG_FILE = Path(__file__).with_name("rd_downloader.log")
|
LOG_FILE = Path(__file__).with_name("rd_downloader.log")
|
||||||
CHUNK_SIZE = 1024 * 512
|
CHUNK_SIZE = 1024 * 512
|
||||||
APP_NAME = "Real-Debrid Downloader GUI"
|
APP_NAME = "Real-Debrid Downloader GUI"
|
||||||
APP_VERSION = "1.1.7"
|
APP_VERSION = "1.1.8"
|
||||||
DEFAULT_UPDATE_REPO = "Sucukdeluxe/real-debrid-downloader"
|
DEFAULT_UPDATE_REPO = "Sucukdeluxe/real-debrid-downloader"
|
||||||
DEFAULT_RELEASE_ASSET = "Real-Debrid-Downloader-win64.zip"
|
DEFAULT_RELEASE_ASSET = "Real-Debrid-Downloader-win64.zip"
|
||||||
DCRYPT_UPLOAD_URL = "https://dcrypt.it/decrypt/upload"
|
DCRYPT_UPLOAD_URL = "https://dcrypt.it/decrypt/upload"
|
||||||
@ -644,137 +644,192 @@ class DownloaderApp(TkBase):
|
|||||||
def _build_ui(self) -> None:
|
def _build_ui(self) -> None:
|
||||||
self._configure_modern_theme()
|
self._configure_modern_theme()
|
||||||
|
|
||||||
root = ttk.Frame(self, padding=10)
|
root = ttk.Frame(self, style="App.TFrame", padding=(16, 14, 16, 12))
|
||||||
root.pack(fill="both", expand=True)
|
root.pack(fill="both", expand=True)
|
||||||
root.columnconfigure(0, weight=1)
|
root.columnconfigure(0, weight=1)
|
||||||
root.rowconfigure(1, weight=1)
|
root.rowconfigure(2, weight=1)
|
||||||
|
|
||||||
header = ttk.LabelFrame(root, text="Steuerung", padding=10)
|
title_row = ttk.Frame(root, style="App.TFrame")
|
||||||
header.grid(row=0, column=0, sticky="ew")
|
title_row.grid(row=0, column=0, sticky="ew")
|
||||||
header.columnconfigure(9, weight=1)
|
title_row.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
self.start_button = ttk.Button(header, text="Start", command=self.start_downloads)
|
ttk.Label(title_row, text="Real-Debrid Download Manager", style="HeaderTitle.TLabel").grid(row=0, column=0, sticky="w")
|
||||||
|
ttk.Label(title_row, text=f"v{APP_VERSION}", style="HeaderMeta.TLabel").grid(row=0, column=1, sticky="w", padx=(10, 0))
|
||||||
|
|
||||||
|
metrics = ttk.Frame(title_row, style="App.TFrame")
|
||||||
|
metrics.grid(row=0, column=2, sticky="e")
|
||||||
|
ttk.Label(metrics, textvariable=self.speed_var, style="HeaderValue.TLabel").pack(side="right", padx=(14, 0))
|
||||||
|
ttk.Label(metrics, textvariable=self.eta_var, style="HeaderMeta.TLabel").pack(side="right")
|
||||||
|
|
||||||
|
control_bar = ttk.Frame(root, style="Surface.TFrame", padding=(14, 10))
|
||||||
|
control_bar.grid(row=1, column=0, sticky="ew", pady=(10, 12))
|
||||||
|
control_bar.columnconfigure(12, weight=1)
|
||||||
|
|
||||||
|
self.start_button = ttk.Button(control_bar, text="Start", style="Accent.TButton", command=self.start_downloads)
|
||||||
self.start_button.grid(row=0, column=0, sticky="w")
|
self.start_button.grid(row=0, column=0, sticky="w")
|
||||||
self.pause_button = ttk.Button(header, text="Pause", command=self.toggle_pause_downloads, state="disabled")
|
self.pause_button = ttk.Button(control_bar, text="Pause", style="Ghost.TButton", command=self.toggle_pause_downloads, state="disabled")
|
||||||
self.pause_button.grid(row=0, column=1, sticky="w", padx=(8, 0))
|
self.pause_button.grid(row=0, column=1, sticky="w", padx=(8, 0))
|
||||||
self.stop_button = ttk.Button(header, text="Stop", command=self.stop_downloads, state="disabled")
|
self.stop_button = ttk.Button(control_bar, text="Stop", style="Ghost.TButton", command=self.stop_downloads, state="disabled")
|
||||||
self.stop_button.grid(row=0, column=2, sticky="w", padx=(8, 0))
|
self.stop_button.grid(row=0, column=2, sticky="w", padx=(8, 0))
|
||||||
ttk.Button(header, text="Fortschritt leeren", command=self._clear_progress_only).grid(row=0, column=3, sticky="w", padx=(10, 0))
|
ttk.Button(control_bar, text="Fortschritt leeren", style="Ghost.TButton", command=self._clear_progress_only).grid(
|
||||||
|
row=0,
|
||||||
|
column=3,
|
||||||
|
sticky="w",
|
||||||
|
padx=(10, 0),
|
||||||
|
)
|
||||||
|
|
||||||
|
ttk.Separator(control_bar, orient="vertical").grid(row=0, column=4, sticky="ns", padx=(14, 14))
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
header,
|
control_bar,
|
||||||
text="Speed-Limit aktiv",
|
text="Speed-Limit",
|
||||||
|
style="Surface.TCheckbutton",
|
||||||
variable=self.speed_limit_enabled_var,
|
variable=self.speed_limit_enabled_var,
|
||||||
command=self._on_speed_limit_enabled_toggle,
|
command=self._on_speed_limit_enabled_toggle,
|
||||||
).grid(row=0, column=4, sticky="w", padx=(16, 0))
|
).grid(row=0, column=5, sticky="w")
|
||||||
self.speed_limit_spin = ttk.Spinbox(header, from_=0, to=500000, width=8, textvariable=self.speed_limit_kbps_var)
|
self.speed_limit_spin = ttk.Spinbox(control_bar, from_=0, to=500000, width=8, textvariable=self.speed_limit_kbps_var)
|
||||||
self.speed_limit_spin.grid(row=0, column=5, sticky="w", padx=(6, 0))
|
self.speed_limit_spin.grid(row=0, column=6, sticky="w", padx=(8, 0))
|
||||||
ttk.Label(header, text="KB/s").grid(row=0, column=6, sticky="w", padx=(4, 0))
|
ttk.Label(control_bar, text="KB/s", style="Surface.TLabel").grid(row=0, column=7, sticky="w", padx=(5, 0))
|
||||||
self.speed_mode_box = ttk.Combobox(
|
self.speed_mode_box = ttk.Combobox(
|
||||||
header,
|
control_bar,
|
||||||
textvariable=self.speed_limit_mode_var,
|
textvariable=self.speed_limit_mode_var,
|
||||||
values=SPEED_MODE_CHOICES,
|
values=SPEED_MODE_CHOICES,
|
||||||
width=12,
|
width=12,
|
||||||
state="readonly",
|
state="readonly",
|
||||||
)
|
)
|
||||||
self.speed_mode_box.grid(row=0, column=7, sticky="w", padx=(8, 0))
|
self.speed_mode_box.grid(row=0, column=8, sticky="w", padx=(8, 0))
|
||||||
ttk.Button(header, text="Update suchen", command=self._manual_check_updates).grid(row=0, column=8, sticky="w", padx=(10, 0))
|
ttk.Button(control_bar, text="Update suchen", style="Ghost.TButton", command=self._manual_check_updates).grid(
|
||||||
|
row=0,
|
||||||
ttk.Label(header, textvariable=self.speed_var).grid(row=0, column=9, sticky="e", padx=(10, 0))
|
column=9,
|
||||||
ttk.Label(header, textvariable=self.eta_var).grid(row=0, column=10, sticky="e", padx=(10, 0))
|
sticky="w",
|
||||||
|
padx=(12, 0),
|
||||||
|
)
|
||||||
|
|
||||||
self.main_tabs = ttk.Notebook(root)
|
self.main_tabs = ttk.Notebook(root)
|
||||||
self.main_tabs.grid(row=1, column=0, sticky="nsew", pady=(10, 0))
|
self.main_tabs.grid(row=2, column=0, sticky="nsew")
|
||||||
|
|
||||||
collector_tab = ttk.Frame(self.main_tabs, padding=8)
|
collector_tab = ttk.Frame(self.main_tabs, style="App.TFrame", padding=10)
|
||||||
downloads_tab = ttk.Frame(self.main_tabs, padding=8)
|
downloads_tab = ttk.Frame(self.main_tabs, style="App.TFrame", padding=10)
|
||||||
settings_tab = ttk.Frame(self.main_tabs, padding=8)
|
settings_tab = ttk.Frame(self.main_tabs, style="App.TFrame", padding=10)
|
||||||
self.main_tabs.add(collector_tab, text="Linksammler")
|
self.main_tabs.add(collector_tab, text="Linksammler")
|
||||||
self.main_tabs.add(downloads_tab, text="Downloads")
|
self.main_tabs.add(downloads_tab, text="Downloads")
|
||||||
self.main_tabs.add(settings_tab, text="Settings")
|
self.main_tabs.add(settings_tab, text="Settings")
|
||||||
|
|
||||||
collector_tab.columnconfigure(0, weight=1)
|
collector_tab.columnconfigure(0, weight=1)
|
||||||
collector_tab.rowconfigure(2, weight=1)
|
collector_tab.rowconfigure(1, weight=1)
|
||||||
|
|
||||||
token_frame = ttk.LabelFrame(collector_tab, text="Authentifizierung & Update", padding=10)
|
collector_top = ttk.Frame(collector_tab, style="App.TFrame")
|
||||||
token_frame.grid(row=0, column=0, sticky="ew")
|
collector_top.grid(row=0, column=0, sticky="ew")
|
||||||
token_frame.columnconfigure(1, weight=1)
|
collector_top.columnconfigure(0, weight=1)
|
||||||
|
collector_top.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
ttk.Label(token_frame, text="Real-Debrid API Token:").grid(row=0, column=0, sticky="w", padx=(0, 8))
|
auth_card, auth = self._create_card(
|
||||||
self.token_entry = ttk.Entry(token_frame, textvariable=self.token_var, show="*", width=80)
|
collector_top,
|
||||||
|
"Authentifizierung",
|
||||||
|
"Token, Update-Quelle und Startverhalten",
|
||||||
|
)
|
||||||
|
auth_card.grid(row=0, column=0, sticky="nsew", padx=(0, 8))
|
||||||
|
auth.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
|
ttk.Label(auth, text="API Token", style="CardLabel.TLabel").grid(row=0, column=0, sticky="w", padx=(0, 8))
|
||||||
|
self.token_entry = ttk.Entry(auth, textvariable=self.token_var, show="*")
|
||||||
self.token_entry.grid(row=0, column=1, sticky="ew", padx=(0, 8))
|
self.token_entry.grid(row=0, column=1, sticky="ew", padx=(0, 8))
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
token_frame,
|
auth,
|
||||||
text="Token anzeigen",
|
text="anzeigen",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.show_token_var,
|
variable=self.show_token_var,
|
||||||
command=self._toggle_token_visibility,
|
command=self._toggle_token_visibility,
|
||||||
).grid(row=0, column=2, sticky="w")
|
).grid(row=0, column=2, sticky="w")
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
token_frame,
|
auth,
|
||||||
text="Token lokal speichern",
|
text="Token lokal speichern",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.remember_token_var,
|
variable=self.remember_token_var,
|
||||||
).grid(row=1, column=1, sticky="w", pady=(8, 0))
|
).grid(row=1, column=1, sticky="w", pady=(8, 0))
|
||||||
ttk.Label(token_frame, text="GitHub Repo (owner/name):").grid(row=2, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
ttk.Label(auth, text="GitHub Repo", style="CardLabel.TLabel").grid(row=2, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
||||||
ttk.Entry(token_frame, textvariable=self.update_repo_var).grid(row=2, column=1, sticky="ew", padx=(0, 8), pady=(8, 0))
|
ttk.Entry(auth, textvariable=self.update_repo_var).grid(row=2, column=1, sticky="ew", padx=(0, 8), pady=(8, 0))
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
token_frame,
|
auth,
|
||||||
text="Beim Start auf Updates prüfen",
|
text="Beim Start auf Updates prüfen",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.auto_update_check_var,
|
variable=self.auto_update_check_var,
|
||||||
).grid(row=3, column=1, sticky="w", pady=(6, 0))
|
).grid(row=3, column=1, sticky="w", pady=(8, 0))
|
||||||
|
|
||||||
output_frame = ttk.LabelFrame(collector_tab, text="Paketierung & Zielpfade", padding=10)
|
path_card, path = self._create_card(
|
||||||
output_frame.grid(row=1, column=0, sticky="ew", pady=(10, 0))
|
collector_top,
|
||||||
output_frame.columnconfigure(1, weight=1)
|
"Paketierung & Zielpfade",
|
||||||
|
"Ordner, Entpacken und Paketoptionen",
|
||||||
ttk.Label(output_frame, text="Download-Ordner:").grid(row=0, column=0, sticky="w", padx=(0, 8))
|
)
|
||||||
ttk.Entry(output_frame, textvariable=self.output_dir_var).grid(row=0, column=1, sticky="ew", padx=(0, 8))
|
path_card.grid(row=0, column=1, sticky="nsew", padx=(8, 0))
|
||||||
ttk.Button(output_frame, text="Ordner wählen", command=self._browse_output_dir).grid(row=0, column=2)
|
path.columnconfigure(1, weight=1)
|
||||||
ttk.Label(output_frame, text="Paketname (optional):").grid(row=1, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
|
||||||
ttk.Entry(output_frame, textvariable=self.package_name_var).grid(row=1, column=1, columnspan=2, sticky="ew", pady=(8, 0))
|
|
||||||
|
|
||||||
|
ttk.Label(path, text="Download-Ordner", style="CardLabel.TLabel").grid(row=0, column=0, sticky="w", padx=(0, 8))
|
||||||
|
ttk.Entry(path, textvariable=self.output_dir_var).grid(row=0, column=1, sticky="ew", padx=(0, 8))
|
||||||
|
ttk.Button(path, text="Wählen", style="Ghost.TButton", command=self._browse_output_dir).grid(row=0, column=2, sticky="w")
|
||||||
|
ttk.Label(path, text="Paketname", style="CardLabel.TLabel").grid(row=1, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
||||||
|
ttk.Entry(path, textvariable=self.package_name_var).grid(row=1, column=1, columnspan=2, sticky="ew", pady=(8, 0))
|
||||||
|
ttk.Label(path, text="Entpacken nach", style="CardLabel.TLabel").grid(row=2, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
||||||
|
ttk.Entry(path, textvariable=self.extract_dir_var).grid(row=2, column=1, sticky="ew", padx=(0, 8), pady=(8, 0))
|
||||||
|
ttk.Button(path, text="Wählen", style="Ghost.TButton", command=self._browse_extract_dir).grid(row=2, column=2, sticky="w", pady=(8, 0))
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
output_frame,
|
path,
|
||||||
text="Nach Download automatisch entpacken",
|
text="Nach Download automatisch entpacken",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.auto_extract_var,
|
variable=self.auto_extract_var,
|
||||||
).grid(row=2, column=0, columnspan=3, sticky="w", pady=(8, 0))
|
).grid(row=3, column=0, columnspan=3, sticky="w", pady=(8, 0))
|
||||||
ttk.Label(output_frame, text="Entpacken nach:").grid(row=3, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
|
||||||
ttk.Entry(output_frame, textvariable=self.extract_dir_var).grid(row=3, column=1, sticky="ew", padx=(0, 8), pady=(8, 0))
|
|
||||||
ttk.Button(output_frame, text="Ordner wählen", command=self._browse_extract_dir).grid(row=3, column=2, pady=(8, 0))
|
|
||||||
|
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
output_frame,
|
path,
|
||||||
text="Unterordner erstellen (Paketname)",
|
text="Unterordner erstellen (Paketname)",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.create_extract_subfolder_var,
|
variable=self.create_extract_subfolder_var,
|
||||||
).grid(row=4, column=0, columnspan=3, sticky="w", pady=(6, 0))
|
).grid(row=4, column=0, columnspan=3, sticky="w", pady=(6, 0))
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
output_frame,
|
path,
|
||||||
text="Hybrid-Entpacken (sobald Parts komplett)",
|
text="Hybrid-Entpacken sobald Parts komplett",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.hybrid_extract_var,
|
variable=self.hybrid_extract_var,
|
||||||
).grid(row=5, column=0, columnspan=3, sticky="w", pady=(6, 0))
|
).grid(row=5, column=0, columnspan=3, sticky="w", pady=(6, 0))
|
||||||
ttk.Label(output_frame, text="Auto-Passwörter: serienfans.org, serienjunkies.net").grid(
|
ttk.Label(path, text="Auto-Passwörter: serienfans.org, serienjunkies.net", style="CardSub.TLabel").grid(
|
||||||
row=6,
|
row=6,
|
||||||
column=0,
|
column=0,
|
||||||
columnspan=3,
|
columnspan=3,
|
||||||
sticky="w",
|
sticky="w",
|
||||||
pady=(6, 0),
|
pady=(8, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
links_frame = ttk.LabelFrame(collector_tab, text="Linksammler (ein Link pro Zeile)", padding=10)
|
links_card, links_body = self._create_card(
|
||||||
links_frame.grid(row=2, column=0, sticky="nsew", pady=(10, 0))
|
collector_tab,
|
||||||
links_frame.columnconfigure(0, weight=1)
|
"Linksammler",
|
||||||
links_frame.rowconfigure(1, weight=1)
|
"Container und Direktlinks prüfen, sammeln und in die Queue übernehmen",
|
||||||
|
)
|
||||||
|
links_card.grid(row=1, column=0, sticky="nsew", pady=(10, 0))
|
||||||
|
links_body.columnconfigure(0, weight=1)
|
||||||
|
links_body.rowconfigure(1, weight=1)
|
||||||
|
|
||||||
links_actions = ttk.Frame(links_frame)
|
links_actions = ttk.Frame(links_body, style="Card.TFrame")
|
||||||
links_actions.grid(row=0, column=0, columnspan=2, sticky="ew", pady=(0, 8))
|
links_actions.grid(row=0, column=0, sticky="ew", pady=(0, 8))
|
||||||
ttk.Button(links_actions, text="Links laden", command=self._load_links_from_file).pack(side="left")
|
ttk.Button(links_actions, text="Links laden", style="Ghost.TButton", command=self._load_links_from_file).pack(side="left")
|
||||||
ttk.Button(links_actions, text="DLC import", command=self._import_dlc_file).pack(side="left", padx=(8, 0))
|
ttk.Button(links_actions, text="DLC import", style="Ghost.TButton", command=self._import_dlc_file).pack(side="left", padx=(8, 0))
|
||||||
ttk.Button(links_actions, text="Links speichern", command=self._save_links_to_file).pack(side="left", padx=(8, 0))
|
ttk.Button(links_actions, text="Speichern", style="Ghost.TButton", command=self._save_links_to_file).pack(side="left", padx=(8, 0))
|
||||||
ttk.Button(links_actions, text="Links leeren", command=self._clear_links).pack(side="left", padx=(8, 0))
|
ttk.Button(links_actions, text="Leeren", style="Ghost.TButton", command=self._clear_links).pack(side="left", padx=(8, 0))
|
||||||
ttk.Label(links_actions, text="Tipp: .dlc per Drag-and-Drop in dieses Feld").pack(side="right")
|
ttk.Label(links_actions, text=".dlc direkt hier droppen", style="CardSub.TLabel").pack(side="right")
|
||||||
|
|
||||||
self.links_text = tk.Text(links_frame, height=18, wrap="none", bg="#1e2329", fg="#e8edf4", insertbackground="#e8edf4")
|
self.links_text = tk.Text(
|
||||||
|
links_body,
|
||||||
|
height=18,
|
||||||
|
wrap="none",
|
||||||
|
bg="#0b1526",
|
||||||
|
fg="#e2e8f0",
|
||||||
|
insertbackground="#e2e8f0",
|
||||||
|
relief="flat",
|
||||||
|
padx=10,
|
||||||
|
pady=10,
|
||||||
|
highlightthickness=1,
|
||||||
|
highlightbackground="#253349",
|
||||||
|
highlightcolor="#253349",
|
||||||
|
)
|
||||||
self.links_text.grid(row=1, column=0, sticky="nsew")
|
self.links_text.grid(row=1, column=0, sticky="nsew")
|
||||||
links_scroll = ttk.Scrollbar(links_frame, orient="vertical", command=self.links_text.yview)
|
links_scroll = ttk.Scrollbar(links_body, orient="vertical", command=self.links_text.yview)
|
||||||
links_scroll.grid(row=1, column=1, sticky="ns")
|
links_scroll.grid(row=1, column=1, sticky="ns")
|
||||||
self.links_text.configure(yscrollcommand=links_scroll.set)
|
self.links_text.configure(yscrollcommand=links_scroll.set)
|
||||||
self._setup_dlc_drag_and_drop()
|
self._setup_dlc_drag_and_drop()
|
||||||
@ -782,28 +837,32 @@ class DownloaderApp(TkBase):
|
|||||||
downloads_tab.columnconfigure(0, weight=1)
|
downloads_tab.columnconfigure(0, weight=1)
|
||||||
downloads_tab.rowconfigure(0, weight=1)
|
downloads_tab.rowconfigure(0, weight=1)
|
||||||
|
|
||||||
table_frame = ttk.LabelFrame(downloads_tab, text="Downloads", padding=10)
|
downloads_card, downloads_body = self._create_card(
|
||||||
table_frame.grid(row=0, column=0, sticky="nsew")
|
downloads_tab,
|
||||||
table_frame.columnconfigure(0, weight=1)
|
"Downloads",
|
||||||
table_frame.rowconfigure(0, weight=1)
|
"Paket-Tree mit Download-, Entpack- und Integritätsstatus",
|
||||||
|
)
|
||||||
|
downloads_card.grid(row=0, column=0, sticky="nsew")
|
||||||
|
downloads_body.columnconfigure(0, weight=1)
|
||||||
|
downloads_body.rowconfigure(0, weight=1)
|
||||||
|
|
||||||
columns = ("file", "status", "progress", "speed", "retries")
|
columns = ("file", "status", "progress", "speed", "retries")
|
||||||
self.table = ttk.Treeview(table_frame, columns=columns, show="tree headings")
|
self.table = ttk.Treeview(downloads_body, columns=columns, show="tree headings")
|
||||||
self.table.heading("#0", text="Paket / Datei")
|
self.table.heading("#0", text="Paket / Datei")
|
||||||
self.table.heading("file", text="Datei")
|
self.table.heading("file", text="Datei")
|
||||||
self.table.heading("status", text="Status")
|
self.table.heading("status", text="Status")
|
||||||
self.table.heading("progress", text="Fortschritt")
|
self.table.heading("progress", text="Fortschritt")
|
||||||
self.table.heading("speed", text="Speed")
|
self.table.heading("speed", text="Speed")
|
||||||
self.table.heading("retries", text="Retries")
|
self.table.heading("retries", text="Retries")
|
||||||
self.table.column("#0", width=380, anchor="w")
|
self.table.column("#0", width=340, anchor="w")
|
||||||
self.table.column("file", width=260, anchor="w")
|
self.table.column("file", width=250, anchor="w")
|
||||||
self.table.column("status", width=260, anchor="w")
|
self.table.column("status", width=260, anchor="w")
|
||||||
self.table.column("progress", width=100, anchor="center")
|
self.table.column("progress", width=100, anchor="center")
|
||||||
self.table.column("speed", width=100, anchor="center")
|
self.table.column("speed", width=110, anchor="center")
|
||||||
self.table.column("retries", width=80, anchor="center")
|
self.table.column("retries", width=85, anchor="center")
|
||||||
self.table.grid(row=0, column=0, sticky="nsew")
|
self.table.grid(row=0, column=0, sticky="nsew")
|
||||||
|
|
||||||
table_scroll = ttk.Scrollbar(table_frame, orient="vertical", command=self.table.yview)
|
table_scroll = ttk.Scrollbar(downloads_body, orient="vertical", command=self.table.yview)
|
||||||
table_scroll.grid(row=0, column=1, sticky="ns")
|
table_scroll.grid(row=0, column=1, sticky="ns")
|
||||||
self.table.configure(yscrollcommand=table_scroll.set)
|
self.table.configure(yscrollcommand=table_scroll.set)
|
||||||
self.table.bind("<Delete>", self._on_table_delete_key)
|
self.table.bind("<Delete>", self._on_table_delete_key)
|
||||||
@ -818,15 +877,33 @@ class DownloaderApp(TkBase):
|
|||||||
self.table_context_menu.add_command(label="Links komplett leeren", command=self._clear_links)
|
self.table_context_menu.add_command(label="Links komplett leeren", command=self._clear_links)
|
||||||
self.table_context_menu.add_command(label="Alles leeren", command=self._clear_all_lists)
|
self.table_context_menu.add_command(label="Alles leeren", command=self._clear_all_lists)
|
||||||
|
|
||||||
footer = ttk.Frame(downloads_tab)
|
footer = ttk.Frame(downloads_body, style="Card.TFrame")
|
||||||
footer.grid(row=1, column=0, sticky="ew", pady=(8, 0))
|
footer.grid(row=1, column=0, columnspan=2, sticky="ew", pady=(10, 0))
|
||||||
footer.columnconfigure(0, weight=1)
|
footer.columnconfigure(0, weight=1)
|
||||||
ttk.Progressbar(footer, variable=self.overall_progress_var, maximum=100, mode="determinate").grid(row=0, column=0, sticky="ew")
|
ttk.Progressbar(footer, variable=self.overall_progress_var, maximum=100, mode="determinate").grid(
|
||||||
ttk.Label(footer, textvariable=self.status_var).grid(row=1, column=0, sticky="w", pady=(5, 0))
|
row=0,
|
||||||
|
column=0,
|
||||||
|
sticky="ew",
|
||||||
|
)
|
||||||
|
ttk.Label(footer, textvariable=self.status_var, style="CardSub.TLabel").grid(row=1, column=0, sticky="w", pady=(6, 0))
|
||||||
|
|
||||||
self._build_settings_tab(settings_tab)
|
self._build_settings_tab(settings_tab)
|
||||||
self._on_speed_limit_enabled_toggle()
|
self._on_speed_limit_enabled_toggle()
|
||||||
|
|
||||||
|
def _create_card(self, parent: ttk.Widget, title: str, subtitle: str = "") -> tuple[ttk.Frame, ttk.Frame]:
|
||||||
|
card = ttk.Frame(parent, style="Card.TFrame", padding=(14, 12))
|
||||||
|
card.columnconfigure(0, weight=1)
|
||||||
|
ttk.Label(card, text=title, style="CardTitle.TLabel").grid(row=0, column=0, sticky="w")
|
||||||
|
if subtitle:
|
||||||
|
ttk.Label(card, text=subtitle, style="CardSub.TLabel").grid(row=1, column=0, sticky="w", pady=(2, 0))
|
||||||
|
body_row = 2
|
||||||
|
else:
|
||||||
|
body_row = 1
|
||||||
|
|
||||||
|
body = ttk.Frame(card, style="Card.TFrame")
|
||||||
|
body.grid(row=body_row, column=0, sticky="nsew", pady=(10, 0))
|
||||||
|
return card, body
|
||||||
|
|
||||||
def _configure_modern_theme(self) -> None:
|
def _configure_modern_theme(self) -> None:
|
||||||
style = ttk.Style(self)
|
style = ttk.Style(self)
|
||||||
try:
|
try:
|
||||||
@ -834,98 +911,288 @@ class DownloaderApp(TkBase):
|
|||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
bg = "#0f141b"
|
bg = "#070b14"
|
||||||
card = "#1a212c"
|
surface = "#0e1626"
|
||||||
fg = "#e6edf3"
|
card = "#111d31"
|
||||||
sub = "#b7c3d0"
|
field = "#081120"
|
||||||
accent = "#2f81f7"
|
fg = "#e2e8f0"
|
||||||
|
muted = "#8fa1b8"
|
||||||
|
border = "#24364f"
|
||||||
|
accent = "#38bdf8"
|
||||||
|
accent_hover = "#60d3ff"
|
||||||
|
accent_press = "#27a7de"
|
||||||
|
|
||||||
|
font_base = ("Segoe UI", 10)
|
||||||
|
self.option_add("*Font", "{Segoe UI} 10")
|
||||||
self.configure(bg=bg)
|
self.configure(bg=bg)
|
||||||
|
|
||||||
|
style.configure(".", font=font_base)
|
||||||
|
style.configure("App.TFrame", background=bg)
|
||||||
|
style.configure("Surface.TFrame", background=surface)
|
||||||
|
style.configure("Card.TFrame", background=card)
|
||||||
style.configure("TFrame", background=bg)
|
style.configure("TFrame", background=bg)
|
||||||
style.configure("TLabelframe", background=card, foreground=fg)
|
|
||||||
style.configure("TLabelframe.Label", background=card, foreground=fg)
|
style.configure("HeaderTitle.TLabel", background=bg, foreground=fg, font=("Segoe UI Semibold", 17))
|
||||||
|
style.configure("HeaderMeta.TLabel", background=bg, foreground=muted, font=("Segoe UI", 10))
|
||||||
|
style.configure("HeaderValue.TLabel", background=bg, foreground=fg, font=("Segoe UI Semibold", 10))
|
||||||
|
|
||||||
|
style.configure("Surface.TLabel", background=surface, foreground=fg)
|
||||||
|
style.configure("CardTitle.TLabel", background=card, foreground=fg, font=("Segoe UI Semibold", 11))
|
||||||
|
style.configure("CardSub.TLabel", background=card, foreground=muted, font=("Segoe UI", 9))
|
||||||
|
style.configure("CardLabel.TLabel", background=card, foreground=muted, font=("Segoe UI", 9))
|
||||||
style.configure("TLabel", background=bg, foreground=fg)
|
style.configure("TLabel", background=bg, foreground=fg)
|
||||||
style.configure("TButton", background=card, foreground=fg, borderwidth=0, padding=(10, 6))
|
|
||||||
style.map("TButton", background=[("active", accent), ("pressed", accent)])
|
style.configure(
|
||||||
|
"TButton",
|
||||||
|
background=surface,
|
||||||
|
foreground=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
relief="flat",
|
||||||
|
borderwidth=1,
|
||||||
|
focusthickness=0,
|
||||||
|
padding=(11, 7),
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"TButton",
|
||||||
|
background=[("active", "#17263c"), ("pressed", "#162338")],
|
||||||
|
bordercolor=[("active", accent)],
|
||||||
|
)
|
||||||
|
|
||||||
|
style.configure(
|
||||||
|
"Ghost.TButton",
|
||||||
|
background=surface,
|
||||||
|
foreground=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
relief="flat",
|
||||||
|
borderwidth=1,
|
||||||
|
focusthickness=0,
|
||||||
|
padding=(11, 7),
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"Ghost.TButton",
|
||||||
|
background=[("active", "#17263c"), ("pressed", "#162338")],
|
||||||
|
bordercolor=[("active", accent)],
|
||||||
|
)
|
||||||
|
|
||||||
|
style.configure(
|
||||||
|
"Accent.TButton",
|
||||||
|
background=accent,
|
||||||
|
foreground="#041018",
|
||||||
|
bordercolor=accent,
|
||||||
|
relief="flat",
|
||||||
|
borderwidth=1,
|
||||||
|
focusthickness=0,
|
||||||
|
padding=(12, 7),
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"Accent.TButton",
|
||||||
|
background=[("active", accent_hover), ("pressed", accent_press), ("disabled", "#334155")],
|
||||||
|
foreground=[("disabled", "#8b9fb5")],
|
||||||
|
bordercolor=[("active", accent_hover), ("pressed", accent_press)],
|
||||||
|
)
|
||||||
|
|
||||||
style.configure("TCheckbutton", background=bg, foreground=fg)
|
style.configure("TCheckbutton", background=bg, foreground=fg)
|
||||||
|
style.map("TCheckbutton", foreground=[("disabled", muted)])
|
||||||
|
style.configure("Surface.TCheckbutton", background=surface, foreground=fg)
|
||||||
|
style.configure("Card.TCheckbutton", background=card, foreground=fg)
|
||||||
|
style.map("Card.TCheckbutton", foreground=[("disabled", muted)], background=[("active", card)])
|
||||||
|
style.map("Surface.TCheckbutton", foreground=[("disabled", muted)], background=[("active", surface)])
|
||||||
|
|
||||||
|
style.configure(
|
||||||
|
"TEntry",
|
||||||
|
fieldbackground=field,
|
||||||
|
foreground=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
lightcolor=border,
|
||||||
|
darkcolor=border,
|
||||||
|
insertcolor=fg,
|
||||||
|
relief="flat",
|
||||||
|
padding=6,
|
||||||
|
)
|
||||||
|
style.configure(
|
||||||
|
"TCombobox",
|
||||||
|
fieldbackground=field,
|
||||||
|
foreground=fg,
|
||||||
|
background=field,
|
||||||
|
arrowcolor=muted,
|
||||||
|
bordercolor=border,
|
||||||
|
lightcolor=border,
|
||||||
|
darkcolor=border,
|
||||||
|
relief="flat",
|
||||||
|
padding=5,
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"TCombobox",
|
||||||
|
fieldbackground=[("readonly", field)],
|
||||||
|
foreground=[("readonly", fg)],
|
||||||
|
selectbackground=[("readonly", field)],
|
||||||
|
selectforeground=[("readonly", fg)],
|
||||||
|
)
|
||||||
|
style.configure(
|
||||||
|
"TSpinbox",
|
||||||
|
fieldbackground=field,
|
||||||
|
foreground=fg,
|
||||||
|
background=field,
|
||||||
|
arrowcolor=muted,
|
||||||
|
bordercolor=border,
|
||||||
|
lightcolor=border,
|
||||||
|
darkcolor=border,
|
||||||
|
relief="flat",
|
||||||
|
padding=5,
|
||||||
|
)
|
||||||
|
|
||||||
style.configure("TNotebook", background=bg, borderwidth=0)
|
style.configure("TNotebook", background=bg, borderwidth=0)
|
||||||
style.configure("TNotebook.Tab", background=card, foreground=sub, padding=(14, 7))
|
style.configure("TNotebook.Tab", background=surface, foreground=muted, padding=(16, 8), borderwidth=0)
|
||||||
style.map("TNotebook.Tab", background=[("selected", "#243041")], foreground=[("selected", fg)])
|
style.map(
|
||||||
style.configure("Treeview", background=card, fieldbackground=card, foreground=fg, rowheight=24)
|
"TNotebook.Tab",
|
||||||
style.configure("Treeview.Heading", background="#243041", foreground=fg)
|
background=[("selected", card), ("active", "#15243a")],
|
||||||
|
foreground=[("selected", fg), ("active", fg)],
|
||||||
|
)
|
||||||
|
|
||||||
|
style.configure(
|
||||||
|
"Treeview",
|
||||||
|
background=field,
|
||||||
|
fieldbackground=field,
|
||||||
|
foreground=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
lightcolor=border,
|
||||||
|
darkcolor=border,
|
||||||
|
rowheight=26,
|
||||||
|
)
|
||||||
|
style.configure("Treeview.Heading", background=surface, foreground=muted, relief="flat")
|
||||||
|
style.map(
|
||||||
|
"Treeview",
|
||||||
|
background=[("selected", "#1d4ed8")],
|
||||||
|
foreground=[("selected", "#f8fafc")],
|
||||||
|
)
|
||||||
|
style.map(
|
||||||
|
"Treeview.Heading",
|
||||||
|
background=[("active", "#17263c")],
|
||||||
|
foreground=[("active", fg)],
|
||||||
|
)
|
||||||
|
|
||||||
|
style.configure(
|
||||||
|
"Horizontal.TProgressbar",
|
||||||
|
troughcolor="#0b1524",
|
||||||
|
background=accent,
|
||||||
|
bordercolor="#0b1524",
|
||||||
|
lightcolor=accent,
|
||||||
|
darkcolor=accent,
|
||||||
|
)
|
||||||
|
|
||||||
def _build_settings_tab(self, parent: ttk.Frame) -> None:
|
def _build_settings_tab(self, parent: ttk.Frame) -> None:
|
||||||
parent.columnconfigure(0, weight=1)
|
parent.columnconfigure(0, weight=1)
|
||||||
|
|
||||||
queue_box = ttk.LabelFrame(parent, text="Queue & Reconnect", padding=10)
|
reconnect_card, reconnect = self._create_card(
|
||||||
queue_box.grid(row=0, column=0, sticky="ew")
|
parent,
|
||||||
queue_box.columnconfigure(1, weight=1)
|
"Queue & Reconnect",
|
||||||
|
"Parallele Downloads und IP-Limit-Strategie",
|
||||||
|
)
|
||||||
|
reconnect_card.grid(row=0, column=0, sticky="ew")
|
||||||
|
reconnect.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
ttk.Label(queue_box, text="Max. gleichzeitige Downloads:").grid(row=0, column=0, sticky="w", padx=(0, 8))
|
ttk.Label(reconnect, text="Max. gleichzeitige Downloads", style="CardLabel.TLabel").grid(
|
||||||
ttk.Spinbox(queue_box, from_=1, to=50, width=6, textvariable=self.max_parallel_var).grid(row=0, column=1, sticky="w")
|
row=0,
|
||||||
|
column=0,
|
||||||
|
sticky="w",
|
||||||
|
padx=(0, 8),
|
||||||
|
)
|
||||||
|
ttk.Spinbox(reconnect, from_=1, to=50, width=7, textvariable=self.max_parallel_var).grid(row=0, column=1, sticky="w")
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
queue_box,
|
reconnect,
|
||||||
text="Automatischer Reconnect aktiv",
|
text="Automatischer Reconnect aktiv",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.auto_reconnect_var,
|
variable=self.auto_reconnect_var,
|
||||||
).grid(row=1, column=0, columnspan=2, sticky="w", pady=(8, 0))
|
).grid(row=1, column=0, columnspan=2, sticky="w", pady=(8, 0))
|
||||||
ttk.Label(queue_box, text="Reconnect-Wartezeit (Sek.):").grid(row=2, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
ttk.Label(reconnect, text="Reconnect-Wartezeit (Sek.)", style="CardLabel.TLabel").grid(
|
||||||
ttk.Spinbox(queue_box, from_=10, to=600, width=8, textvariable=self.reconnect_wait_seconds_var).grid(
|
row=2,
|
||||||
|
column=0,
|
||||||
|
sticky="w",
|
||||||
|
padx=(0, 8),
|
||||||
|
pady=(8, 0),
|
||||||
|
)
|
||||||
|
ttk.Spinbox(reconnect, from_=10, to=600, width=9, textvariable=self.reconnect_wait_seconds_var).grid(
|
||||||
row=2,
|
row=2,
|
||||||
column=1,
|
column=1,
|
||||||
sticky="w",
|
sticky="w",
|
||||||
pady=(8, 0),
|
pady=(8, 0),
|
||||||
)
|
)
|
||||||
|
|
||||||
resume_box = ttk.LabelFrame(parent, text="Session & Persistenz", padding=10)
|
session_card, session = self._create_card(
|
||||||
resume_box.grid(row=1, column=0, sticky="ew", pady=(10, 0))
|
parent,
|
||||||
resume_box.columnconfigure(1, weight=1)
|
"Session & Persistenz",
|
||||||
|
"Automatisches Fortsetzen und Bereinigung fertiger Tasks",
|
||||||
|
)
|
||||||
|
session_card.grid(row=1, column=0, sticky="ew", pady=(10, 0))
|
||||||
|
session.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
resume_box,
|
session,
|
||||||
text="Downloads beim Start automatisch fortsetzen",
|
text="Downloads beim Start automatisch fortsetzen",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.auto_resume_on_start_var,
|
variable=self.auto_resume_on_start_var,
|
||||||
).grid(row=0, column=0, columnspan=2, sticky="w")
|
).grid(row=0, column=0, columnspan=2, sticky="w")
|
||||||
|
|
||||||
ttk.Label(resume_box, text="Fertiggestellte Downloads entfernen:").grid(row=1, column=0, sticky="w", pady=(8, 0), padx=(0, 8))
|
|
||||||
cleanup_label_var = tk.StringVar(
|
cleanup_label_var = tk.StringVar(
|
||||||
value=self._finished_cleanup_label(self._normalize_finished_cleanup_policy(self.completed_cleanup_policy_var.get()))
|
value=self._finished_cleanup_label(self._normalize_finished_cleanup_policy(self.completed_cleanup_policy_var.get()))
|
||||||
)
|
)
|
||||||
cleanup_combo = ttk.Combobox(
|
ttk.Label(session, text="Fertiggestellte Downloads entfernen", style="CardLabel.TLabel").grid(
|
||||||
resume_box,
|
row=1,
|
||||||
|
column=0,
|
||||||
|
sticky="w",
|
||||||
|
pady=(8, 0),
|
||||||
|
padx=(0, 8),
|
||||||
|
)
|
||||||
|
ttk.Combobox(
|
||||||
|
session,
|
||||||
textvariable=cleanup_label_var,
|
textvariable=cleanup_label_var,
|
||||||
values=tuple(FINISHED_TASK_CLEANUP_LABELS.values()),
|
values=tuple(FINISHED_TASK_CLEANUP_LABELS.values()),
|
||||||
state="readonly",
|
state="readonly",
|
||||||
width=28,
|
width=30,
|
||||||
)
|
).grid(row=1, column=1, sticky="w", pady=(8, 0))
|
||||||
cleanup_combo.grid(row=1, column=1, sticky="w", pady=(8, 0))
|
|
||||||
|
|
||||||
integrity_box = ttk.LabelFrame(parent, text="Integrität & Aufräumen", padding=10)
|
integrity_card, integrity = self._create_card(
|
||||||
integrity_box.grid(row=2, column=0, sticky="ew", pady=(10, 0))
|
parent,
|
||||||
integrity_box.columnconfigure(0, weight=1)
|
"Integrität & Cleanup",
|
||||||
|
"Datei-Prüfung und post-processing Verhalten",
|
||||||
|
)
|
||||||
|
integrity_card.grid(row=2, column=0, sticky="ew", pady=(10, 0))
|
||||||
|
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
integrity_box,
|
integrity,
|
||||||
text="Datei-Integrität (SFV/CRC/MD5/SHA1) nach Download prüfen",
|
text="Integritätsprüfung (SFV/CRC/MD5/SHA1) nach Download",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.enable_integrity_check_var,
|
variable=self.enable_integrity_check_var,
|
||||||
).grid(row=0, column=0, sticky="w")
|
).grid(row=0, column=0, sticky="w")
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
integrity_box,
|
integrity,
|
||||||
text="Downloadlinks in Archiven nach erfolgreichem Entpacken entfernen",
|
text="Downloadlink-Dateien nach Entpacken entfernen",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.remove_link_files_after_extract_var,
|
variable=self.remove_link_files_after_extract_var,
|
||||||
).grid(row=1, column=0, sticky="w", pady=(6, 0))
|
).grid(row=1, column=0, sticky="w", pady=(6, 0))
|
||||||
ttk.Checkbutton(
|
ttk.Checkbutton(
|
||||||
integrity_box,
|
integrity,
|
||||||
text="Sample-Dateien/-Ordner nach dem Entpacken entfernen",
|
text="Sample-Dateien/-Ordner nach Entpacken entfernen",
|
||||||
|
style="Card.TCheckbutton",
|
||||||
variable=self.remove_samples_var,
|
variable=self.remove_samples_var,
|
||||||
).grid(row=2, column=0, sticky="w", pady=(6, 0))
|
).grid(row=2, column=0, sticky="w", pady=(6, 0))
|
||||||
|
|
||||||
extract_box = ttk.LabelFrame(parent, text="Entpacken", padding=10)
|
extract_card, extract = self._create_card(
|
||||||
extract_box.grid(row=3, column=0, sticky="ew", pady=(10, 0))
|
parent,
|
||||||
extract_box.columnconfigure(1, weight=1)
|
"Entpacken",
|
||||||
|
"Konflikt- und Cleanup-Verhalten für Archive",
|
||||||
|
)
|
||||||
|
extract_card.grid(row=3, column=0, sticky="ew", pady=(10, 0))
|
||||||
|
extract.columnconfigure(1, weight=1)
|
||||||
|
|
||||||
ttk.Label(extract_box, text="Nach erfolgreichem Entpacken:").grid(row=0, column=0, sticky="w", padx=(0, 8))
|
ttk.Label(extract, text="Nach erfolgreichem Entpacken", style="CardLabel.TLabel").grid(
|
||||||
|
row=0,
|
||||||
|
column=0,
|
||||||
|
sticky="w",
|
||||||
|
padx=(0, 8),
|
||||||
|
)
|
||||||
self.cleanup_combo_settings_tab = ttk.Combobox(
|
self.cleanup_combo_settings_tab = ttk.Combobox(
|
||||||
extract_box,
|
extract,
|
||||||
values=tuple(CLEANUP_LABELS.values()),
|
values=tuple(CLEANUP_LABELS.values()),
|
||||||
state="readonly",
|
state="readonly",
|
||||||
width=42,
|
width=42,
|
||||||
@ -933,9 +1200,15 @@ class DownloaderApp(TkBase):
|
|||||||
self.cleanup_combo_settings_tab.set(self._cleanup_label(self._normalize_cleanup_mode(self.cleanup_mode_var.get())))
|
self.cleanup_combo_settings_tab.set(self._cleanup_label(self._normalize_cleanup_mode(self.cleanup_mode_var.get())))
|
||||||
self.cleanup_combo_settings_tab.grid(row=0, column=1, sticky="w")
|
self.cleanup_combo_settings_tab.grid(row=0, column=1, sticky="w")
|
||||||
|
|
||||||
ttk.Label(extract_box, text="Wenn Datei bereits existiert:").grid(row=1, column=0, sticky="w", padx=(0, 8), pady=(8, 0))
|
ttk.Label(extract, text="Wenn Datei bereits existiert", style="CardLabel.TLabel").grid(
|
||||||
|
row=1,
|
||||||
|
column=0,
|
||||||
|
sticky="w",
|
||||||
|
padx=(0, 8),
|
||||||
|
pady=(8, 0),
|
||||||
|
)
|
||||||
self.conflict_combo_settings_tab = ttk.Combobox(
|
self.conflict_combo_settings_tab = ttk.Combobox(
|
||||||
extract_box,
|
extract,
|
||||||
values=tuple(CONFLICT_LABELS.values()),
|
values=tuple(CONFLICT_LABELS.values()),
|
||||||
state="readonly",
|
state="readonly",
|
||||||
width=42,
|
width=42,
|
||||||
@ -943,7 +1216,7 @@ class DownloaderApp(TkBase):
|
|||||||
self.conflict_combo_settings_tab.set(self._conflict_label(self._normalize_extract_conflict_mode(self.extract_conflict_mode_var.get())))
|
self.conflict_combo_settings_tab.set(self._conflict_label(self._normalize_extract_conflict_mode(self.extract_conflict_mode_var.get())))
|
||||||
self.conflict_combo_settings_tab.grid(row=1, column=1, sticky="w", pady=(8, 0))
|
self.conflict_combo_settings_tab.grid(row=1, column=1, sticky="w", pady=(8, 0))
|
||||||
|
|
||||||
buttons = ttk.Frame(parent)
|
buttons = ttk.Frame(parent, style="App.TFrame")
|
||||||
buttons.grid(row=4, column=0, sticky="e", pady=(12, 0))
|
buttons.grid(row=4, column=0, sticky="e", pady=(12, 0))
|
||||||
|
|
||||||
def apply_settings() -> None:
|
def apply_settings() -> None:
|
||||||
@ -953,7 +1226,7 @@ class DownloaderApp(TkBase):
|
|||||||
self._save_config()
|
self._save_config()
|
||||||
self.status_var.set("Settings gespeichert")
|
self.status_var.set("Settings gespeichert")
|
||||||
|
|
||||||
ttk.Button(buttons, text="Speichern", command=apply_settings).pack(side="right")
|
ttk.Button(buttons, text="Settings speichern", style="Accent.TButton", command=apply_settings).pack(side="right")
|
||||||
|
|
||||||
def _on_speed_limit_enabled_toggle(self) -> None:
|
def _on_speed_limit_enabled_toggle(self) -> None:
|
||||||
enabled = bool(self.speed_limit_enabled_var.get())
|
enabled = bool(self.speed_limit_enabled_var.get())
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user