Implement dark mode theme (#744)
Co-authored-by: DevilXD <4180725+DevilXD@users.noreply.github.com>
This commit is contained in:
1 parent
f990437731
commit
2737936739
23 files changed
+265
-16
No files matched your search
@@ -3,12 +3,12 @@ name: Build
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- 'master'
|
- "master"
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: '3.10'
|
PYTHON_VERSION: "3.10"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
validate:
|
validate:
|
||||||
@@ -267,8 +267,14 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
path: artifacts
|
path: artifacts
|
||||||
|
|
||||||
- name: Delete the existing pre-release
|
- name: Delete the existing pre-release (if present)
|
||||||
run: gh release delete dev-build --cleanup-tag --yes --repo $GITHUB_REPOSITORY
|
run: |
|
||||||
|
TAG=dev-build
|
||||||
|
if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
|
||||||
|
gh release delete "$TAG" --cleanup-tag --yes --repo "$GITHUB_REPOSITORY"
|
||||||
|
else
|
||||||
|
echo "No $TAG release; skipping delete"
|
||||||
|
fi
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{github.token}}
|
GITHUB_TOKEN: ${{github.token}}
|
||||||
|
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ placed past the period character at the end.
|
|||||||
-->
|
-->
|
||||||
|
|
||||||
@guihkx - For the CI script, CI maintenance, and everything related to Linux builds.
|
@guihkx - For the CI script, CI maintenance, and everything related to Linux builds.
|
||||||
|
@kWAYTV - For the implementation of the dark mode theme.
|
||||||
|
|
||||||
@Bamboozul - For the entirety of the Arabic (العربية) translation.
|
@Bamboozul - For the entirety of the Arabic (العربية) translation.
|
||||||
@Suz1e - For the entirety of the Chinese (简体中文) translation and revisions.
|
@Suz1e - For the entirety of the Chinese (简体中文) translation and revisions.
|
||||||
|
|||||||
@@ -264,6 +264,10 @@ class PaddedListbox(tk.Listbox):
|
|||||||
# because 'config = configure' makes mypy complain
|
# because 'config = configure' makes mypy complain
|
||||||
self.configure(*args, **kwargs)
|
self.configure(*args, **kwargs)
|
||||||
|
|
||||||
|
def configure_theme(self, *, bg: str, fg: str, sel_bg: str, sel_fg: str):
|
||||||
|
# Apply basic colors for dark/light mode
|
||||||
|
super().config(bg=bg, fg=fg, selectbackground=sel_bg, selectforeground=sel_fg)
|
||||||
|
|
||||||
|
|
||||||
class MouseOverLabel(ttk.Label):
|
class MouseOverLabel(ttk.Label):
|
||||||
def __init__(self, *args, alt_text: str = '', reverse: bool = False, **kwargs) -> None:
|
def __init__(self, *args, alt_text: str = '', reverse: bool = False, **kwargs) -> None:
|
||||||
@@ -819,6 +823,16 @@ class ConsoleOutput:
|
|||||||
self._text.see("end") # scroll to the newly added line
|
self._text.see("end") # scroll to the newly added line
|
||||||
self._text.config(state="disabled")
|
self._text.config(state="disabled")
|
||||||
|
|
||||||
|
def configure_theme(self, *, bg: str, fg: str, sel_bg: str, sel_fg: str):
|
||||||
|
# Apply colors to the Tk Text widget used for console output
|
||||||
|
self._text.config(
|
||||||
|
bg=bg,
|
||||||
|
fg=fg,
|
||||||
|
insertbackground=fg,
|
||||||
|
selectbackground=sel_bg,
|
||||||
|
selectforeground=sel_fg,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class _Buttons(TypedDict):
|
class _Buttons(TypedDict):
|
||||||
frame: ttk.Frame
|
frame: ttk.Frame
|
||||||
@@ -1291,6 +1305,10 @@ class InventoryOverview:
|
|||||||
self._campaigns: dict[DropsCampaign, CampaignDisplay] = {}
|
self._campaigns: dict[DropsCampaign, CampaignDisplay] = {}
|
||||||
self._drops: dict[str, ttk.Label] = {}
|
self._drops: dict[str, ttk.Label] = {}
|
||||||
|
|
||||||
|
def configure_theme(self, *, bg: str):
|
||||||
|
# Canvas background needs manual control
|
||||||
|
self._canvas.configure(bg=bg)
|
||||||
|
|
||||||
def _update_visibility(self, campaign: DropsCampaign):
|
def _update_visibility(self, campaign: DropsCampaign):
|
||||||
# True if the campaign is supposed to show, False makes it hidden.
|
# True if the campaign is supposed to show, False makes it hidden.
|
||||||
frame = self._campaigns[campaign]["frame"]
|
frame = self._campaigns[campaign]["frame"]
|
||||||
@@ -1528,6 +1546,7 @@ class _SettingsVars(TypedDict):
|
|||||||
tray: IntVar
|
tray: IntVar
|
||||||
proxy: StringVar
|
proxy: StringVar
|
||||||
autostart: IntVar
|
autostart: IntVar
|
||||||
|
dark_mode: IntVar
|
||||||
language: StringVar
|
language: StringVar
|
||||||
priority_mode: StringVar
|
priority_mode: StringVar
|
||||||
tray_notifications: IntVar
|
tray_notifications: IntVar
|
||||||
@@ -1550,7 +1569,7 @@ class SettingsPanel:
|
|||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, manager: GUIManager, master: ttk.Widget):
|
def __init__(self, manager: GUIManager, master: ttk.Widget):
|
||||||
self._twitch = manager._twitch
|
self._manager = manager
|
||||||
self._settings: Settings = manager._twitch.settings
|
self._settings: Settings = manager._twitch.settings
|
||||||
priority_mode = self._settings.priority_mode
|
priority_mode = self._settings.priority_mode
|
||||||
if priority_mode not in self.PRIORITY_MODES:
|
if priority_mode not in self.PRIORITY_MODES:
|
||||||
@@ -1561,6 +1580,7 @@ class SettingsPanel:
|
|||||||
"language": StringVar(master, _.current),
|
"language": StringVar(master, _.current),
|
||||||
"proxy": StringVar(master, str(self._settings.proxy)),
|
"proxy": StringVar(master, str(self._settings.proxy)),
|
||||||
"tray": IntVar(master, self._settings.autostart_tray),
|
"tray": IntVar(master, self._settings.autostart_tray),
|
||||||
|
"dark_mode": IntVar(master, int(self._settings.dark_mode)),
|
||||||
"priority_mode": StringVar(master, self.PRIORITY_MODES[priority_mode]),
|
"priority_mode": StringVar(master, self.PRIORITY_MODES[priority_mode]),
|
||||||
"tray_notifications": IntVar(master, self._settings.tray_notifications),
|
"tray_notifications": IntVar(master, self._settings.tray_notifications),
|
||||||
}
|
}
|
||||||
@@ -1616,6 +1636,14 @@ class SettingsPanel:
|
|||||||
variable=self._vars["tray_notifications"],
|
variable=self._vars["tray_notifications"],
|
||||||
command=self.update_notifications,
|
command=self.update_notifications,
|
||||||
).grid(column=1, row=irow, sticky="w")
|
).grid(column=1, row=irow, sticky="w")
|
||||||
|
ttk.Label(
|
||||||
|
checkboxes_frame, text=_("gui", "settings", "general", "dark_mode")
|
||||||
|
).grid(column=0, row=(irow := irow + 1), sticky="e")
|
||||||
|
ttk.Checkbutton(
|
||||||
|
checkboxes_frame,
|
||||||
|
variable=self._vars["dark_mode"],
|
||||||
|
command=self.update_dark_mode,
|
||||||
|
).grid(column=1, row=irow, sticky="w")
|
||||||
ttk.Label(
|
ttk.Label(
|
||||||
checkboxes_frame, text=_("gui", "settings", "general", "priority_mode")
|
checkboxes_frame, text=_("gui", "settings", "general", "priority_mode")
|
||||||
).grid(column=0, row=(irow := irow + 1), sticky="e")
|
).grid(column=0, row=(irow := irow + 1), sticky="e")
|
||||||
@@ -1719,7 +1747,7 @@ class SettingsPanel:
|
|||||||
ttk.Button(
|
ttk.Button(
|
||||||
reload_frame,
|
reload_frame,
|
||||||
text=_("gui", "settings", "reload"),
|
text=_("gui", "settings", "reload"),
|
||||||
command=self._twitch.state_change(State.INVENTORY_FETCH),
|
command=self._manager._twitch.state_change(State.INVENTORY_FETCH),
|
||||||
).grid(column=1, row=0)
|
).grid(column=1, row=0)
|
||||||
|
|
||||||
self._vars["autostart"].set(self._query_autostart())
|
self._vars["autostart"].set(self._query_autostart())
|
||||||
@@ -1728,6 +1756,11 @@ class SettingsPanel:
|
|||||||
self._priority_list.selection_clear(0, "end")
|
self._priority_list.selection_clear(0, "end")
|
||||||
self._exclude_list.selection_clear(0, "end")
|
self._exclude_list.selection_clear(0, "end")
|
||||||
|
|
||||||
|
def update_dark_mode(self) -> None:
|
||||||
|
self._settings.dark_mode = bool(self._vars["dark_mode"].get())
|
||||||
|
self._settings.alter()
|
||||||
|
self._manager.apply_theme(self._settings.dark_mode)
|
||||||
|
|
||||||
def update_notifications(self) -> None:
|
def update_notifications(self) -> None:
|
||||||
self._settings.tray_notifications = bool(self._vars["tray_notifications"].get())
|
self._settings.tray_notifications = bool(self._vars["tray_notifications"].get())
|
||||||
|
|
||||||
@@ -2025,7 +2058,6 @@ class GUIManager:
|
|||||||
|
|
||||||
# style adjustements
|
# style adjustements
|
||||||
self._style = style = ttk.Style(root)
|
self._style = style = ttk.Style(root)
|
||||||
default_font = nametofont("TkDefaultFont")
|
|
||||||
# theme
|
# theme
|
||||||
theme = ''
|
theme = ''
|
||||||
# theme = style.theme_names()[6]
|
# theme = style.theme_names()[6]
|
||||||
@@ -2057,17 +2089,23 @@ class GUIManager:
|
|||||||
style.configure("green.TLabel", foreground="green")
|
style.configure("green.TLabel", foreground="green")
|
||||||
style.configure("yellow.TLabel", foreground="goldenrod")
|
style.configure("yellow.TLabel", foreground="goldenrod")
|
||||||
style.configure("red.TLabel", foreground="red")
|
style.configure("red.TLabel", foreground="red")
|
||||||
|
# fonts
|
||||||
|
default_font = nametofont("TkDefaultFont")
|
||||||
|
self._fonts: dict[str, Font] = {
|
||||||
|
"default": default_font,
|
||||||
|
"large": default_font.copy(),
|
||||||
|
"monospaced": default_font.copy(),
|
||||||
|
"underlined": default_font.copy(),
|
||||||
|
}
|
||||||
|
self._fonts["large"].config(size=10)
|
||||||
|
self._fonts["underlined"].config(underline=True)
|
||||||
|
self._fonts["monospaced"].config(family="Courier New", size=10)
|
||||||
# label style with a monospace font
|
# label style with a monospace font
|
||||||
monospaced_font = Font(root, family="Courier New", size=10)
|
style.configure("MS.TLabel", font=self._fonts["monospaced"])
|
||||||
style.configure("MS.TLabel", font=monospaced_font)
|
|
||||||
# button style with a larger font
|
# button style with a larger font
|
||||||
large_font = default_font.copy()
|
style.configure("Large.TButton", font=self._fonts["large"])
|
||||||
large_font.config(size=10)
|
|
||||||
style.configure("Large.TButton", font=large_font)
|
|
||||||
# label style that mimics links
|
# label style that mimics links
|
||||||
link_font = default_font.copy()
|
style.configure("Link.TLabel", font=self._fonts["underlined"], foreground="blue")
|
||||||
link_font.config(underline=True)
|
|
||||||
style.configure("Link.TLabel", font=link_font, foreground="blue")
|
|
||||||
# end of style changes
|
# end of style changes
|
||||||
|
|
||||||
root_frame = ttk.Frame(root, padding=8)
|
root_frame = ttk.Frame(root, padding=8)
|
||||||
@@ -2133,6 +2171,12 @@ class GUIManager:
|
|||||||
# use old-style window closing protocol for non-windows platforms
|
# use old-style window closing protocol for non-windows platforms
|
||||||
root.protocol("WM_DELETE_WINDOW", self.close)
|
root.protocol("WM_DELETE_WINDOW", self.close)
|
||||||
root.protocol("WM_DESTROY_WINDOW", self.close)
|
root.protocol("WM_DESTROY_WINDOW", self.close)
|
||||||
|
# Save current theme and apply palette after widgets are created
|
||||||
|
try:
|
||||||
|
self._orig_theme_name = self._style.theme_use()
|
||||||
|
except Exception:
|
||||||
|
self._orig_theme_name = ''
|
||||||
|
self.apply_theme(self._twitch.settings.dark_mode)
|
||||||
# stay hidden in tray if needed, otherwise show the window when everything's ready
|
# stay hidden in tray if needed, otherwise show the window when everything's ready
|
||||||
if self._twitch.settings.tray:
|
if self._twitch.settings.tray:
|
||||||
# NOTE: this starts the tray icon thread
|
# NOTE: this starts the tray icon thread
|
||||||
@@ -2277,6 +2321,179 @@ class GUIManager:
|
|||||||
# print to our custom output
|
# print to our custom output
|
||||||
self.output.print(message)
|
self.output.print(message)
|
||||||
|
|
||||||
|
def apply_theme(self, dark: bool) -> None:
|
||||||
|
"""
|
||||||
|
Apply dark/light palette to ttk styles and Tk widgets in a minimal, non-invasive way.
|
||||||
|
"""
|
||||||
|
# Palette
|
||||||
|
if dark:
|
||||||
|
# Switch to a configurable ttk theme for better color control
|
||||||
|
if self._style.theme_use() != "clam":
|
||||||
|
self._style.theme_use("clam")
|
||||||
|
bg = "#1e1e1e"
|
||||||
|
fg = "#e6e6e6"
|
||||||
|
sel_bg = "#094771"
|
||||||
|
sel_fg = "#ffffff"
|
||||||
|
link = "#4ea3ff"
|
||||||
|
surface = "#252525"
|
||||||
|
header = "#2a2a2a"
|
||||||
|
fieldbg = "#2b2b2b"
|
||||||
|
border = "#3c3c3c"
|
||||||
|
muted = "#b3b3b3"
|
||||||
|
accent = "#0d99ff"
|
||||||
|
else:
|
||||||
|
# Restore original theme if we changed it
|
||||||
|
if getattr(self, "_orig_theme_name", '') and self._style.theme_use() == "clam":
|
||||||
|
self._style.theme_use(self._orig_theme_name)
|
||||||
|
# Use platform defaults but ensure toggling back is readable
|
||||||
|
bg = "#f0f0f0"
|
||||||
|
fg = "#000000"
|
||||||
|
sel_bg = "#cce5ff"
|
||||||
|
sel_fg = "#000000"
|
||||||
|
link = "blue"
|
||||||
|
surface = "#ffffff"
|
||||||
|
header = "#eeeeee"
|
||||||
|
fieldbg = "#ffffff"
|
||||||
|
border = "#cccccc"
|
||||||
|
muted = "#404040"
|
||||||
|
accent = "#0a84ff"
|
||||||
|
|
||||||
|
s = self._style
|
||||||
|
# Base containers and labels
|
||||||
|
s.configure("TFrame", background=bg, foreground=fg)
|
||||||
|
s.configure("TLabel", background=bg, foreground=fg)
|
||||||
|
s.configure("TLabelframe", background=bg, foreground=fg)
|
||||||
|
s.configure("TLabelframe.Label", background=bg, foreground=fg)
|
||||||
|
s.configure("MS.TLabel", background=bg, foreground=fg)
|
||||||
|
s.configure("green.TLabel", background=bg)
|
||||||
|
s.configure("yellow.TLabel", background=bg)
|
||||||
|
s.configure("red.TLabel", background=bg)
|
||||||
|
s.configure("Link.TLabel", font=self._fonts["underlined"], background=bg, foreground=link)
|
||||||
|
# Buttons and checks
|
||||||
|
s.configure("TButton", background=surface, foreground=fg, bordercolor=border)
|
||||||
|
s.configure("Large.TButton", background=surface, foreground=fg, bordercolor=border)
|
||||||
|
s.map(
|
||||||
|
"TButton",
|
||||||
|
background=[("active", header), ("pressed", border)],
|
||||||
|
foreground=[("disabled", muted)],
|
||||||
|
)
|
||||||
|
s.configure(
|
||||||
|
"TCheckbutton",
|
||||||
|
background=bg,
|
||||||
|
foreground=fg,
|
||||||
|
focuscolor=bg,
|
||||||
|
bordercolor=border,
|
||||||
|
)
|
||||||
|
s.map(
|
||||||
|
"TCheckbutton",
|
||||||
|
# Remove hover visuals by mapping active/pressed to the base background
|
||||||
|
background=[
|
||||||
|
("active", bg),
|
||||||
|
("pressed", bg),
|
||||||
|
],
|
||||||
|
foreground=[("disabled", muted)],
|
||||||
|
indicatorcolor=[
|
||||||
|
("selected", accent if dark else fg),
|
||||||
|
("!selected", border),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
# Notebook
|
||||||
|
s.configure("TNotebook", background=bg, bordercolor=border)
|
||||||
|
s.configure("TNotebook.Tab", background=surface, foreground=fg, bordercolor=border)
|
||||||
|
s.map(
|
||||||
|
"TNotebook.Tab",
|
||||||
|
background=[("selected", header), ("active", header)],
|
||||||
|
foreground=[("disabled", muted)],
|
||||||
|
)
|
||||||
|
# Entries/Combos
|
||||||
|
s.configure(
|
||||||
|
"TEntry", fieldbackground=fieldbg, background=fieldbg, foreground=fg, insertcolor=fg
|
||||||
|
)
|
||||||
|
s.configure(
|
||||||
|
"TCombobox", fieldbackground=fieldbg, background=fieldbg, foreground=fg, arrowcolor=fg
|
||||||
|
)
|
||||||
|
# Ensure readability for readonly comboboxes (Language, Priority mode)
|
||||||
|
s.map(
|
||||||
|
"TCombobox",
|
||||||
|
foreground=[("readonly", fg), ("disabled", muted)],
|
||||||
|
fieldbackground=[("readonly", fieldbg)],
|
||||||
|
background=[("readonly", fieldbg)],
|
||||||
|
arrowcolor=[("readonly", fg)],
|
||||||
|
)
|
||||||
|
s.map("TEntry", foreground=[("disabled", muted)])
|
||||||
|
# Treeview
|
||||||
|
s.configure(
|
||||||
|
"Treeview",
|
||||||
|
background=surface,
|
||||||
|
fieldbackground=surface,
|
||||||
|
foreground=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
)
|
||||||
|
s.map(
|
||||||
|
"Treeview",
|
||||||
|
background=[("selected", sel_bg)],
|
||||||
|
foreground=[("selected", sel_fg)],
|
||||||
|
)
|
||||||
|
s.configure("Treeview.Heading", background=header, foreground=fg, bordercolor=border)
|
||||||
|
# Progressbar
|
||||||
|
s.configure("TProgressbar", background=accent, troughcolor=surface)
|
||||||
|
# Scrollbars
|
||||||
|
s.configure(
|
||||||
|
"Vertical.TScrollbar",
|
||||||
|
background=surface,
|
||||||
|
troughcolor=bg,
|
||||||
|
arrowcolor=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
)
|
||||||
|
s.configure(
|
||||||
|
"Horizontal.TScrollbar",
|
||||||
|
background=surface,
|
||||||
|
troughcolor=bg,
|
||||||
|
arrowcolor=fg,
|
||||||
|
bordercolor=border,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Pure Tk widgets
|
||||||
|
# Console text
|
||||||
|
self.output.configure_theme(bg=surface, fg=fg, sel_bg=sel_bg, sel_fg=sel_fg)
|
||||||
|
# Listboxes
|
||||||
|
self.settings._priority_list.configure_theme(
|
||||||
|
bg=surface, fg=fg, sel_bg=sel_bg, sel_fg=sel_fg
|
||||||
|
)
|
||||||
|
self.settings._exclude_list.configure_theme(
|
||||||
|
bg=surface, fg=fg, sel_bg=sel_bg, sel_fg=sel_fg
|
||||||
|
)
|
||||||
|
# Inventory canvas
|
||||||
|
self.inv.configure_theme(bg=bg)
|
||||||
|
|
||||||
|
# Tk option database for selection/popup list readability (affects Tk-backed widgets)
|
||||||
|
# Global selection colors and listbox defaults (covers Combobox dropdown)
|
||||||
|
self._root.option_add("*selectBackground", sel_bg)
|
||||||
|
self._root.option_add("*selectForeground", sel_fg)
|
||||||
|
# Combobox dropdown list (Tk Listbox)
|
||||||
|
for key in (
|
||||||
|
"*TCombobox*Listbox.background",
|
||||||
|
"*TCombobox*Listbox.Background",
|
||||||
|
"*Listbox.background",
|
||||||
|
):
|
||||||
|
self._root.option_add(key, surface)
|
||||||
|
for key in (
|
||||||
|
"*TCombobox*Listbox.foreground",
|
||||||
|
"*TCombobox*Listbox.Foreground",
|
||||||
|
"*Listbox.foreground",
|
||||||
|
):
|
||||||
|
self._root.option_add(key, fg)
|
||||||
|
for key in (
|
||||||
|
"*TCombobox*Listbox.selectBackground",
|
||||||
|
"*Listbox.selectBackground",
|
||||||
|
):
|
||||||
|
self._root.option_add(key, sel_bg)
|
||||||
|
for key in (
|
||||||
|
"*TCombobox*Listbox.selectForeground",
|
||||||
|
"*Listbox.selectForeground",
|
||||||
|
):
|
||||||
|
self._root.option_add(key, sel_fg)
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# GUI MANAGER END #
|
# GUI MANAGER END #
|
||||||
@@ -2403,6 +2620,7 @@ if __name__ == "__main__":
|
|||||||
tray=False,
|
tray=False,
|
||||||
priority=[],
|
priority=[],
|
||||||
proxy=URL(),
|
proxy=URL(),
|
||||||
|
dark_mode=False,
|
||||||
alter=lambda: None,
|
alter=lambda: None,
|
||||||
language="English",
|
language="English",
|
||||||
autostart_tray=False,
|
autostart_tray=False,
|
||||||
|
|||||||
@@ -135,6 +135,7 @@
|
|||||||
"tray": "Automatisk start i systembakken: ",
|
"tray": "Automatisk start i systembakken: ",
|
||||||
"tray_notifications": "Bakkemeddelelser: ",
|
"tray_notifications": "Bakkemeddelelser: ",
|
||||||
"priority_only": "Kun prioritet: ",
|
"priority_only": "Kun prioritet: ",
|
||||||
|
"dark_mode": "Mørk tilstand: ",
|
||||||
"proxy": "Proxy (kræver genstart):"
|
"proxy": "Proxy (kræver genstart):"
|
||||||
},
|
},
|
||||||
"game_name": "Spilnavn",
|
"game_name": "Spilnavn",
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Autostart: ",
|
"autostart": "Autostart: ",
|
||||||
"tray": "Autostart ins System Tray: ",
|
"tray": "Autostart ins System Tray: ",
|
||||||
"priority_only": "Nur Priorität: ",
|
"priority_only": "Nur Priorität: ",
|
||||||
|
"dark_mode": "Dunkler Modus: ",
|
||||||
"proxy": "Proxy (Erfordert Neustart):"
|
"proxy": "Proxy (Erfordert Neustart):"
|
||||||
},
|
},
|
||||||
"game_name": "Spiel",
|
"game_name": "Spiel",
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Ejecutar al iniciar el sistema: ",
|
"autostart": "Ejecutar al iniciar el sistema: ",
|
||||||
"tray": "Ejecutar en la bandeja del sistema: ",
|
"tray": "Ejecutar en la bandeja del sistema: ",
|
||||||
"tray_notifications": "Mostrar notificaciones: ",
|
"tray_notifications": "Mostrar notificaciones: ",
|
||||||
|
"dark_mode": "Modo oscuro: ",
|
||||||
"priority_mode": "Modo de prioridad: ",
|
"priority_mode": "Modo de prioridad: ",
|
||||||
"proxy": "Proxy (requiere reinicio):"
|
"proxy": "Proxy (requiere reinicio):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Démarrage automatique :",
|
"autostart": "Démarrage automatique :",
|
||||||
"tray": "Démarrage automatique dans la barre des tâches :",
|
"tray": "Démarrage automatique dans la barre des tâches :",
|
||||||
"tray_notifications": "Notifications dans la barre des tâches :",
|
"tray_notifications": "Notifications dans la barre des tâches :",
|
||||||
|
"dark_mode": "Mode sombre : ",
|
||||||
"priority_mode": "Mode de priorité :",
|
"priority_mode": "Mode de priorité :",
|
||||||
"proxy": "Proxy (nécessite un redémarrage) :"
|
"proxy": "Proxy (nécessite un redémarrage) :"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Mulai secara otomatis :",
|
"autostart": "Mulai secara otomatis :",
|
||||||
"tray": "Mulai otomatis di bilah tugas :",
|
"tray": "Mulai otomatis di bilah tugas :",
|
||||||
"tray_notifications": "Pemberitahuan bilah tugas :",
|
"tray_notifications": "Pemberitahuan bilah tugas :",
|
||||||
|
"dark_mode": "Mode gelap: ",
|
||||||
"priority_only": "Prioritas saja :",
|
"priority_only": "Prioritas saja :",
|
||||||
"proxy": "Proksi (harus dimulai ulang) :"
|
"proxy": "Proksi (harus dimulai ulang) :"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Avvio automatico: ",
|
"autostart": "Avvio automatico: ",
|
||||||
"tray": "Avvio automatico nella barra delle applicazioni: ",
|
"tray": "Avvio automatico nella barra delle applicazioni: ",
|
||||||
"tray_notifications": "Notifiche: ",
|
"tray_notifications": "Notifiche: ",
|
||||||
|
"dark_mode": "Modalità scura: ",
|
||||||
"priority_only": "Solo priorità: ",
|
"priority_only": "Solo priorità: ",
|
||||||
"proxy": "Proxy (richiede il riavvio):"
|
"proxy": "Proxy (richiede il riavvio):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Autostart: ",
|
"autostart": "Autostart: ",
|
||||||
"tray": "Automatisch starten in het taakbalk: ",
|
"tray": "Automatisch starten in het taakbalk: ",
|
||||||
"priority_only": "Alleen prioriteit: ",
|
"priority_only": "Alleen prioriteit: ",
|
||||||
|
"dark_mode": "Donkere modus: ",
|
||||||
"proxy": "Proxy (Vereist opnieuw opstarten):"
|
"proxy": "Proxy (Vereist opnieuw opstarten):"
|
||||||
},
|
},
|
||||||
"game_name": "Spel",
|
"game_name": "Spel",
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Autostart: ",
|
"autostart": "Autostart: ",
|
||||||
"tray": "Autostart z zasobnika: ",
|
"tray": "Autostart z zasobnika: ",
|
||||||
"tray_notifications": "Powiadomienia z zasobnika: ",
|
"tray_notifications": "Powiadomienia z zasobnika: ",
|
||||||
|
"dark_mode": "Tryb ciemny: ",
|
||||||
"priority_mode": "Tryb priorytetu: ",
|
"priority_mode": "Tryb priorytetu: ",
|
||||||
"proxy": "Proxy (wymaga restartu):"
|
"proxy": "Proxy (wymaga restartu):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -133,6 +133,8 @@
|
|||||||
"name": "Geral",
|
"name": "Geral",
|
||||||
"autostart": "Auto-início: ",
|
"autostart": "Auto-início: ",
|
||||||
"tray": "Auto-iniciar na área de notificação: ",
|
"tray": "Auto-iniciar na área de notificação: ",
|
||||||
|
"tray_notifications": "Notificações: ",
|
||||||
|
"dark_mode": "Modo escuro: ",
|
||||||
"priority_only": "Apenas com prioridade: ",
|
"priority_only": "Apenas com prioridade: ",
|
||||||
"proxy": "Proxy (requer o reinício do app):"
|
"proxy": "Proxy (requer o reinício do app):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Pornire automată :",
|
"autostart": "Pornire automată :",
|
||||||
"tray": "Pornire automată în bara de activități :",
|
"tray": "Pornire automată în bara de activități :",
|
||||||
"tray_notifications": "Notificări în bara de activități :",
|
"tray_notifications": "Notificări în bara de activități :",
|
||||||
|
"dark_mode": "Mod întunecat :",
|
||||||
"priority_only": "Doar cu prioritate :",
|
"priority_only": "Doar cu prioritate :",
|
||||||
"proxy": "Proxy (necesită repornire) :"
|
"proxy": "Proxy (necesită repornire) :"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Otomatik başlatma: ",
|
"autostart": "Otomatik başlatma: ",
|
||||||
"tray": "Sistem tepsisine otomatik başlatma: ",
|
"tray": "Sistem tepsisine otomatik başlatma: ",
|
||||||
"priority_only": "Yalnızca öncelik: ",
|
"priority_only": "Yalnızca öncelik: ",
|
||||||
|
"dark_mode": "Karanlık mod: ",
|
||||||
"proxy": "Proxy (Yeniden başlatma gerektirir):"
|
"proxy": "Proxy (Yeniden başlatma gerektirir):"
|
||||||
},
|
},
|
||||||
"game_name": "Oyun",
|
"game_name": "Oyun",
|
||||||
|
|||||||
@@ -127,6 +127,7 @@
|
|||||||
"autostart": "Automatické spuštění: ",
|
"autostart": "Automatické spuštění: ",
|
||||||
"tray": "Automaticky spusti minimalizovaně: ",
|
"tray": "Automaticky spusti minimalizovaně: ",
|
||||||
"priority_only": "Pouze prioritní: ",
|
"priority_only": "Pouze prioritní: ",
|
||||||
|
"dark_mode": "Tmavý režim: ",
|
||||||
"proxy": "Proxy:"
|
"proxy": "Proxy:"
|
||||||
},
|
},
|
||||||
"game_name": "Název Hry",
|
"game_name": "Název Hry",
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Автозапуск: ",
|
"autostart": "Автозапуск: ",
|
||||||
"tray": "Автозапуск свёрнутым: ",
|
"tray": "Автозапуск свёрнутым: ",
|
||||||
"tray_notifications": "Всплывающие уведомления: ",
|
"tray_notifications": "Всплывающие уведомления: ",
|
||||||
|
"dark_mode": "Тёмный режим: ",
|
||||||
"priority_mode": "Режим приоритета: ",
|
"priority_mode": "Режим приоритета: ",
|
||||||
"proxy": "Прокси (Требуется перезапуск):"
|
"proxy": "Прокси (Требуется перезапуск):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "Автозапуск: ",
|
"autostart": "Автозапуск: ",
|
||||||
"tray": "Автозапуск у треї: ",
|
"tray": "Автозапуск у треї: ",
|
||||||
"tray_notifications": "Сповіщення: ",
|
"tray_notifications": "Сповіщення: ",
|
||||||
|
"dark_mode": "Темний режим: ",
|
||||||
"priority_mode": "Режим пріоритету: ",
|
"priority_mode": "Режим пріоритету: ",
|
||||||
"proxy": "Проксі (потребує перезапуску):"
|
"proxy": "Проксі (потребує перезапуску):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "تشغيل تلقائي ",
|
"autostart": "تشغيل تلقائي ",
|
||||||
"tray": "تشغيل تلقائي في الدرج ",
|
"tray": "تشغيل تلقائي في الدرج ",
|
||||||
"tray_notifications": "إشعارات الدرج ",
|
"tray_notifications": "إشعارات الدرج ",
|
||||||
|
"dark_mode": "الوضع الداكن: ",
|
||||||
"priority_only": "الأولوية فقط ",
|
"priority_only": "الأولوية فقط ",
|
||||||
"proxy": "بروكسي (يتطلب إعادة التشغيل) "
|
"proxy": "بروكسي (يتطلب إعادة التشغيل) "
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "自動起動:",
|
"autostart": "自動起動:",
|
||||||
"tray": "トレイに自動起動:",
|
"tray": "トレイに自動起動:",
|
||||||
"tray_notifications": "トレイ通知:",
|
"tray_notifications": "トレイ通知:",
|
||||||
|
"dark_mode": "ダークモード:",
|
||||||
"priority_only": "優先のみ:",
|
"priority_only": "優先のみ:",
|
||||||
"proxy": "プロキシ(再起動が必要):"
|
"proxy": "プロキシ(再起動が必要):"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "开机自启: ",
|
"autostart": "开机自启: ",
|
||||||
"tray": "开机自启并最小化: ",
|
"tray": "开机自启并最小化: ",
|
||||||
"tray_notifications": "启用托盘通知: ",
|
"tray_notifications": "启用托盘通知: ",
|
||||||
|
"dark_mode": "深色模式: ",
|
||||||
"priority_mode": "掉宝模式: ",
|
"priority_mode": "掉宝模式: ",
|
||||||
"proxy": "代理:"
|
"proxy": "代理:"
|
||||||
},
|
},
|
||||||
|
|||||||
+2
-1
@@ -134,6 +134,7 @@
|
|||||||
"autostart": "開機時自動啟動:",
|
"autostart": "開機時自動啟動:",
|
||||||
"tray": "開機時以最小化自動啟動:",
|
"tray": "開機時以最小化自動啟動:",
|
||||||
"tray_notifications": "啟用系統列通知:",
|
"tray_notifications": "啟用系統列通知:",
|
||||||
|
"dark_mode": "深色模式:",
|
||||||
"priority_mode": "掉寶模式:",
|
"priority_mode": "掉寶模式:",
|
||||||
"proxy": "代理伺服器(需要重新啟動):"
|
"proxy": "代理伺服器(需要重新啟動):"
|
||||||
},
|
},
|
||||||
@@ -158,6 +159,6 @@
|
|||||||
"how_it_works_text": "每隔一段時間,應用程式就會向 Twitch 請求當前觀看頻道的原始串流數據的 URL。然後提取此串流的元數據——這足以推進掉寶進度。請注意,這完全繞過了下載實際的串流視頻和音頻的需求。為了使頻道的狀態(上線或離線)的即時更新,應用程式建立了一個 WebSocket 連接,該連接會接收有關串流上下線的事件或當前觀眾數量的更新。",
|
"how_it_works_text": "每隔一段時間,應用程式就會向 Twitch 請求當前觀看頻道的原始串流數據的 URL。然後提取此串流的元數據——這足以推進掉寶進度。請注意,這完全繞過了下載實際的串流視頻和音頻的需求。為了使頻道的狀態(上線或離線)的即時更新,應用程式建立了一個 WebSocket 連接,該連接會接收有關串流上下線的事件或當前觀眾數量的更新。",
|
||||||
"getting_started": "事前準備",
|
"getting_started": "事前準備",
|
||||||
"getting_started_text": "1. 透過應用程式登入。\n2. 確保您的 Twitch 帳號已經和您所有感興趣的遊戲帳號已經連接。\n 3. 如果您想要獲取所有感興趣的掉寶,請不要勾選「僅參與優先掉寶遊戲」,然後按「重新載入」。\n4. 如果您想優先獲取特定遊戲,請使用「優先掉寶遊戲」列表設置您想獲取的遊戲的優先順序。應用程式將嘗試先獲取列表頂端的遊戲,然後依序獲取之後的遊戲。\n5. 勾選「僅參與優先掉寶遊戲」以避免獲取不在優先列表中的遊戲。當然,你也可以選擇不勾選——這取決於您。\n6. 使用「排除掉寶遊戲」列表設置永不獲取的遊戲。\n7. 更改任一列表的內容,或更改「僅參與優先掉寶遊戲」勾選狀態,需要手動按「重新載入」才能使更改生效。"
|
"getting_started_text": "1. 透過應用程式登入。\n2. 確保您的 Twitch 帳號已經和您所有感興趣的遊戲帳號已經連接。\n 3. 如果您想要獲取所有感興趣的掉寶,請不要勾選「僅參與優先掉寶遊戲」,然後按「重新載入」。\n4. 如果您想優先獲取特定遊戲,請使用「優先掉寶遊戲」列表設置您想獲取的遊戲的優先順序。應用程式將嘗試先獲取列表頂端的遊戲,然後依序獲取之後的遊戲。\n5. 勾選「僅參與優先掉寶遊戲」以避免獲取不在優先列表中的遊戲。當然,你也可以選擇不勾選——這取決於您。\n6. 使用「排除掉寶遊戲」列表設置永不獲取的遊戲。\n7. 更改任一列表的內容,或更改「僅參與優先掉寶遊戲」勾選狀態,需要手動按「重新載入」才能使更改生效。"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,7 @@ if TYPE_CHECKING:
|
|||||||
class SettingsFile(TypedDict):
|
class SettingsFile(TypedDict):
|
||||||
proxy: URL
|
proxy: URL
|
||||||
language: str
|
language: str
|
||||||
|
dark_mode: bool
|
||||||
exclude: set[str]
|
exclude: set[str]
|
||||||
priority: list[str]
|
priority: list[str]
|
||||||
autostart_tray: bool
|
autostart_tray: bool
|
||||||
@@ -26,6 +27,7 @@ default_settings: SettingsFile = {
|
|||||||
"proxy": URL(),
|
"proxy": URL(),
|
||||||
"priority": [],
|
"priority": [],
|
||||||
"exclude": set(),
|
"exclude": set(),
|
||||||
|
"dark_mode": False,
|
||||||
"autostart_tray": False,
|
"autostart_tray": False,
|
||||||
"connection_quality": 1,
|
"connection_quality": 1,
|
||||||
"language": DEFAULT_LANG,
|
"language": DEFAULT_LANG,
|
||||||
@@ -46,6 +48,7 @@ class Settings:
|
|||||||
# from settings file
|
# from settings file
|
||||||
proxy: URL
|
proxy: URL
|
||||||
language: str
|
language: str
|
||||||
|
dark_mode: bool
|
||||||
exclude: set[str]
|
exclude: set[str]
|
||||||
priority: list[str]
|
priority: list[str]
|
||||||
autostart_tray: bool
|
autostart_tray: bool
|
||||||
|
|||||||
@@ -161,6 +161,7 @@ class GUISettingsGeneral(TypedDict):
|
|||||||
autostart: str
|
autostart: str
|
||||||
tray: str
|
tray: str
|
||||||
tray_notifications: str
|
tray_notifications: str
|
||||||
|
dark_mode: str
|
||||||
priority_mode: str
|
priority_mode: str
|
||||||
proxy: str
|
proxy: str
|
||||||
|
|
||||||
@@ -361,6 +362,7 @@ default_translation: Translation = {
|
|||||||
"autostart": "Autostart: ",
|
"autostart": "Autostart: ",
|
||||||
"tray": "Autostart into tray: ",
|
"tray": "Autostart into tray: ",
|
||||||
"tray_notifications": "Tray notifications: ",
|
"tray_notifications": "Tray notifications: ",
|
||||||
|
"dark_mode": "Dark mode: ",
|
||||||
"priority_mode": "Priority mode: ",
|
"priority_mode": "Priority mode: ",
|
||||||
"proxy": "Proxy (requires restart):",
|
"proxy": "Proxy (requires restart):",
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in new issue
Block a user