Skip to content

Filterspage

FiltersPage

Bases: CTkFrame

Source code in src\gui\filterspage.py
class FiltersPage(ctk.CTkFrame):
    def __init__(self, master: ctk.CTk, search_page: ctk.CTkFrame, **kwargs):
        # main setup
        super().__init__(master, **kwargs)
        self.root = master
        self.search_page = search_page
        self.cur_year = datetime.datetime.now().year
        self.year_list = [str(x) for x in range(2010, self.cur_year + 1)]
        list.reverse(self.year_list)
        self.sqft_list = [sqft.value for sqft in RedfinApi.Sqft]
        list.reverse(self.sqft_list)
        self.sold_within_list = [
            "Last 1 week",
            "Last 1 month",
            "Last 3 months",
            "Last 6 months",
            "Last 1 year",
            "Last 2 years",
            "Last 3 years",
            "Last 5 years",
        ]
        self.price_list = [price.value for price in RedfinApi.Price]
        list.reverse(self.price_list)
        self.create_widgets()
        self.set_default_values()

    def create_widgets(self) -> None:
        """Create widgets."""
        # frames
        self.content_frame = ctk.CTkFrame(self)
        self.for_sale_sold_frame = ctk.CTkFrame(
            self.content_frame, width=300, height=100, fg_color="transparent"
        )
        self.stories_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
        self.year_built_frame = ctk.CTkFrame(
            self.content_frame, corner_radius=0, fg_color="transparent"
        )
        self.home_type_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
        self.square_feet_frame = ctk.CTkFrame(
            self.content_frame, corner_radius=0, fg_color="transparent"
        )
        self.status_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
        self.sold_within_frame = ctk.CTkFrame(
            self.content_frame, fg_color="transparent", corner_radius=0
        )
        self.price_range_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
        self.reset_apply_frame = ctk.CTkFrame(
            self.content_frame, fg_color="transparent", corner_radius=0
        )

        # make more grid
        self.columnconfigure((0, 2), weight=1)
        self.columnconfigure(1, weight=30)
        self.content_frame.columnconfigure(0, weight=1, uniform="a")  # uniform
        self.for_sale_sold_frame.columnconfigure((0, 1), weight=1)
        self.stories_frame.columnconfigure((0, 1), weight=1)
        self.year_built_frame.columnconfigure((0, 1, 2, 3), weight=1)
        self.home_type_frame.columnconfigure((0, 1, 2, 3), weight=1)
        self.square_feet_frame.columnconfigure((0, 1, 2, 3), weight=1)
        self.status_frame.columnconfigure((0, 1, 2), weight=1)
        self.sold_within_frame.columnconfigure((0, 1), weight=1)
        self.price_range_frame.columnconfigure((0, 1, 2, 3), weight=1)
        self.reset_apply_frame.columnconfigure((0, 1), weight=1)

        self.rowconfigure(0, weight=1)
        self.content_frame.rowconfigure(
            (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), weight=1, uniform="a"
        )
        self.for_sale_sold_frame.rowconfigure(0, weight=1)
        self.stories_frame.rowconfigure(0, weight=1)
        self.year_built_frame.rowconfigure((0, 1), weight=1)
        self.home_type_frame.rowconfigure((0, 1, 2), weight=1)
        self.square_feet_frame.rowconfigure((0, 1), weight=1)
        self.status_frame.rowconfigure((0, 1), weight=1)
        self.sold_within_frame.rowconfigure(0, weight=1)
        self.price_range_frame.rowconfigure((0, 1), weight=1)
        self.reset_apply_frame.rowconfigure(0, weight=1)

        # placing the frames
        self.content_frame.grid(row=0, column=1, sticky="ns")
        self.for_sale_sold_frame.grid(row=0, column=0, sticky="nsew")
        self.stories_frame.grid(row=1, column=0, sticky="nesw")
        self.year_built_frame.grid(row=2, column=0, sticky="nesw")
        self.home_type_frame.grid(row=3, column=0, rowspan=2, sticky="nesw")
        self.square_feet_frame.grid(row=5, column=0, sticky="nesw")
        self.status_frame.grid(row=6, column=0)
        self.sold_within_frame.grid(row=7, column=0, sticky="nesw")
        self.price_range_frame.grid(row=8, column=0, rowspan=2, sticky="nesw")
        self.reset_apply_frame.grid(row=10, column=0)

        # Create the labels
        self.for_sale_sold_label = ctk.CTkLabel(
            self.for_sale_sold_frame, text="For Sale/Sold"
        )
        self.stories_label = ctk.CTkLabel(self.stories_frame, text="Stories")
        self.year_built_label = ctk.CTkLabel(self.year_built_frame, text="Year Built")
        self.home_type_label = ctk.CTkLabel(self.home_type_frame, text="Home Type")
        self.sqft_label = ctk.CTkLabel(self.square_feet_frame, text="Square Feet")
        self.sale_status_label = ctk.CTkLabel(self.status_frame, text="Status")
        self.price_range_label = ctk.CTkLabel(
            self.price_range_frame, text="Price Range"
        )
        self.price_range_from_label = ctk.CTkLabel(self.price_range_frame, text="From")
        self.price_range_to_label = ctk.CTkLabel(self.price_range_frame, text="To")
        self.year_built_from_label = ctk.CTkLabel(self.year_built_frame, text="From")
        self.year_built_to_label = ctk.CTkLabel(self.year_built_frame, text="To")
        self.sold_within_label = ctk.CTkLabel(
            self.sold_within_frame, text="Sold Within"
        )
        self.sold_within_from_label = ctk.CTkLabel(self.square_feet_frame, text="From")
        self.sold_within_to_label = ctk.CTkLabel(self.square_feet_frame, text="To")

        # Create the Buttons
        self.for_sale_sold_om = ctk.CTkOptionMenu(
            master=self.for_sale_sold_frame,
            values=[status.value for status in RedfinApi.SoldStatus],
            command=lambda x: self.status_within_activate_deactivate(x),
        )

        self.min_stories_om = ctk.CTkOptionMenu(
            self.stories_frame, values=[story.value for story in RedfinApi.Stories]
        )

        self.min_year_built_om = ctk.CTkOptionMenu(
            self.year_built_frame,
            values=self.year_list,
            command=lambda x: self.year_validation(),
        )

        self.max_year_built_om = ctk.CTkOptionMenu(
            self.year_built_frame,
            values=self.year_list,
            command=lambda x: self.year_validation(),
        )

        self.house_type_house_switch = ctk.CTkSwitch(
            self.home_type_frame,
            text="House",
            command=self.house_type_validation,
        )
        self.house_type_townhouse_switch = ctk.CTkSwitch(
            self.home_type_frame,
            text="Townhouse",
            command=self.house_type_validation,
        )
        self.house_type_condo_switch = ctk.CTkSwitch(
            self.home_type_frame,
            text="Condo",
            command=self.house_type_validation,
        )
        self.house_type_mul_fam_switch = ctk.CTkSwitch(
            self.home_type_frame,
            text="Multi-Family",
            command=self.house_type_validation,
        )

        self.min_sqft_om = ctk.CTkOptionMenu(
            self.square_feet_frame,
            values=self.sqft_list,
            command=lambda x: self.sqft_validation(),
        )
        self.max_sqft_om = ctk.CTkOptionMenu(
            self.square_feet_frame,
            values=self.sqft_list,
            command=lambda x: self.sqft_validation(),
        )
        self.status_coming_soon_chb = ctk.CTkCheckBox(
            self.status_frame, text="Coming soon"
        )
        self.status_active_chb = ctk.CTkCheckBox(self.status_frame, text="Active")
        self.status_pending_chb = ctk.CTkCheckBox(
            self.status_frame, text="Under contract/Pending"
        )  # missing one i think
        self.sold_within_om = ctk.CTkOptionMenu(
            self.sold_within_frame, values=self.sold_within_list
        )

        self.min_price_om = ctk.CTkOptionMenu(
            self.price_range_frame,
            values=self.price_list,
            command=lambda x: self.price_validation(),
        )
        self.max_price_om = ctk.CTkOptionMenu(
            self.price_range_frame,
            values=self.price_list,
            command=lambda x: self.price_validation(),
        )

        self.reset_filters_button = ctk.CTkButton(
            self.reset_apply_frame,
            text="Reset Filters",
            command=self.set_default_values,
        )
        self.apply_filters_button = ctk.CTkButton(
            self.reset_apply_frame,
            text="Apply Filters",
            command=self.change_to_search_page,
        )

        # Placing the widgets
        self.for_sale_sold_label.grid(row=0, column=0)
        self.stories_label.grid(row=0, column=0)
        self.year_built_label.grid(row=0, column=0)
        self.home_type_label.grid(row=0, column=0)
        self.sqft_label.grid(row=0, column=0)
        self.sale_status_label.grid(row=0, column=0)
        self.price_range_label.grid(row=0, column=0)
        self.year_built_from_label.grid(row=1, column=0)
        self.year_built_to_label.grid(row=1, column=2)
        self.price_range_from_label.grid(row=1, column=0)
        self.price_range_to_label.grid(row=1, column=2)
        self.sold_within_label.grid(row=0, column=0)
        self.sold_within_from_label.grid(row=1, column=0)
        self.sold_within_to_label.grid(row=1, column=2)

        self.for_sale_sold_om.grid(row=0, column=1)
        self.min_stories_om.grid(row=0, column=1)
        self.min_year_built_om.grid(row=1, column=1)
        self.max_year_built_om.grid(row=1, column=3)
        self.min_sqft_om.grid(row=1, column=1)
        self.max_sqft_om.grid(row=1, column=3)
        self.sold_within_om.grid(row=0, column=1)
        self.min_price_om.grid(row=1, column=1)
        self.max_price_om.grid(row=1, column=3)
        self.house_type_house_switch.grid(row=1, column=0)
        self.house_type_townhouse_switch.grid(row=1, column=1)
        self.house_type_condo_switch.grid(row=2, column=0)
        self.house_type_mul_fam_switch.grid(row=2, column=1)
        self.status_coming_soon_chb.grid(row=1, column=0)
        self.status_active_chb.grid(row=1, column=1)
        self.status_pending_chb.grid(row=1, column=2)
        self.reset_filters_button.grid(row=0, column=0, sticky="w")
        self.apply_filters_button.grid(row=0, column=1, sticky="e")

    def set_default_values(self) -> None:
        """Set the default values for all widgets.
        Note:
            Should be called after init and when clicking reset button.
        """
        self.for_sale_sold_om.set(RedfinApi.SoldStatus.SOLD.value)
        self.min_stories_om.set(RedfinApi.Stories.ONE.value)
        self.min_year_built_om.set(str(self.cur_year - 1))
        self.max_year_built_om.set(str(self.cur_year - 1))
        self.sold_within_om.set(self.sold_within_list[-1])
        self.max_price_om.set(RedfinApi.Price.NONE.value)
        self.min_price_om.set(RedfinApi.Price.NONE.value)
        self.max_sqft_om.set(RedfinApi.Sqft.NONE.value)
        self.min_sqft_om.set(RedfinApi.Sqft.NONE.value)
        self.status_active_chb.deselect()
        self.status_pending_chb.deselect()
        self.status_coming_soon_chb.deselect()
        self.house_type_house_switch.select()
        self.house_type_condo_switch.deselect()
        self.house_type_townhouse_switch.deselect()
        self.house_type_mul_fam_switch.deselect()
        self.status_within_activate_deactivate(self.for_sale_sold_om.get())

    def status_within_activate_deactivate(self, status) -> None:
        """Deactivate or activate the status and sold within sections, since they depend on what type of sale a house is being searched with.

        Args:
            status (Event): ignored
        """
        match self.for_sale_sold_om.get():
            case RedfinApi.SoldStatus.FOR_SALE.value:
                self.sale_status_label.configure(state="normal")
                self.status_active_chb.configure(state="normal")
                self.status_coming_soon_chb.configure(state="normal")
                self.status_pending_chb.configure(state="normal")
                self.sold_within_label.configure(state="disabled")
                self.sold_within_om.configure(state="disabled")
            case RedfinApi.SoldStatus.SOLD.value:
                self.sale_status_label.configure(state="disabled")
                self.status_active_chb.configure(state="disabled")
                self.status_coming_soon_chb.configure(state="disabled")
                self.status_pending_chb.configure(state="disabled")
                self.sold_within_label.configure(state="normal")
                self.sold_within_om.configure(state="normal")
                self.status_active_chb.deselect()
                self.status_pending_chb.deselect()
                self.status_coming_soon_chb.deselect()

    def change_to_search_page(self) -> None:
        """Change to search page."""
        self.grid_remove()
        self.search_page.grid()

    def price_validation(self):
        """Called when price range min om gets changed"""
        if (
            self.max_price_om.get() == RedfinApi.Price.NONE.value
            or self.min_price_om.get() == RedfinApi.Price.NONE.value
        ):
            return
        if int(self.max_price_om.get()) < int(self.min_price_om.get()):
            self.max_price_om.set(self.min_price_om.get())

    def year_validation(self) -> None:
        """Year drop down callback"""
        if int(self.max_year_built_om.get()) < int(self.min_year_built_om.get()):
            self.max_year_built_om.set(self.min_year_built_om.get())

    def sqft_validation(self) -> None:
        """Sqft dropdown callback"""
        if (
            self.max_sqft_om.get() == RedfinApi.Sqft.NONE.value
            or self.min_sqft_om.get() == RedfinApi.Sqft.NONE.value
        ):
            return
        if int(self.max_sqft_om.get()) < int(self.min_sqft_om.get()):
            self.max_sqft_om.set(self.min_sqft_om.get())

    def house_type_validation(self) -> None:
        """House type switch validation to make sure at lest house is selected."""
        if not any(
            [
                self.house_type_house_switch.get(),
                self.house_type_condo_switch.get(),
                self.house_type_mul_fam_switch.get(),
                self.house_type_townhouse_switch.get(),
            ]
        ):
            self.house_type_house_switch.select()

    def get_values(self) -> dict[str, Any]:
        """Get the values of all widgets on this page.

        Returns:
            dict[str, Any]: dict of values
        """
        match self.sold_within_om.get():
            case "Last 1 week":
                sold_within_days = RedfinApi.SoldWithinDays.ONE_WEEK
            case "Last 1 month":
                sold_within_days = RedfinApi.SoldWithinDays.ONE_MONTH
            case "Last 3 months":
                sold_within_days = RedfinApi.SoldWithinDays.THREE_MONTHS
            case "Last 6 months":
                sold_within_days = RedfinApi.SoldWithinDays.SIX_MONTHS
            case "Last 1 year":
                sold_within_days = RedfinApi.SoldWithinDays.ONE_YEAR
            case "Last 2 years":
                sold_within_days = RedfinApi.SoldWithinDays.TWO_YEARS
            case "Last 3 years":
                sold_within_days = RedfinApi.SoldWithinDays.THREE_YEARS
            case _:
                sold_within_days = RedfinApi.SoldWithinDays.FIVE_YEARS

        return {
            "for sale sold": self.for_sale_sold_om.get(),
            "min stories": self.min_stories_om.get(),
            "max year built": self.max_year_built_om.get(),  # do validation here
            "min year built": self.min_year_built_om.get(),
            "sold within": sold_within_days.value,
            "status active": bool(self.status_active_chb.get()),
            "status coming soon": bool(self.status_coming_soon_chb.get()),
            "status pending": bool(self.status_pending_chb.get()),
            "house type house": bool(self.house_type_house_switch.get()),
            "house type townhouse": bool(self.house_type_townhouse_switch.get()),
            "house type mul fam": bool(self.house_type_mul_fam_switch.get()),
            "house type condo": bool(self.house_type_condo_switch.get()),
            "max sqft": self.max_sqft_om.get(),
            "min sqft": self.min_sqft_om.get(),
            "max price": self.max_price_om.get(),
            "min price": self.min_price_om.get(),
        }

change_to_search_page()

Change to search page.

Source code in src\gui\filterspage.py
def change_to_search_page(self) -> None:
    """Change to search page."""
    self.grid_remove()
    self.search_page.grid()

create_widgets()

Create widgets.

Source code in src\gui\filterspage.py
def create_widgets(self) -> None:
    """Create widgets."""
    # frames
    self.content_frame = ctk.CTkFrame(self)
    self.for_sale_sold_frame = ctk.CTkFrame(
        self.content_frame, width=300, height=100, fg_color="transparent"
    )
    self.stories_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
    self.year_built_frame = ctk.CTkFrame(
        self.content_frame, corner_radius=0, fg_color="transparent"
    )
    self.home_type_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
    self.square_feet_frame = ctk.CTkFrame(
        self.content_frame, corner_radius=0, fg_color="transparent"
    )
    self.status_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
    self.sold_within_frame = ctk.CTkFrame(
        self.content_frame, fg_color="transparent", corner_radius=0
    )
    self.price_range_frame = ctk.CTkFrame(self.content_frame, corner_radius=0)
    self.reset_apply_frame = ctk.CTkFrame(
        self.content_frame, fg_color="transparent", corner_radius=0
    )

    # make more grid
    self.columnconfigure((0, 2), weight=1)
    self.columnconfigure(1, weight=30)
    self.content_frame.columnconfigure(0, weight=1, uniform="a")  # uniform
    self.for_sale_sold_frame.columnconfigure((0, 1), weight=1)
    self.stories_frame.columnconfigure((0, 1), weight=1)
    self.year_built_frame.columnconfigure((0, 1, 2, 3), weight=1)
    self.home_type_frame.columnconfigure((0, 1, 2, 3), weight=1)
    self.square_feet_frame.columnconfigure((0, 1, 2, 3), weight=1)
    self.status_frame.columnconfigure((0, 1, 2), weight=1)
    self.sold_within_frame.columnconfigure((0, 1), weight=1)
    self.price_range_frame.columnconfigure((0, 1, 2, 3), weight=1)
    self.reset_apply_frame.columnconfigure((0, 1), weight=1)

    self.rowconfigure(0, weight=1)
    self.content_frame.rowconfigure(
        (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), weight=1, uniform="a"
    )
    self.for_sale_sold_frame.rowconfigure(0, weight=1)
    self.stories_frame.rowconfigure(0, weight=1)
    self.year_built_frame.rowconfigure((0, 1), weight=1)
    self.home_type_frame.rowconfigure((0, 1, 2), weight=1)
    self.square_feet_frame.rowconfigure((0, 1), weight=1)
    self.status_frame.rowconfigure((0, 1), weight=1)
    self.sold_within_frame.rowconfigure(0, weight=1)
    self.price_range_frame.rowconfigure((0, 1), weight=1)
    self.reset_apply_frame.rowconfigure(0, weight=1)

    # placing the frames
    self.content_frame.grid(row=0, column=1, sticky="ns")
    self.for_sale_sold_frame.grid(row=0, column=0, sticky="nsew")
    self.stories_frame.grid(row=1, column=0, sticky="nesw")
    self.year_built_frame.grid(row=2, column=0, sticky="nesw")
    self.home_type_frame.grid(row=3, column=0, rowspan=2, sticky="nesw")
    self.square_feet_frame.grid(row=5, column=0, sticky="nesw")
    self.status_frame.grid(row=6, column=0)
    self.sold_within_frame.grid(row=7, column=0, sticky="nesw")
    self.price_range_frame.grid(row=8, column=0, rowspan=2, sticky="nesw")
    self.reset_apply_frame.grid(row=10, column=0)

    # Create the labels
    self.for_sale_sold_label = ctk.CTkLabel(
        self.for_sale_sold_frame, text="For Sale/Sold"
    )
    self.stories_label = ctk.CTkLabel(self.stories_frame, text="Stories")
    self.year_built_label = ctk.CTkLabel(self.year_built_frame, text="Year Built")
    self.home_type_label = ctk.CTkLabel(self.home_type_frame, text="Home Type")
    self.sqft_label = ctk.CTkLabel(self.square_feet_frame, text="Square Feet")
    self.sale_status_label = ctk.CTkLabel(self.status_frame, text="Status")
    self.price_range_label = ctk.CTkLabel(
        self.price_range_frame, text="Price Range"
    )
    self.price_range_from_label = ctk.CTkLabel(self.price_range_frame, text="From")
    self.price_range_to_label = ctk.CTkLabel(self.price_range_frame, text="To")
    self.year_built_from_label = ctk.CTkLabel(self.year_built_frame, text="From")
    self.year_built_to_label = ctk.CTkLabel(self.year_built_frame, text="To")
    self.sold_within_label = ctk.CTkLabel(
        self.sold_within_frame, text="Sold Within"
    )
    self.sold_within_from_label = ctk.CTkLabel(self.square_feet_frame, text="From")
    self.sold_within_to_label = ctk.CTkLabel(self.square_feet_frame, text="To")

    # Create the Buttons
    self.for_sale_sold_om = ctk.CTkOptionMenu(
        master=self.for_sale_sold_frame,
        values=[status.value for status in RedfinApi.SoldStatus],
        command=lambda x: self.status_within_activate_deactivate(x),
    )

    self.min_stories_om = ctk.CTkOptionMenu(
        self.stories_frame, values=[story.value for story in RedfinApi.Stories]
    )

    self.min_year_built_om = ctk.CTkOptionMenu(
        self.year_built_frame,
        values=self.year_list,
        command=lambda x: self.year_validation(),
    )

    self.max_year_built_om = ctk.CTkOptionMenu(
        self.year_built_frame,
        values=self.year_list,
        command=lambda x: self.year_validation(),
    )

    self.house_type_house_switch = ctk.CTkSwitch(
        self.home_type_frame,
        text="House",
        command=self.house_type_validation,
    )
    self.house_type_townhouse_switch = ctk.CTkSwitch(
        self.home_type_frame,
        text="Townhouse",
        command=self.house_type_validation,
    )
    self.house_type_condo_switch = ctk.CTkSwitch(
        self.home_type_frame,
        text="Condo",
        command=self.house_type_validation,
    )
    self.house_type_mul_fam_switch = ctk.CTkSwitch(
        self.home_type_frame,
        text="Multi-Family",
        command=self.house_type_validation,
    )

    self.min_sqft_om = ctk.CTkOptionMenu(
        self.square_feet_frame,
        values=self.sqft_list,
        command=lambda x: self.sqft_validation(),
    )
    self.max_sqft_om = ctk.CTkOptionMenu(
        self.square_feet_frame,
        values=self.sqft_list,
        command=lambda x: self.sqft_validation(),
    )
    self.status_coming_soon_chb = ctk.CTkCheckBox(
        self.status_frame, text="Coming soon"
    )
    self.status_active_chb = ctk.CTkCheckBox(self.status_frame, text="Active")
    self.status_pending_chb = ctk.CTkCheckBox(
        self.status_frame, text="Under contract/Pending"
    )  # missing one i think
    self.sold_within_om = ctk.CTkOptionMenu(
        self.sold_within_frame, values=self.sold_within_list
    )

    self.min_price_om = ctk.CTkOptionMenu(
        self.price_range_frame,
        values=self.price_list,
        command=lambda x: self.price_validation(),
    )
    self.max_price_om = ctk.CTkOptionMenu(
        self.price_range_frame,
        values=self.price_list,
        command=lambda x: self.price_validation(),
    )

    self.reset_filters_button = ctk.CTkButton(
        self.reset_apply_frame,
        text="Reset Filters",
        command=self.set_default_values,
    )
    self.apply_filters_button = ctk.CTkButton(
        self.reset_apply_frame,
        text="Apply Filters",
        command=self.change_to_search_page,
    )

    # Placing the widgets
    self.for_sale_sold_label.grid(row=0, column=0)
    self.stories_label.grid(row=0, column=0)
    self.year_built_label.grid(row=0, column=0)
    self.home_type_label.grid(row=0, column=0)
    self.sqft_label.grid(row=0, column=0)
    self.sale_status_label.grid(row=0, column=0)
    self.price_range_label.grid(row=0, column=0)
    self.year_built_from_label.grid(row=1, column=0)
    self.year_built_to_label.grid(row=1, column=2)
    self.price_range_from_label.grid(row=1, column=0)
    self.price_range_to_label.grid(row=1, column=2)
    self.sold_within_label.grid(row=0, column=0)
    self.sold_within_from_label.grid(row=1, column=0)
    self.sold_within_to_label.grid(row=1, column=2)

    self.for_sale_sold_om.grid(row=0, column=1)
    self.min_stories_om.grid(row=0, column=1)
    self.min_year_built_om.grid(row=1, column=1)
    self.max_year_built_om.grid(row=1, column=3)
    self.min_sqft_om.grid(row=1, column=1)
    self.max_sqft_om.grid(row=1, column=3)
    self.sold_within_om.grid(row=0, column=1)
    self.min_price_om.grid(row=1, column=1)
    self.max_price_om.grid(row=1, column=3)
    self.house_type_house_switch.grid(row=1, column=0)
    self.house_type_townhouse_switch.grid(row=1, column=1)
    self.house_type_condo_switch.grid(row=2, column=0)
    self.house_type_mul_fam_switch.grid(row=2, column=1)
    self.status_coming_soon_chb.grid(row=1, column=0)
    self.status_active_chb.grid(row=1, column=1)
    self.status_pending_chb.grid(row=1, column=2)
    self.reset_filters_button.grid(row=0, column=0, sticky="w")
    self.apply_filters_button.grid(row=0, column=1, sticky="e")

get_values()

Get the values of all widgets on this page.

Returns:

Type Description
dict[str, Any]

dict[str, Any]: dict of values

Source code in src\gui\filterspage.py
def get_values(self) -> dict[str, Any]:
    """Get the values of all widgets on this page.

    Returns:
        dict[str, Any]: dict of values
    """
    match self.sold_within_om.get():
        case "Last 1 week":
            sold_within_days = RedfinApi.SoldWithinDays.ONE_WEEK
        case "Last 1 month":
            sold_within_days = RedfinApi.SoldWithinDays.ONE_MONTH
        case "Last 3 months":
            sold_within_days = RedfinApi.SoldWithinDays.THREE_MONTHS
        case "Last 6 months":
            sold_within_days = RedfinApi.SoldWithinDays.SIX_MONTHS
        case "Last 1 year":
            sold_within_days = RedfinApi.SoldWithinDays.ONE_YEAR
        case "Last 2 years":
            sold_within_days = RedfinApi.SoldWithinDays.TWO_YEARS
        case "Last 3 years":
            sold_within_days = RedfinApi.SoldWithinDays.THREE_YEARS
        case _:
            sold_within_days = RedfinApi.SoldWithinDays.FIVE_YEARS

    return {
        "for sale sold": self.for_sale_sold_om.get(),
        "min stories": self.min_stories_om.get(),
        "max year built": self.max_year_built_om.get(),  # do validation here
        "min year built": self.min_year_built_om.get(),
        "sold within": sold_within_days.value,
        "status active": bool(self.status_active_chb.get()),
        "status coming soon": bool(self.status_coming_soon_chb.get()),
        "status pending": bool(self.status_pending_chb.get()),
        "house type house": bool(self.house_type_house_switch.get()),
        "house type townhouse": bool(self.house_type_townhouse_switch.get()),
        "house type mul fam": bool(self.house_type_mul_fam_switch.get()),
        "house type condo": bool(self.house_type_condo_switch.get()),
        "max sqft": self.max_sqft_om.get(),
        "min sqft": self.min_sqft_om.get(),
        "max price": self.max_price_om.get(),
        "min price": self.min_price_om.get(),
    }

house_type_validation()

House type switch validation to make sure at lest house is selected.

Source code in src\gui\filterspage.py
def house_type_validation(self) -> None:
    """House type switch validation to make sure at lest house is selected."""
    if not any(
        [
            self.house_type_house_switch.get(),
            self.house_type_condo_switch.get(),
            self.house_type_mul_fam_switch.get(),
            self.house_type_townhouse_switch.get(),
        ]
    ):
        self.house_type_house_switch.select()

price_validation()

Called when price range min om gets changed

Source code in src\gui\filterspage.py
def price_validation(self):
    """Called when price range min om gets changed"""
    if (
        self.max_price_om.get() == RedfinApi.Price.NONE.value
        or self.min_price_om.get() == RedfinApi.Price.NONE.value
    ):
        return
    if int(self.max_price_om.get()) < int(self.min_price_om.get()):
        self.max_price_om.set(self.min_price_om.get())

set_default_values()

Set the default values for all widgets. Note: Should be called after init and when clicking reset button.

Source code in src\gui\filterspage.py
def set_default_values(self) -> None:
    """Set the default values for all widgets.
    Note:
        Should be called after init and when clicking reset button.
    """
    self.for_sale_sold_om.set(RedfinApi.SoldStatus.SOLD.value)
    self.min_stories_om.set(RedfinApi.Stories.ONE.value)
    self.min_year_built_om.set(str(self.cur_year - 1))
    self.max_year_built_om.set(str(self.cur_year - 1))
    self.sold_within_om.set(self.sold_within_list[-1])
    self.max_price_om.set(RedfinApi.Price.NONE.value)
    self.min_price_om.set(RedfinApi.Price.NONE.value)
    self.max_sqft_om.set(RedfinApi.Sqft.NONE.value)
    self.min_sqft_om.set(RedfinApi.Sqft.NONE.value)
    self.status_active_chb.deselect()
    self.status_pending_chb.deselect()
    self.status_coming_soon_chb.deselect()
    self.house_type_house_switch.select()
    self.house_type_condo_switch.deselect()
    self.house_type_townhouse_switch.deselect()
    self.house_type_mul_fam_switch.deselect()
    self.status_within_activate_deactivate(self.for_sale_sold_om.get())

sqft_validation()

Sqft dropdown callback

Source code in src\gui\filterspage.py
def sqft_validation(self) -> None:
    """Sqft dropdown callback"""
    if (
        self.max_sqft_om.get() == RedfinApi.Sqft.NONE.value
        or self.min_sqft_om.get() == RedfinApi.Sqft.NONE.value
    ):
        return
    if int(self.max_sqft_om.get()) < int(self.min_sqft_om.get()):
        self.max_sqft_om.set(self.min_sqft_om.get())

status_within_activate_deactivate(status)

Deactivate or activate the status and sold within sections, since they depend on what type of sale a house is being searched with.

Parameters:

Name Type Description Default
status Event

ignored

required
Source code in src\gui\filterspage.py
def status_within_activate_deactivate(self, status) -> None:
    """Deactivate or activate the status and sold within sections, since they depend on what type of sale a house is being searched with.

    Args:
        status (Event): ignored
    """
    match self.for_sale_sold_om.get():
        case RedfinApi.SoldStatus.FOR_SALE.value:
            self.sale_status_label.configure(state="normal")
            self.status_active_chb.configure(state="normal")
            self.status_coming_soon_chb.configure(state="normal")
            self.status_pending_chb.configure(state="normal")
            self.sold_within_label.configure(state="disabled")
            self.sold_within_om.configure(state="disabled")
        case RedfinApi.SoldStatus.SOLD.value:
            self.sale_status_label.configure(state="disabled")
            self.status_active_chb.configure(state="disabled")
            self.status_coming_soon_chb.configure(state="disabled")
            self.status_pending_chb.configure(state="disabled")
            self.sold_within_label.configure(state="normal")
            self.sold_within_om.configure(state="normal")
            self.status_active_chb.deselect()
            self.status_pending_chb.deselect()
            self.status_coming_soon_chb.deselect()

year_validation()

Year drop down callback

Source code in src\gui\filterspage.py
def year_validation(self) -> None:
    """Year drop down callback"""
    if int(self.max_year_built_om.get()) < int(self.min_year_built_om.get()):
        self.max_year_built_om.set(self.min_year_built_om.get())