From b192bdf42480b32d261e948af5587457588b7c72 Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Wed, 25 Jun 2025 21:19:29 +0200 Subject: [PATCH] Convert from card based view to list based view with thumbnails --- menus/main.py | 56 +++++++++++++++-------------------------------- utils/utils.py | 59 ++++++++++++++++---------------------------------- 2 files changed, 36 insertions(+), 79 deletions(-) diff --git a/menus/main.py b/menus/main.py index d874be3..e634810 100644 --- a/menus/main.py +++ b/menus/main.py @@ -3,7 +3,7 @@ import arcade, pyglet from utils.preload import * from utils.constants import button_style, slider_style, audio_extensions, discord_presence_id -from utils.utils import FakePyPresence, UIFocusTextureButton, Card, extract_metadata, get_audio_thumbnail_texture, truncate_end, get_wrapped_text, adjust_volume +from utils.utils import FakePyPresence, UIFocusTextureButton, ListItem, extract_metadata, get_audio_thumbnail_texture, truncate_end, adjust_volume from math import ceil from thefuzz import process, fuzz @@ -56,9 +56,7 @@ class Main(arcade.gui.UIView): self.tab_options = self.settings_dict.get("tab_options", [os.path.join("~", "Music"), os.path.join("~", "Downloads")]) self.tab_content = {} - self.tab_wrapped_text = {} self.playlist_content = {} - self.playlist_wrapped_text = {} self.thumbnails = {} self.tab_buttons = {} self.music_buttons = {} @@ -107,8 +105,8 @@ class Main(arcade.gui.UIView): self.scrollbar.size_hint = (0.02, 1) self.scroll_box.add(self.scrollbar) - self.music_grid = arcade.gui.UIGridLayout(horizontal_spacing=30, vertical_spacing=30, row_count=100, column_count=8) - self.scroll_area.add(self.music_grid) + self.music_box = arcade.gui.UIBoxLayout(space_between=5) + self.scroll_area.add(self.music_box) # Utility @@ -262,11 +260,11 @@ class Main(arcade.gui.UIView): def show_content(self, tab): for music_button in self.music_buttons.values(): music_button.remove(music_button.button) - music_button.remove(music_button.label) - self.music_grid.remove(music_button) + music_button.remove(music_button.image) + self.music_box.remove(music_button) del music_button - self.music_grid.clear() + self.music_box.clear() self.music_buttons.clear() if self.current_mode == "files": @@ -274,61 +272,46 @@ class Main(arcade.gui.UIView): if not self.search_term == "": matches = process.extract(self.search_term, self.tab_content[self.current_tab], limit=5, processor=lambda text: text.lower(), scorer=fuzz.partial_token_sort_ratio) self.highest_score_file = f"{self.current_tab}/{matches[0][0]}" - for n, match in enumerate(matches): + for match in matches: music_filename = match[0] - self.music_buttons[f"{tab}/{music_filename}"] = self.music_grid.add(Card(card_texture=self.thumbnails[f"{tab}/{music_filename}"], font_name="Roboto", font_size=13, text=music_filename, width=self.window.width / 11, height=self.window.height / 11), row=0, column=n) + self.music_buttons[f"{tab}/{music_filename}"] = self.music_box.add(ListItem(texture=self.thumbnails[f"{tab}/{music_filename}"], font_name="Roboto", font_size=13, text=music_filename, width=self.window.width / 1.2, height=self.window.height / 11)) self.music_buttons[f"{tab}/{music_filename}"].button.on_click = lambda event, tab=tab, music_filename=music_filename: self.music_button_click(event, f"{tab}/{music_filename}") else: - self.music_grid.row_count = ceil(len(self.tab_content[tab]) / 8) - self.highest_score_file = "" self.no_music_label.visible = not self.tab_content[tab] - for n, music_filename in enumerate(self.tab_content[tab]): - row = n // 8 - col = n % 8 - - self.music_buttons[f"{tab}/{music_filename}"] = self.music_grid.add(Card(card_texture=self.thumbnails[f"{tab}/{music_filename}"], font_name="Roboto", font_size=13, text=self.tab_wrapped_text[tab][n], width=self.window.width / 11, height=self.window.height / 11), row=row, column=col) + for music_filename in self.tab_content[tab]: + self.music_buttons[f"{tab}/{music_filename}"] = self.music_box.add(ListItem(texture=self.thumbnails[f"{tab}/{music_filename}"], font_name="Roboto", font_size=13, text=music_filename, width=self.window.width / 1.2, height=self.window.height / 11)) self.music_buttons[f"{tab}/{music_filename}"].button.on_click = lambda event, tab=tab, music_filename=music_filename: self.music_button_click(event, f"{tab}/{music_filename}") - self.music_grid._update_size_hints() + self.music_box._update_size_hints() elif self.current_mode == "playlist": self.current_playlist = tab - n = 0 - if self.current_playlist: if not self.search_term == "": matches = process.extract(self.search_term, self.playlist_content[tab], limit=5, processor=lambda text: text.lower(), scorer=fuzz.partial_token_sort_ratio) self.highest_score_file = matches[0][0] - for n, match in enumerate(matches): + for match in matches: music_filename = match[0] - self.music_buttons[music_filename] = self.music_grid.add(Card(card_texture=self.thumbnails[music_filename], font_name="Roboto", font_size=13, text=music_filename, width=self.window.width / 11, height=self.window.height / 11), row=0, column=n) + self.music_buttons[music_filename] = self.music_box.add(ListItem(texture=self.thumbnails[music_filename], font_name="Roboto", font_size=13, text=music_filename, width=self.window.width / 1.2, height=self.window.height / 11)) self.music_buttons[music_filename].button.on_click = lambda event, music_filename=music_filename: self.music_button_click(event, music_filename) else: - self.music_grid.row_count = ceil((len(self.playlist_content[tab]) + 1) / 8) - self.highest_score_file = "" self.no_music_label.visible = not self.playlist_content[tab] - for n, music_filename in enumerate(self.playlist_content[tab]): - row = n // 8 - col = n % 8 - - self.music_buttons[music_filename] = self.music_grid.add(Card(card_texture=self.thumbnails[music_filename], font_name="Roboto", font_size=13, text=self.playlist_wrapped_text[tab][n], width=self.window.width / 11, height=self.window.height / 11), row=row, column=col) + for music_filename in self.playlist_content[tab]: + self.music_buttons[music_filename] = self.music_box.add(ListItem(texture=self.thumbnails[music_filename], font_name="Roboto", font_size=13, text=music_filename, width=self.window.width / 1.2, height=self.window.height / 11)) self.music_buttons[music_filename].button.on_click = lambda event, music_filename=music_filename: self.music_button_click(event, music_filename) - self.music_grid._update_size_hints() + self.music_box._update_size_hints() - row = (n + 1) // 8 - col = (n + 1) % 8 - - self.music_buttons["add_music"] = self.music_grid.add(Card(card_texture=music_icon, font_name="Roboto", font_size=13, text="Add Music", width=self.window.width / 11, height=self.window.height / 11), row=row, column=col) + self.music_buttons["add_music"] = self.music_box.add(ListItem(texture=plus_icon, font_name="Roboto", font_size=13, text="Add Music", width=self.window.width / 1.2, height=self.window.height / 11)) self.music_buttons["add_music"].button.on_click = lambda event: self.add_music() self.anchor.detect_focusable_widgets() @@ -350,9 +333,7 @@ class Main(arcade.gui.UIView): def load_content(self): self.tab_content.clear() - self.tab_wrapped_text.clear() self.playlist_content.clear() - self.playlist_wrapped_text.clear() for tab in self.tab_options: expanded_tab = os.path.expanduser(tab) @@ -368,8 +349,6 @@ class Main(arcade.gui.UIView): if f"{expanded_tab}/{filename}" not in self.thumbnails: self.thumbnails[f"{expanded_tab}/{filename}"] = get_audio_thumbnail_texture(f"{expanded_tab}/{filename}", self.window.size) self.tab_content[expanded_tab].append(filename) - - self.tab_wrapped_text[expanded_tab] = get_wrapped_text(self.tab_content[expanded_tab], self.window.width // 11, 14) for playlist, content in self.settings_dict.get("playlists", {}).items(): for file in content: @@ -381,7 +360,6 @@ class Main(arcade.gui.UIView): self.thumbnails[file] = get_audio_thumbnail_texture(file, self.window.size) self.playlist_content[playlist] = content - self.playlist_wrapped_text[playlist] = get_wrapped_text(content, self.window.width // 11, 14) def load_tabs(self): self.tab_box.clear() diff --git a/utils/utils.py b/utils/utils.py index 7f7370d..cfe353c 100644 --- a/utils/utils.py +++ b/utils/utils.py @@ -1,4 +1,4 @@ -import logging, sys, traceback, os, re, platform, urllib.request, textwrap, io, base64, tempfile +import logging, sys, traceback, os, re, platform, urllib.request, io, base64, tempfile from mutagen.easyid3 import EasyID3 from mutagen.id3 import ID3 @@ -8,7 +8,8 @@ from pydub import AudioSegment from PIL import Image -from utils.constants import menu_background_color +from utils.constants import menu_background_color, button_style +from utils.preload import button_texture, button_hovered_texture import pyglet, arcade, arcade.gui @@ -86,50 +87,28 @@ class UIFocusTextureButton(arcade.gui.UITextureButton): else: self.resize(width=self.width / 1.1, height=self.height / 1.1) -class Card(arcade.gui.UIBoxLayout): - def __init__(self, width: int, height: int, font_name: str, font_size: int, text: str, card_texture: arcade.Texture, padding=10): - super().__init__(width=width, height=height, space_between=padding, align="top") +class ListItem(arcade.gui.UIBoxLayout): + def __init__(self, width: int, height: int, font_name: str, font_size: int, text: str, texture: arcade.Texture, padding=10): + super().__init__(width=width, height=height, space_between=padding, align="top", vertical=False) + + self.image = self.add(arcade.gui.UIImage( + texture=texture, + width=width * 0.1, + height=height + )) self.button = self.add(arcade.gui.UITextureButton( - texture=card_texture, - texture_hovered=card_texture, - texture_pressed=card_texture, - texture_disabled=card_texture, - width=width, + text=text, + texture=button_texture, + texture_hovered=button_hovered_texture, + texture_pressed=button_texture, + texture_disabled=button_texture, + style=button_style, + width=width * 0.9, height=height, interaction_buttons=[arcade.MOUSE_BUTTON_LEFT, arcade.MOUSE_BUTTON_RIGHT] )) - self.label = self.add(arcade.gui.UILabel( - text=text, - font_name=font_name, - font_size=font_size, - width=width, - height=height * 0.1, - multiline=True, - )) - -def get_wrapped_text(text_list: list[str], width: int, font_size: int): - max_lines = 0 - wrapped_line_list = [] - wrapped_text_list = [] - - for text in text_list: # get max lines and wrap text - wrapped_lines = textwrap.wrap(text, width=int(width / (font_size * 0.6))) - if len(wrapped_lines) > max_lines: - max_lines = len(wrapped_lines) - - wrapped_line_list.append(wrapped_lines) - - for wrapped_lines in wrapped_line_list: - if len(wrapped_lines) < max_lines: # adjust text to maximum lines - for i in range(max_lines - len(wrapped_lines)): - wrapped_lines.append("") - - wrapped_text_list.append("\n".join(wrapped_lines)) - - return wrapped_text_list - def on_exception(*exc_info): logging.error(f"Unhandled exception:\n{''.join(traceback.format_exception(exc_info[1], limit=None))}")