class categorylistFrame(tk.Frame):
    def __init__(self, parent, controller, framework, packages):
        #list of packages to be displayed by this frame
        self.packages = packages
        self.parent = parent
        self.controller = controller  #Frame manager
        self.framework = framework  #**Scheduler
        self.appstore_handler = Store_handler  #Tool to get installed package data etc
        self.current_search = None
        self.selected = False
        self.sort_type = None
        self.listbox_list = []

        tk.Frame.__init__(self,
                          parent,
                          background=style.w,
                          border=0,
                          highlightthickness=0)

        threader.do_async(self.build_listframe)

    def build_listframe(self):
        columnwidth = 0.33 * (self.winfo_width() - style.updated_column_width)
        self.body_frame = tk.Frame(self, background=style.color_1)
        self.body_frame.place(relwidth=1, relheight=1)
        self.scrollbar = tk.Scrollbar(self.body_frame,
                                      troughcolor=style.color_1,
                                      bg=style.color_2)
        self.scrollbar.place(relheight=1,
                             width=style.scrollbarwidth,
                             relx=1,
                             x=-style.scrollbarwidth,
                             height=-(style.listbox_footer_height +
                                      style.listbox_footer_height),
                             y=+style.listbox_footer_height)
        self.listbox_frame = tk.Frame(self.body_frame,
                                      background=style.color_2)
        self.listbox_frame.place(relwidth=1,
                                 relheight=1,
                                 height=-style.listbox_footer_height,
                                 width=-style.scrollbarwidth)
        self.scaling_listboxes_frame = tk.Frame(self.listbox_frame,
                                                background=style.color_2)
        self.scaling_listboxes_frame.place(relwidth=1,
                                           relheight=1,
                                           width=-style.updated_column_width)
        self.scaling_listboxes_frame_header = tk.Frame(
            self.scaling_listboxes_frame, background=style.color_2)
        self.scaling_listboxes_frame_header.place(
            relwidth=1, height=style.listbox_header_height)
        self.scaling_listboxes_frame_body = tk.Frame(
            self.scaling_listboxes_frame, background=style.color_2)
        self.scaling_listboxes_frame_body.place(
            relwidth=1,
            relheight=1,
            y=style.listbox_header_height,
            height=-style.listbox_header_height)
        self.package_listbox = ThemedListbox(self.scaling_listboxes_frame_body,
                                             background=style.color_2,
                                             font=style.smallboldtext,
                                             borderwidth=1,
                                             foreground=style.w)
        self.package_listbox.place(relx=0, relwidth=0.33333, relheight=1)
        self.package_listbox_label = ThemedLabel(
            self.scaling_listboxes_frame_header,
            text="Package",
            background=style.color_1,
            font=style.mediumboldtext)
        self.package_listbox_label.place(relx=0, relwidth=0.33333, relheight=1)
        self.title_listbox = ThemedListbox(self.scaling_listboxes_frame_body,
                                           background=style.color_2,
                                           font=style.smalltext,
                                           borderwidth=1)
        self.title_listbox.place(relx=0.33333, relwidth=0.33333, relheight=1)
        self.title_listbox_label = ThemedLabel(
            self.scaling_listboxes_frame_header,
            text="Title",
            background=style.color_1,
            font=style.mediumboldtext)
        self.title_listbox_label.place(relx=0.33333,
                                       relwidth=0.33333,
                                       relheight=1)
        self.author_listbox = ThemedListbox(self.scaling_listboxes_frame_body,
                                            background=style.color_2,
                                            font=style.smalltext,
                                            borderwidth=1)
        self.author_listbox.place(relx=0.66666, relwidth=0.33333, relheight=1)
        self.author_listbox_label = ThemedLabel(
            self.scaling_listboxes_frame_header,
            text="Author",
            background=style.color_1,
            font=style.mediumboldtext)
        self.author_listbox_label.place(relx=0.66666,
                                        relwidth=0.33333,
                                        relheight=1)
        self.updated_listbox = ThemedListbox(self.listbox_frame,
                                             background=style.color_2,
                                             font=style.smalltext,
                                             borderwidth=1)
        self.updated_listbox.place(relx=1,
                                   width=style.updated_column_width,
                                   x=-style.updated_column_width,
                                   relheight=1,
                                   y=style.listbox_header_height,
                                   height=-style.listbox_header_height)
        self.updated_listbox_label = ThemedLabel(self.listbox_frame,
                                                 text="Updated",
                                                 background=style.color_1,
                                                 font=style.mediumboldtext)
        self.updated_listbox_label.place(relx=1,
                                         width=style.updated_column_width,
                                         x=-style.updated_column_width,
                                         height=style.listbox_header_height)
        self.listbox_list = [
            self.package_listbox, self.title_listbox, self.author_listbox,
            self.updated_listbox
        ]
        self.listbox_frame_footer = tk.Frame(self, background=style.color_1)
        self.listbox_frame_footer.place(relwidth=1,
                                        rely=1,
                                        y=-style.listbox_footer_height,
                                        height=style.listbox_footer_height)
        self.installed_label = ThemedLabel(self.listbox_frame_footer,
                                           text="Installed - ◆",
                                           background=style.color_1,
                                           foreground="green",
                                           anchor="center")
        self.installed_label.place(relx=0, relwidth=0.333, relheight=1)
        self.hasupdate_label = ThemedLabel(self.listbox_frame_footer,
                                           text="Update Available - ◆",
                                           background=style.color_1,
                                           foreground="yellow",
                                           anchor="center")
        self.hasupdate_label.place(relx=0.333, relwidth=0.333, relheight=1)
        self.notinstalled_label = ThemedLabel(self.listbox_frame_footer,
                                              text="Not installed - ◆",
                                              background=style.color_1,
                                              foreground="white",
                                              anchor="center")
        self.notinstalled_label.place(relx=0.666, relwidth=0.333, relheight=1)
        self.package_listbox.configure({"selectbackground": style.lg})
        self.package_listbox.configure({"selectmode": "single"})
        self.package_listbox.bind("<<ListboxSelect>>",
                                  self.on_listbox_selection)

        self.scrollbar.config(command=self.on_scroll_bar)
        self.package_listbox.config(yscrollcommand=self.scrollbar.set)

        self.set_sort_type(None)
        self.rebuild()

    def get_current_packages(self):
        packages = self.search_packages(self.current_search)
        if self.sort_type:
            packages = self.sort_packages(packages, self.sort_type)
        return packages

    def configure(self, event=None):
        self.rebuild()

    def search_packages(self, search: str = ""):
        if search:
            packages = []
            for package in self.packages:
                try:
                    for field in ["author", "name", "title", "description"]:
                        if search.lower() in package[field].lower():
                            packages.append(package)
                            break
                except:
                    pass
            return packages if packages else [{
                "name": "NO RESULTS",
                "title": "",
                "author": "",
                "updated": ""
            }]
        else:
            return self.packages

    def on_listbox_selection(self, event):
        selection = self.package_listbox.curselection()
        picked = self.package_listbox.get(selection[0])
        for package in self.packages:
            if package["name"] == picked:
                self.open_details(package)

    def sort_packages(self, packages, sort_method):
        reverse = False
        if sort_method.endswith('-'):
            reverse = True
            sort_method = sort_method.strip('-')

        return sorted(packages, key=lambda k: k[sort_method], reverse=reverse)

    def rebuild(self):
        self.build_frame(self.get_current_packages())

    def build_frame(self, packages):
        def do_build_frame():
            if not packages:
                return

            self.clear()

            if self.listbox_list:
                for lb in self.listbox_list:
                    lb.configure(state="normal")

                installed_packages = self.appstore_handler.get_packages(
                    silent=True)

                for package in packages:
                    if not package:
                        continue
                    self.package_listbox.insert('end', package["name"])
                    self.title_listbox.insert('end', package["title"])
                    self.author_listbox.insert('end', package["author"])
                    self.updated_listbox.insert('end', package["updated"])
                    if installed_packages:
                        if package["name"] in installed_packages:
                            if self.appstore_handler.get_package_version(
                                    package["name"]) == package["version"]:
                                self.package_listbox.itemconfig(
                                    'end', {"fg": "green"})
                            else:
                                self.package_listbox.itemconfig(
                                    'end', {"fg": "yellow"})

                for lb in self.listbox_list:
                    lb.configure(state="disable")
                self.package_listbox.configure(state='normal')

                bindlist = [
                    self, self.package_listbox, self.title_listbox,
                    self.author_listbox, self.updated_listbox
                ]

                if platform.system() == 'Windows' or platform.system(
                ) == "Darwin":
                    for b in bindlist:
                        b.bind("<MouseWheel>", self.on_mouse_wheel)
                elif platform.system() == "Linux":
                    for b in bindlist:
                        b.bind("<Button-4>", self.on_mouse_wheel)
                        b.bind("<Button-5>", self.on_mouse_wheel)

        threader.do_async(do_build_frame)

    def open_details(self, package):
        self.controller.frames["detailPage"].show(package)

    def select(self):
        self.selected = True

    def deselect(self):
        self.selected = False

    def is_selected(self):
        return self.selected

    def search(self, searchterm):
        self.current_search = searchterm
        self.rebuild()

    def clear(self):
        if self.listbox_list:
            for lb in self.listbox_list:
                lb.configure(state="normal")
                lb.delete(0, "end")
                lb.configure(state="disable")

    def on_scroll_bar(self, move_type, move_units, __=None):
        if move_type == "moveto":
            for lb in self.listbox_list:
                lb.yview("moveto", move_units)

    def on_mouse_wheel(self, event):
        try:
            if platform.system() == 'Windows':
                self.package_listbox.yview(
                    "scroll", int(-1 * (event.delta / 120), "units"))
            elif platform.system() == "Linux":
                if event.num == 5:
                    self.package_listbox.yview("scroll", 1, "units")
                if event.num == 4:
                    self.package_listbox.yview("scroll", -1, "units")
            elif platform.system() == "Darwin":
                self.package_listbox.yview("scroll", event.delta, "units")

            for listbox in self.listbox_list:
                listbox.yview_moveto(self.package_listbox.yview()[0])

            return "break"
        except:
            pass

    def set_sort_type(self, sort_type):
        self.sort_type = sort_type
Exemplo n.º 2
0
class appstorePage(activeFrame):
    def __init__(self, parent, controller):
        self.controller = controller
        self.appstore_handler = controller.appstore_handler
        self.repo_parser = controller.repo_parser
        self.image_sharer = controller.image_sharer
        self.current_frame = None
        self.current_frame_name = None
        self.last_selection = None
        self.last_sort_option = None
        activeFrame.__init__(self, parent, controller)

        self.column = ThemedFrame(self, background=style.color_1)
        self.column.place(relx=0,
                          rely=0,
                          width=style.sidecolumnwidth,
                          relheight=1)

        self.column_header = ThemedFrame(self.column, background=style.color_1)
        self.column_header.place(relx=0,
                                 rely=0,
                                 relwidth=1,
                                 height=style.headerheight)

        self.column_header_title = ThemedLabel(self.column_header,
                                               "HBUpdater\nGPLv3",
                                               anchor="center",
                                               label_font=style.giantboldtext,
                                               background=style.color_1)
        self.column_header_title.place(relx=0,
                                       rely=0,
                                       relwidth=1,
                                       relheight=1,
                                       height=-1)

        self.column_header_separator = ThemedLabel(self.column_header,
                                                   "",
                                                   background=style.lg)
        self.column_header_separator.place(x=style.offset,
                                           rely=1,
                                           y=-1,
                                           relwidth=1,
                                           width=-2 * style.offset)

        self.column_body = ThemedFrame(self.column, background=style.color_1)
        self.column_body.place(
            relx=0,
            relwidth=1,
            y=style.headerheight,
            relheight=1,
            height=-(style.headerheight + style.footerheight))

        self.category_listbox = ThemedListbox(self.column_body)
        self.category_listbox.configure(activestyle="none")
        self.category_listbox.place(relwidth=1, relheight=1)
        self.category_listbox.bind('<<ListboxSelect>>', self.select_frame)

        self.column_footer = ThemedFrame(self.column, background=style.color_1)
        self.column_footer.place(relx=0,
                                 rely=1,
                                 relwidth=1,
                                 height=style.footerheight,
                                 y=-style.footerheight)

        self.column_set_sd = button(self.column_footer,
                                    callback=self.set_sd,
                                    text_string="Select SD Root",
                                    font=style.mediumboldtext,
                                    background=style.color_2).place(
                                        relwidth=1,
                                        relheight=0.5,
                                        y=style.offset,
                                        x=style.offset,
                                        width=-2 * style.offset,
                                        height=-2 * style.offset)

        self.column_sd_status_label = ThemedLabel(
            self.column_footer,
            "SD: Not Set",
            anchor="w",
            label_font=style.giantboldtext,
            background=style.color_1,
            foreground=style.pathdisplaytextcolor)
        self.column_sd_status_label.place(x=style.offset,
                                          relheight=0.5,
                                          rely=0.5,
                                          height=-style.offset,
                                          relwidth=1,
                                          width=-2 * style.offset)

        self.content_frame = ThemedFrame(self)
        self.content_frame.place(x=style.sidecolumnwidth,
                                 width=-style.sidecolumnwidth,
                                 rely=0,
                                 relheight=1,
                                 relwidth=1)

        self.content_frame_header = ThemedFrame(self.content_frame)
        self.content_frame_header.place(relx=0,
                                        rely=0,
                                        relwidth=1,
                                        height=style.searchboxheight)

        self.category_label = ThemedLabel(self.content_frame_header,
                                          "",
                                          anchor="w",
                                          label_font=style.giantboldtext,
                                          background=style.color_1,
                                          foreground=style.lg)
        self.category_label.place(relheight=1,
                                  rely=0.5,
                                  y=-0.5 * style.searchboxheight)

        self.content_frame_header_search_bar = searchBox(
            self.content_frame_header,
            command=self.search,
            entry_background=style.color_2,
            borderwidth=0)

        self.selected_sort_method = tk.StringVar()
        self.selected_sort_method.set(SORT_OPTIONS[0])
        self.content_frame_header_sort_method_dropdown = tk.OptionMenu(
            self.content_frame_header, self.selected_sort_method,
            *SORT_OPTIONS)
        self.content_frame_header_sort_method_dropdown.configure(
            background=style.color_2)
        self.content_frame_header_sort_method_dropdown.configure(
            highlightthickness=0)
        self.content_frame_header_sort_method_dropdown.configure(borderwidth=0)

        #The various content gets stacked on top of each other here.
        self.content_stacking_frame = ThemedFrame(self.content_frame)
        self.content_stacking_frame.place(
            relx=0,
            y=(style.searchboxheight + style.offset),
            relwidth=1,
            relheight=1,
            height=-(style.searchboxheight + style.offset))

        all_frame = categoryFrame(self.content_stacking_frame, self.controller,
                                  self, self.repo_parser.all)
        media_frame = categoryFrame(self.content_stacking_frame,
                                    self.controller, self,
                                    self.repo_parser.media)
        emus_frame = categoryFrame(self.content_stacking_frame,
                                   self.controller, self,
                                   self.repo_parser.emulators)
        games_frame = categoryFrame(self.content_stacking_frame,
                                    self.controller, self,
                                    self.repo_parser.games)
        tools_frame = categoryFrame(self.content_stacking_frame,
                                    self.controller, self,
                                    self.repo_parser.homebrew)
        python_frame = categoryFrame(self.content_stacking_frame,
                                     self.controller, self,
                                     self.repo_parser.nxpythonlist)
        cfw_frame = categoryFrame(self.content_stacking_frame, self.controller,
                                  self, self.repo_parser.customfirmwarelist)
        installed_frame = installed_categoryFrame(self.content_stacking_frame,
                                                  self.controller, self,
                                                  self.repo_parser.all)
        injector_frame = injector_categoryFrame(self.content_stacking_frame,
                                                self.controller, self,
                                                self.repo_parser.payloadlist)
        help_frame = helpFrame(self.content_stacking_frame)
        about_frame = aboutFrame(self.content_stacking_frame)
        readme_frame = readmeFrame(self.content_stacking_frame)

        self.category_frames = [
            all_frame, media_frame, emus_frame, games_frame, tools_frame,
            python_frame, cfw_frame, installed_frame, injector_frame
        ]

        self.frames = [{
            "frame": all_frame,
            "text": "All Apps"
        }, {
            "frame": games_frame,
            "text": "Games"
        }, {
            "frame": emus_frame,
            "text": "Emulators"
        }, {
            "frame": tools_frame,
            "text": "Homebrew"
        }, {
            "frame": media_frame,
            "text": "Media"
        }, {
            "frame": python_frame,
            "text": "Python"
        }, {
            "frame": cfw_frame,
            "text": "Custom Firmware"
        }, {
            "frame": installed_frame,
            "text": "Installed"
        }, {
            "frame": injector_frame,
            "text": "RCM Injector"
        }, {
            "frame": help_frame,
            "text": "HELP"
        }, {
            "frame": about_frame,
            "text": "ABOUT"
        }, {
            "frame": readme_frame,
            "text": "README",
        }]

        #Add pages as frames to dict, with keyword being the name of the frame
        self.content_frames = {}
        for E in self.frames:
            page_name = E["text"]
            frame = E["frame"]
            self.content_frames[page_name] = frame
            frame.place(relx=0, rely=0, relwidth=1, relheight=1)
            self.category_listbox.insert("end", " {}".format(page_name))
        self.category_listbox.select_set(
            0)  #sets focus on the first item in listbox
        self.category_listbox.event_generate("<<ListboxSelect>>")

        self.bind("<<ShowFrame>>", self.reset_selection)

        self.show_frame("All Apps")

        if self.controller.updater.status:
            print(self.controller.updater.status)
            self.yesnoPage = yesnoPage(self)
            self.yesnoPage.getanswer(
                "An update is available, would you like to download it?\nPatch notes:\n{}"
                .format(self.controller.updater.status),
                self.controller.updater.update)

        self.loaded()
        self.add_on_refresh_callback(self.update_sd_path)
        self.sort_check_loop()

    def reset_selection(self, event=None):
        self.category_listbox.select_set(
            self.category_listbox.get(0, "end").index(" {}".format(
                self.current_frame_name)))

    def show_frame(self, page_name):
        #Show a frame for the given page name
        frame = self.content_frames[page_name]
        frame.event_generate("<<ShowFrame>>")
        frame.tkraise()
        self.category_label.set(page_name)
        self.controller.after(100, self.update_search_bar_position)

        for frm in self.category_frames:
            frm.deselect()
        if frame in self.category_frames:
            frame.select()
        self.current_frame = frame
        self.current_frame_name = page_name

    def update_search_bar_position(self):
        if not self.current_frame in self.category_frames:
            self.content_frame_header_search_bar.place_forget()
            self.content_frame_header_sort_method_dropdown.place_forget()
        else:
            category_label_offset = self.category_label.winfo_width()
            #If the category label has been populated, otherwise the offset is usually just a few pixels (prevents an ugly draw on launch)
            if category_label_offset > style.offset:
                self.content_frame_header_sort_method_dropdown.place(
                    relx=1,
                    x=-(style.offset + style.sortdropdownwidth),
                    width=style.sortdropdownwidth,
                    rely=0.5,
                    y=-0.5 * style.searchboxheight + style.offset,
                    relheight=1,
                    height=-2 * style.offset)
                self.content_frame_header_search_bar.place(
                    x=category_label_offset + style.offset,
                    rely=0.5,
                    y=-0.5 * style.searchboxheight + style.offset,
                    relheight=1,
                    relwidth=1,
                    width=-(category_label_offset + 4 * style.offset +
                            style.sortdropdownwidth),
                    height=-2 * style.offset)
            else:
                self.content_frame_header_search_bar.place_forget()
                self.controller.after(100, self.update_search_bar_position)

    def select_frame(self, event):
        try:
            widget = event.widget
            selection = widget.curselection()
            picked = widget.get(selection[0])
            if not picked == self.last_selection:
                frame = None
                for f in self.frames:
                    t = f["text"]
                    if t.strip() == picked.strip():
                        self.show_frame(t)
                        break
                self.last_selection = picked
        except Exception as e:
            # print(e)
            pass

    def search(self, searchterm):
        self.current_frame.search(searchterm)

    def reload_category_frames(self):
        print("Reloading frames")
        for frame in self.category_frames:
            frame.configure(None)

    def set_sd(self):
        chosensdpath = tkinter.filedialog.askdirectory(
            initialdir="/", title='Please select your SD card')
        self.appstore_handler.set_path(chosensdpath)
        self.reload_category_frames()
        self.update_sd_path()

    def update_sd_path(self):
        chosensdpath = self.appstore_handler.check_path()
        if chosensdpath:
            #Get the basename
            basepath = os.path.basename(os.path.normpath(chosensdpath))
            #If we didn't find it, assume it's a root dir and just return the whole path
            if not basepath:
                basepath = chosensdpath
        else:
            basepath = "Not Set"
        self.column_sd_status_label.set("SD: {}".format(basepath))

    def update_sort(self):
        for frame in self.category_frames:
            frame.set_sort_type(SORT_MAP[self.selected_sort_method.get()])
        self.current_frame.rebuild()

    #loop to check if the sorting methog has been applied yet
    def sort_check_loop(self):
        if not self.last_sort_option == self.selected_sort_method.get():
            self.last_sort_option = self.selected_sort_method.get()
            self.update_sort()

        #schedule self
        self.schedule_callback(self.sort_check_loop, 100)