mirror of
https://github.com/rangermix/TwitchDropsMiner.git
synced 2026-05-26 07:08:04 +00:00
Implement a dynamic tray icon status picture
This commit is contained in:
@@ -19,7 +19,7 @@ script:
|
||||
|
||||
# Package the app.
|
||||
- mkdir -p "$TARGET_APPDIR"/usr/{src,share/icons/hicolor/128x128/apps}
|
||||
- cp -r "$SOURCE_DIR/../lang" "$SOURCE_DIR/../pickaxe.ico" "$SOURCE_DIR"/../*.py "$TARGET_APPDIR/usr/src"
|
||||
- cp -r "$SOURCE_DIR/../lang" "$SOURCE_DIR/../icons" "$SOURCE_DIR"/../*.py "$TARGET_APPDIR/usr/src"
|
||||
- cp "$SOURCE_DIR/pickaxe.png" "$TARGET_APPDIR/usr/share/icons/hicolor/128x128/apps/io.github.devilxd.twitchdropsminer.png"
|
||||
|
||||
# Install requirements.
|
||||
|
||||
@@ -17,7 +17,12 @@ if TYPE_CHECKING:
|
||||
|
||||
# (source_path, dest_path, required)
|
||||
to_add: list[tuple[Path, str, bool]] = [
|
||||
(Path("pickaxe.ico"), '.', True), # icon file
|
||||
# icon files
|
||||
(Path("icons/pickaxe.ico"), "./icons", True),
|
||||
(Path("icons/active.ico"), "./icons", True),
|
||||
(Path("icons/idle.ico"), "./icons", True),
|
||||
(Path("icons/error.ico"), "./icons", True),
|
||||
(Path("icons/maint.ico"), "./icons", True),
|
||||
# SeleniumWire HTTPS/SSL cert file and key
|
||||
(Path(SITE_PACKAGES_PATH, "seleniumwire/ca.crt"), "./seleniumwire", False),
|
||||
(Path(SITE_PACKAGES_PATH, "seleniumwire/ca.key"), "./seleniumwire", False),
|
||||
@@ -99,10 +104,10 @@ exe = EXE(
|
||||
console=False,
|
||||
upx_exclude=[],
|
||||
target_arch=None,
|
||||
icon="pickaxe.ico",
|
||||
runtime_tmpdir=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon="icons/pickaxe.ico",
|
||||
bootloader_ignore_signals=False,
|
||||
disable_windowed_traceback=False,
|
||||
name="Twitch Drops Miner (by DevilXD)",
|
||||
|
||||
25
gui.py
25
gui.py
@@ -1044,13 +1044,21 @@ class TrayIcon:
|
||||
def __init__(self, manager: GUIManager, master: ttk.Widget):
|
||||
self._manager = manager
|
||||
self.icon: pystray.Icon | None = None
|
||||
self.icon_image = Image_module.open(resource_path("pickaxe.ico"))
|
||||
self._icon_images: dict[str, Image_module.Image] = {
|
||||
"pickaxe": Image_module.open(resource_path("icons/pickaxe.ico")),
|
||||
"active": Image_module.open(resource_path("icons/active.ico")),
|
||||
"idle": Image_module.open(resource_path("icons/idle.ico")),
|
||||
"error": Image_module.open(resource_path("icons/error.ico")),
|
||||
"maint": Image_module.open(resource_path("icons/maint.ico")),
|
||||
}
|
||||
self._icon_state: str = "pickaxe"
|
||||
self._button = ttk.Button(master, command=self.minimize, text=_("gui", "tray", "minimize"))
|
||||
self._button.grid(column=0, row=0, sticky="ne")
|
||||
|
||||
def __del__(self) -> None:
|
||||
self.stop()
|
||||
self.icon_image.close()
|
||||
for icon_image in self._icon_images.values():
|
||||
icon_image.close()
|
||||
|
||||
def _shorten(self, text: str, by_len: int, min_len: int) -> str:
|
||||
if (text_len := len(text)) <= min_len + 3 or by_len <= 0:
|
||||
@@ -1096,7 +1104,9 @@ class TrayIcon:
|
||||
pystray.Menu.SEPARATOR,
|
||||
pystray.MenuItem(_("gui", "tray", "quit"), bridge(self.quit)),
|
||||
)
|
||||
self.icon = pystray.Icon("twitch_miner", self.icon_image, self.get_title(drop), menu)
|
||||
self.icon = pystray.Icon(
|
||||
"twitch_miner", self._icon_images[self._icon_state], self.get_title(drop), menu
|
||||
)
|
||||
# self.icon.run_detached()
|
||||
loop.run_in_executor(None, self.icon.run)
|
||||
|
||||
@@ -1142,6 +1152,13 @@ class TrayIcon:
|
||||
if self.icon is not None:
|
||||
self.icon.title = self.get_title(drop)
|
||||
|
||||
def change_icon(self, state: str):
|
||||
if state not in self._icon_images:
|
||||
raise ValueError("Invalid icon state")
|
||||
self._icon_state = state
|
||||
if self.icon is not None:
|
||||
self.icon.icon = self._icon_images[state]
|
||||
|
||||
|
||||
class Notebook:
|
||||
def __init__(self, manager: GUIManager, master: ttk.Widget):
|
||||
@@ -1937,7 +1954,7 @@ class GUIManager:
|
||||
# withdraw immediately to prevent the window from flashing
|
||||
self._root.withdraw()
|
||||
# root.resizable(False, True)
|
||||
set_root_icon(root, resource_path("pickaxe.ico"))
|
||||
set_root_icon(root, resource_path("icons/pickaxe.ico"))
|
||||
root.title(WINDOW_TITLE) # window title
|
||||
root.bind_all("<KeyPress-Escape>", self.unfocus) # pressing ESC unfocuses selection
|
||||
# Image cache for displaying images
|
||||
|
||||
BIN
icons/active.ico
Normal file
BIN
icons/active.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
icons/error.ico
Normal file
BIN
icons/error.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
icons/idle.ico
Normal file
BIN
icons/idle.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
BIN
icons/maint.ico
Normal file
BIN
icons/maint.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 66 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
3
main.py
3
main.py
@@ -87,7 +87,7 @@ if __name__ == "__main__":
|
||||
root = tk.Tk()
|
||||
root.overrideredirect(True)
|
||||
root.withdraw()
|
||||
set_root_icon(root, resource_path("pickaxe.ico"))
|
||||
set_root_icon(root, resource_path("icons/pickaxe.ico"))
|
||||
root.update()
|
||||
parser = Parser(
|
||||
SELF_PATH.name,
|
||||
@@ -168,6 +168,7 @@ if __name__ == "__main__":
|
||||
await client.shutdown()
|
||||
if not client.gui.close_requested:
|
||||
# user didn't request the closure
|
||||
client.gui.tray.change_icon("error")
|
||||
client.print(_("status", "terminated"))
|
||||
client.gui.status.update(_("gui", "status", "terminated"))
|
||||
# notify the user about the closure
|
||||
|
||||
@@ -608,11 +608,13 @@ class Twitch:
|
||||
if self.settings.dump:
|
||||
self.gui.close()
|
||||
continue
|
||||
self.gui.tray.change_icon("idle")
|
||||
self.gui.status.update(_("gui", "status", "idle"))
|
||||
self.stop_watching()
|
||||
# clear the flag and wait until it's set again
|
||||
self._state_change.clear()
|
||||
elif self._state is State.INVENTORY_FETCH:
|
||||
self.gui.tray.change_icon("maint")
|
||||
# ensure the websocket is running
|
||||
await self.websocket.start()
|
||||
await self.fetch_inventory()
|
||||
@@ -835,6 +837,7 @@ class Twitch:
|
||||
self.change_state(State.IDLE)
|
||||
del new_watching, selected_channel, watching_channel
|
||||
elif self._state is State.EXIT:
|
||||
self.gui.tray.change_icon("pickaxe")
|
||||
self.gui.status.update(_("gui", "status", "exiting"))
|
||||
# we've been requested to exit the application
|
||||
break
|
||||
@@ -982,6 +985,7 @@ class Twitch:
|
||||
)
|
||||
|
||||
def watch(self, channel: Channel, *, update_status: bool = True):
|
||||
self.gui.tray.change_icon("active")
|
||||
self.gui.channels.set_watching(channel)
|
||||
self.watching_channel.set(channel)
|
||||
if update_status:
|
||||
|
||||
Reference in New Issue
Block a user