From c478858346b7a44dc93bd21030669a452b6775e6 Mon Sep 17 00:00:00 2001 From: Andy Zhang <37402126+AnzhiZhang@users.noreply.github.com> Date: Wed, 15 Jun 2022 21:53:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20=E2=9C=A8=20search=20modpacks=20and?= =?UTF-8?q?=20filter?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/window/frames/filters.py | 39 ++++++++++++++++-- utils/window/frames/search.py | 27 +++++++++++-- utils/window/frames/show.py | 72 ++++++++++++++++++++++++++++++++-- utils/window/main.py | 37 +++++++++++------ 4 files changed, 153 insertions(+), 22 deletions(-) diff --git a/utils/window/frames/filters.py b/utils/window/frames/filters.py index 1f459ca..d06d8b6 100644 --- a/utils/window/frames/filters.py +++ b/utils/window/frames/filters.py @@ -1,17 +1,25 @@ from tkinter import Frame, Label from tkinter.ttk import Combobox +from typing import TYPE_CHECKING, List + +from utils.constant import SEARCH + +if TYPE_CHECKING: + from utils.window.main import Main class Filters(Frame): - def __init__(self, master): + def __init__(self, master: 'Main'): super().__init__(master, height=50) + self.main_window = master + self.sort_label = Label(self, text='排序方式:') - self.sort_combobox = Combobox(self) + self.sort_combobox = Combobox(self, state='readonly') self.game_version_label = Label(self, text='游戏版本:') - self.game_version_combobox = Combobox(self) + self.game_version_combobox = Combobox(self, state='readonly') self.modpack_version_label = Label(self, text='整合包版本:') - self.modpack_version_combobox = Combobox(self) + self.modpack_version_combobox = Combobox(self, state='readonly') self.sort_label.pack(side='left') self.sort_combobox.pack(side='left') @@ -19,3 +27,26 @@ def __init__(self, master): self.game_version_combobox.pack(side='left') self.modpack_version_label.pack(side='left', padx=(10, 0)) self.modpack_version_combobox.pack(side='left') + + # Set combobox values + self.init() + + @property + def sort(self): + return self.sort_combobox.get() + + @property + def game_version(self): + return self.game_version_combobox.get() + + @property + def modpack_version(self): + return self.modpack_version_combobox.get() + + def init(self): + self.sort_combobox['values'] = list(SEARCH.SORT.keys()) + self.sort_combobox.current(1) + self.game_version_combobox['values'] = SEARCH.VERSIONS + + def set_modpack_version(self, values: List[str]): + self.modpack_version_combobox['values'] = values diff --git a/utils/window/frames/search.py b/utils/window/frames/search.py index be3c665..6a212df 100644 --- a/utils/window/frames/search.py +++ b/utils/window/frames/search.py @@ -1,12 +1,33 @@ -from tkinter import Frame, Entry, Label, Button +from tkinter import Frame, Entry, Button +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from utils.window.main import Main class Search(Frame): - def __init__(self, master): + def __init__(self, master: 'Main'): super().__init__(master, height=50) + self.main_window = master + self.search_entry = Entry(self) - self.search_button = Button(self, text='搜索', background='white') + self.search_button = Button( + self, + text='搜索', + background='white', + command=self.on_search + ) + + # Allow press enter in entry to search + self.search_entry.bind('', self.on_search) self.search_entry.pack(side='left', fill='both', expand=True) self.search_button.pack(side='left', fill='y', padx=(10, 0)) + + @property + def keyword(self): + return self.search_entry.get() + + def on_search(self, event=None): + self.main_window.show_frame.update_list() diff --git a/utils/window/frames/show.py b/utils/window/frames/show.py index 7d614bc..ff7340f 100644 --- a/utils/window/frames/show.py +++ b/utils/window/frames/show.py @@ -1,10 +1,76 @@ -from tkinter import Frame, Listbox +from threading import Thread +from tkinter import Frame, Listbox, Scrollbar +from typing import TYPE_CHECKING + +from utils.constant import SEARCH +from utils.requester import Requester + +if TYPE_CHECKING: + from utils.window.main import Main class Show(Frame): - def __init__(self, master): + def __init__(self, master: 'Main'): super().__init__(master) + self.main_window = master + self.index = 0 + self.updating = False + self.list_listbox = Listbox(self, font=('Arial', 12)) + self.list_listbox_scrollbar = Scrollbar(self) + + # Scrollbar setting + self.list_listbox.config(yscrollcommand=self.on_scroll) + self.list_listbox_scrollbar.config(command=self.list_listbox.yview) + + self.list_listbox.pack(side='left', fill='both', expand=True) + self.list_listbox_scrollbar.pack(side='left', fill='y') + + def update_list(self, append=False): + def request(index): + # Get filters + keyword = sort = game_version = None + if self.main_window.search_frame.keyword: + keyword = self.main_window.search_frame.keyword + if self.main_window.filters_frame.sort: + sort = SEARCH.SORT[self.main_window.filters_frame.sort] + if self.main_window.filters_frame.game_version: + game_version = self.main_window.filters_frame.game_version + + return Requester.search_modpack( + game_version=game_version, + search_filter=keyword, + sort=sort, + index=index + ).json() + + def run(): + self.updating = True + + # Refresh list or append + if not append: + self.list_listbox.delete(0, 'end') + else: + self.index += 1 + + # Add request results + for i in request(self.index): + self.list_listbox.insert('end', i['name'].strip()) + + self.updating = False + + # Protection + if not self.updating: + Thread( + target=run, + name='Update List Data' + ).start() + + def on_scroll(self, first, last): + # Call origin function + self.list_listbox_scrollbar.set(first, last) - self.list_listbox.pack(fill='both', expand=True) + # Update at the end + if float(last) == 1.0 and not self.updating: + self.update_list(append=True) diff --git a/utils/window/main.py b/utils/window/main.py index 9c655eb..31f90f2 100644 --- a/utils/window/main.py +++ b/utils/window/main.py @@ -27,24 +27,25 @@ def __init__(self): scale_factor = windll.shcore.GetScaleFactorForDevice(0) / 75 self.tk.call('tk', 'scaling', scale_factor) - self.title_frame = frames.Title(self) - self.search_frame = frames.Search(self) - self.show_frame = frames.Show(self) - self.filters_frame = frames.Filters(self) - self.buttons_frame = frames.Buttons(self) + self.__title_frame = frames.Title(self) + self.__search_frame = frames.Search(self) + self.__show_frame = frames.Show(self) + self.__filters_frame = frames.Filters(self) + self.__buttons_frame = frames.Buttons(self) - self.title_frame.pack(**self.PACK_KWARGS) - self.search_frame.pack(**self.PACK_KWARGS) - self.show_frame.pack(**self.PACK_KWARGS, expand=True) - self.filters_frame.pack(**self.PACK_KWARGS) - self.buttons_frame.pack(**self.PACK_KWARGS) + self.__title_frame.pack(**self.PACK_KWARGS) + self.__search_frame.pack(**self.PACK_KWARGS) + self.__show_frame.pack(**self.PACK_KWARGS, expand=True) + self.__filters_frame.pack(**self.PACK_KWARGS) + self.__buttons_frame.pack(**self.PACK_KWARGS) - self.ask_license() + self.__ask_license() + self.show_frame.update_list() self.mainloop() @staticmethod - def ask_license(): + def __ask_license(): """ Ask to accept license. :return: @@ -57,3 +58,15 @@ def ask_license(): '你应该随程序获得一份 GNU 通用公共许可证的复本。如果没有,请看 https://www.gnu.org/licenses/。' ): exit() + + @property + def search_frame(self): + return self.__search_frame + + @property + def show_frame(self): + return self.__show_frame + + @property + def filters_frame(self): + return self.__filters_frame