Created
April 11, 2024 00:01
-
-
Save Tajcore/82d643caf6b886bddb49316187a205db to your computer and use it in GitHub Desktop.
main.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
from tkinter import ttk | |
from PIL import Image, ImageTk | |
import json | |
class MainApplication(tk.Tk): | |
def __init__(self, *args, **kwargs): | |
super().__init__(*args, **kwargs) | |
self.title("Hulu Clone") | |
self.geometry("800x600") | |
# Create a main container frame | |
self.container = tk.Frame(self, bg="#101622") | |
self.container.pack(side="top", fill="both", expand=True) | |
# Row 0 will be for the nav bar, with no weight (it shouldn't expand) | |
self.container.grid_rowconfigure(0, weight=0) | |
# Row 1 will be for the content frames, with a weight (it will expand to fill space) | |
self.container.grid_rowconfigure(1, weight=1) | |
self.container.grid_columnconfigure(0, weight=1) | |
# Initialize and stack frames in row 1 | |
self.frames = {} | |
for F in (HomePage, MoviesPage, TVPage): | |
frame = F(self.container) | |
self.frames[F] = frame | |
frame.grid(row=1, column=0, sticky="nsew") | |
# The nav bar is created and placed in row 0 | |
self.content = self.load_content() | |
self.movies = [item for item in self.content if item["category"] == "Movie"] | |
self.tv_shows = [item for item in self.content if item["category"] == "TV Show"] | |
self.create_nav_bar() | |
self.show_frame(HomePage) | |
def load_content(self): | |
try: | |
with open("assets/content.json", "r") as file: # Renamed to content.json | |
return json.load(file) | |
except Exception as e: | |
print(f"Error loading content: {e}") | |
return [] | |
def create_nav_bar(self): | |
style = ttk.Style() | |
style.theme_use("alt") | |
style.configure("TButton", background="#101622", foreground="white") | |
# Top navigation bar in the container frame | |
# Search icon button | |
nav_bar_color = "#101622" | |
top_nav_bar = tk.Frame(self.container, bg=nav_bar_color) | |
top_nav_bar.grid(row=0, column=0, sticky="ew", padx=(5, 5), pady=(20, 20)) | |
search_icon_image = Image.open("assets/icons/search_icon.png").resize( | |
(20, 20), Image.Resampling.LANCZOS | |
) # Adjust path as needed | |
self.search_icon_photo = ImageTk.PhotoImage(search_icon_image) | |
self.search_button = ttk.Button( | |
top_nav_bar, | |
image=self.search_icon_photo, | |
style="TButton", | |
command=self.toggle_search, | |
) | |
self.search_button.pack(side=tk.RIGHT, padx=10) | |
# Hidden search entry | |
self.search_var = tk.StringVar() | |
self.search_entry = tk.Entry( | |
top_nav_bar, textvariable=self.search_var, width=30 | |
) | |
# Hulu logo | |
logo_image = Image.open("assets/logo/hulu.png").resize( | |
(40, 20), Image.Resampling.LANCZOS | |
) | |
logo_photo = ImageTk.PhotoImage(logo_image) | |
logo_label = tk.Label(top_nav_bar, image=logo_photo, bg="#1a1a1a") | |
logo_label.image = logo_photo # Keep a reference | |
logo_label.pack(side=tk.LEFT, padx=10) | |
# Container frame for the navigation buttons, which will be centered | |
self.nav_buttons_frame = tk.Frame(top_nav_bar, bg="#101622") | |
self.nav_buttons_frame.pack(side=tk.LEFT, expand=True) | |
# Navigation buttons inside the container frame | |
self.home_button = ttk.Button( | |
self.nav_buttons_frame, | |
text="Home", | |
style="TButton", | |
command=lambda: self.show_frame(HomePage), | |
) | |
self.home_button.pack(side=tk.LEFT, padx=10) | |
self.tv_button = ttk.Button( | |
self.nav_buttons_frame, | |
text="TV", | |
style="TButton", | |
command=lambda: self.show_frame(TVPage), | |
) | |
self.tv_button.pack(side=tk.LEFT, padx=10) | |
self.movies_button = ttk.Button( | |
self.nav_buttons_frame, | |
text="Movies", | |
style="TButton", | |
command=lambda: self.show_frame(MoviesPage), | |
) | |
self.movies_button.pack(side=tk.LEFT, padx=10) | |
def show_frame(self, cont): | |
"""Show a frame for the given class""" | |
if cont == HomePage: | |
frame = self.frames[HomePage] | |
frame.update_display(self.tv_shows, self.movies) | |
elif cont == MoviesPage: | |
frame = self.frames[MoviesPage] | |
frame.update_display(self.movies) # Update to show only movies | |
elif cont == TVPage: | |
frame = self.frames[TVPage] | |
frame.update_display(self.tv_shows) # Update to show only TV shows | |
frame.tkraise() | |
def toggle_search(self): | |
# Toggle visibility of the search entry | |
if ( | |
self.search_entry.winfo_manager() | |
): # If the entry is already managed by a geometry manager | |
self.search_entry.pack_forget() # Hide the search entry | |
else: | |
self.search_entry.pack( | |
side=tk.RIGHT, padx=10, fill=tk.X | |
) # Show the search entry | |
self.search_entry.focus() # Focus on the entry widget | |
# Bind the update function to the search variable | |
self.search_var.trace( | |
"w", lambda name, index, mode, sv=self.search_var: self.update_search(sv) | |
) | |
def update_search(self, search_var): | |
# Get the current search term | |
search_term = search_var.get().lower() | |
# Filter the movies and tv shows | |
filtered_movies = [ | |
movie for movie in self.movies if search_term in movie["title"].lower() | |
] | |
filtered_tv_shows = [ | |
tv_show | |
for tv_show in self.tv_shows | |
if search_term in tv_show["title"].lower() | |
] | |
# Update the displays | |
self.frames[HomePage].update_display(filtered_tv_shows, filtered_movies) | |
self.frames[MoviesPage].update_display(filtered_movies) | |
self.frames[TVPage].update_display(filtered_tv_shows) | |
class HomePage(tk.Frame): | |
"""HomePage class that displays sections for TV shows and movies""" | |
def __init__(self, master=None, *args, **kwargs): | |
super().__init__(master, *args, **kwargs) | |
self.configure(bg="#2f4b7b") | |
self.movies = [] | |
self.tv_shows = [] | |
self.create_widgets() | |
def create_widgets(self): | |
self.tv_frame = tk.Frame(self, bg="#2f4b7b") | |
self.tv_frame.pack( | |
fill=tk.X, expand=True | |
) # Changed from fill=tk.BOTH to fill=tk.X | |
self.tv_heading = tk.Label( | |
self.tv_frame, | |
text="TV Shows", | |
bg="#2f4b7b", | |
fg="white", | |
font=("Arial", 16), | |
anchor="w", | |
) | |
self.tv_heading.pack(side=tk.TOP, pady=(10, 5), padx=(10, 0), fill=tk.X) | |
self.tv_canvas = tk.Canvas(self.tv_frame, bg="#2f4b7b", highlightthickness=0) | |
self.tv_canvas.pack( | |
side=tk.TOP, fill=tk.X, expand=True | |
) # Changed from fill=tk.BOTH to fill=tk.X | |
# Create a frame for movies and its heading | |
self.movies_frame = tk.Frame(self, bg="#2f4b7b") | |
self.movies_frame.pack( | |
fill=tk.X, expand=True | |
) # Changed from fill=tk.BOTH to fill=tk.X | |
self.movies_heading = tk.Label( | |
self.movies_frame, | |
text="Movies", | |
bg="#2f4b7b", | |
fg="white", | |
font=("Arial", 16), | |
anchor="w", | |
) | |
self.movies_heading.pack(side=tk.TOP, pady=(10, 5), padx=(10, 0), fill=tk.X) | |
self.movies_canvas = tk.Canvas( | |
self.movies_frame, bg="#2f4b7b", highlightthickness=0 | |
) | |
self.movies_canvas.pack(side=tk.TOP, fill=tk.X, expand=True) | |
def update_display(self, tv_shows, movies): | |
# Update the TV shows display | |
self.display_content(self.tv_canvas, tv_shows) | |
# Update the movies display | |
self.display_content(self.movies_canvas, movies) | |
def display_content(self, canvas, content): | |
"""Generic function to display content on a given canvas.""" | |
canvas.delete("all") # Clear the canvas | |
image_references = [] # Keep references to images to avoid garbage collection | |
# Display content in a grid layout | |
for index, item in enumerate(content): | |
row, col = divmod(index, 5) # 5 items per row | |
x, y = (col * 220) + 10, (row * 320) + 10 # Grid position with padding | |
# Load and resize image | |
image_path = f'assets/thumbnails/{item["title"].replace(" ", "_")}.jpg' | |
image = Image.open(image_path).resize((200, 300), Image.Resampling.LANCZOS) | |
photo = ImageTk.PhotoImage(image) | |
# Add image to canvas | |
canvas.create_image(x, y, anchor=tk.NW, image=photo) | |
canvas.create_text( | |
x + 100, | |
y + 310, | |
text=item["title"], | |
fill="white", | |
font=("Arial", 12), | |
anchor=tk.CENTER, | |
) | |
# Keep a reference to the photo | |
image_references.append(photo) | |
# Save image references to the canvas object to ensure they are not garbage collected | |
canvas.image_references = image_references | |
class MoviesPage(tk.Frame): | |
def __init__(self, master=None, *args, **kwargs): | |
super().__init__(master, *args, **kwargs) | |
self.configure(bg="#2f4b7b") | |
self.create_widgets() | |
def create_widgets(self): | |
# Movies heading | |
self.heading_label = tk.Label( | |
self, | |
text="Movies", | |
bg="#2f4b7b", | |
fg="white", | |
font=("Arial", 18), | |
anchor="w", | |
) | |
self.heading_label.pack(side=tk.TOP, fill=tk.X, padx=10, pady=10) | |
self.canvas = tk.Canvas(self, bg="#2f4b7b", highlightthickness=0) | |
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) | |
def update_display(self, movies): | |
self.display_movies(movies) | |
def display_movies(self, movies): | |
"""Display a list of movies on the canvas.""" | |
self.canvas.delete("all") # Clear the canvas | |
image_references = [] # Keep references to images to avoid garbage collection | |
# Display movies in a grid layout | |
for index, movie in enumerate(movies): | |
row, col = divmod(index, 5) # 5 movies per row | |
x, y = (col * 220) + 10, (row * 320) + 10 # Grid position with padding | |
# Load and resize image | |
image_path = f'assets/thumbnails/{movie["title"].replace(" ", "_")}.jpg' | |
image = Image.open(image_path).resize((200, 300), Image.Resampling.LANCZOS) | |
photo = ImageTk.PhotoImage(image) | |
# Add image to canvas | |
self.canvas.create_image(x, y, anchor=tk.NW, image=photo) | |
self.canvas.create_text( | |
x + 100, | |
y + 310, | |
text=movie["title"], | |
fill="white", | |
font=("Arial", 12), | |
anchor=tk.CENTER, | |
) | |
# Keep a reference to the photo | |
image_references.append(photo) | |
# Save image references to the canvas object to ensure they are not garbage collected | |
self.canvas.image_references = image_references | |
def create_search_bar(self): | |
# Search bar frame | |
self.search_bar_frame = tk.Frame(self, bg="#2f4b7b") | |
self.search_bar_frame.pack(side=tk.TOP, fill=tk.X) | |
# Search entry | |
self.search_var = tk.StringVar() | |
self.search_entry = tk.Entry( | |
self.search_bar_frame, textvariable=self.search_var, width=70 | |
) # Adjust width as needed | |
self.search_entry.insert( | |
0, "Search for TV shows and movies" | |
) # Placeholder text | |
self.search_entry.bind( | |
"<FocusIn>", | |
lambda args: ( | |
self.search_entry.delete("0", "end") | |
if self.search_entry.get() == "Search for TV shows and movies" | |
else None | |
), | |
) | |
self.search_entry.pack(side=tk.LEFT, padx=10, pady=5, fill=tk.X, expand=True) | |
# Search button - if you want to include a search button next to the entry | |
self.search_button = ttk.Button( | |
self.search_bar_frame, text="Search", command=self.perform_search | |
) | |
self.search_button.pack(side=tk.RIGHT, padx=10, pady=5) | |
class TVPage(tk.Frame): | |
def __init__(self, master=None, *args, **kwargs): | |
super().__init__(master, *args, **kwargs) | |
self.configure(bg="#2f4b7b") | |
self.create_widgets() | |
def create_widgets(self): | |
# TV Shows heading | |
self.heading_label = tk.Label( | |
self, | |
text="TV Shows", | |
bg="#2f4b7b", | |
fg="white", | |
font=("Arial", 18), | |
anchor="w", | |
) | |
self.heading_label.pack(side=tk.TOP, fill=tk.X, padx=10, pady=10) | |
self.canvas = tk.Canvas(self, bg="#2f4b7b", highlightthickness=0) | |
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=1) | |
def update_display(self, movies): | |
self.display_movies(movies) | |
def display_movies(self, movies): | |
"""Display a list of movies on the canvas.""" | |
self.canvas.delete("all") # Clear the canvas | |
image_references = [] # Keep references to images to avoid garbage collection | |
# Display movies in a grid layout | |
for index, movie in enumerate(movies): | |
row, col = divmod(index, 5) # 5 movies per row | |
x, y = (col * 220) + 10, (row * 320) + 10 # Grid position with padding | |
# Load and resize image | |
image_path = f'assets/thumbnails/{movie["title"].replace(" ", "_")}.jpg' | |
image = Image.open(image_path).resize((200, 300), Image.Resampling.LANCZOS) | |
photo = ImageTk.PhotoImage(image) | |
# Add image to canvas | |
self.canvas.create_image(x, y, anchor=tk.NW, image=photo) | |
self.canvas.create_text( | |
x + 100, | |
y + 310, | |
text=movie["title"], | |
fill="white", | |
font=("Arial", 12), | |
anchor=tk.CENTER, | |
) | |
# Keep a reference to the photo | |
image_references.append(photo) | |
# Save image references to the canvas object to ensure they are not garbage collected | |
self.canvas.image_references = image_references | |
def main(): | |
app = MainApplication() | |
app.mainloop() | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment