diff --git a/messenger_app/api/v1/endpoints/auth/login.py b/messenger_app/api/v1/endpoints/auth/login.py index 21f1d42..8a9bff0 100644 --- a/messenger_app/api/v1/endpoints/auth/login.py +++ b/messenger_app/api/v1/endpoints/auth/login.py @@ -8,6 +8,14 @@ async def login(login_info: Login): if not result: raise HTTPException(status_code=404, detail='User not in system.') - password, email = result[2], result[3] + id, username, password, email = result[0], result[1], result[2], result[3] if login_info.email != email or login_info.password != password: raise HTTPException(status_code=401, detail="Invalid credentials.") + + return { + 'info': { + 'id': id, + 'username': username, + 'email': email, + } + } diff --git a/messenger_app/api/v1/endpoints/auth/signup.py b/messenger_app/api/v1/endpoints/auth/signup.py index 67b529c..f021b67 100644 --- a/messenger_app/api/v1/endpoints/auth/signup.py +++ b/messenger_app/api/v1/endpoints/auth/signup.py @@ -8,6 +8,12 @@ async def signup(user: User): if result: raise HTTPException(status_code=409, detail='User already exists.') - print(user.username, user.email, user.password) - create_user_db(username=user.username, password=user.password, email=user.email) + user_info = get_user_by_email(user.email) + return { + 'info': { + 'id': user_info[0], + 'username': user.username, + 'email': user.email, + } + } diff --git a/messenger_app/api/v1/endpoints/messages/__init__.py b/messenger_app/api/v1/endpoints/messages/__init__.py index f0a88c7..6bc83ab 100644 --- a/messenger_app/api/v1/endpoints/messages/__init__.py +++ b/messenger_app/api/v1/endpoints/messages/__init__.py @@ -1,11 +1,17 @@ from fastapi import APIRouter from .send import send from .get_conversation import get_conversation +from .get_conversation_url import get_conversation_url from app.models import Message router = APIRouter() +@router.get("/get_conversation_url/{id_user1}/{id_user2}") +async def get_conversation_url_router(id_user1: str, id_user2: str): + return await get_conversation_url(id_user1, id_user2) + + @router.post("/send") async def send_router(message: Message): return await send(message) diff --git a/messenger_app/api/v1/endpoints/messages/__pycache__/__init__.cpython-310.pyc b/messenger_app/api/v1/endpoints/messages/__pycache__/__init__.cpython-310.pyc index 88d817c..ed97ff2 100644 Binary files a/messenger_app/api/v1/endpoints/messages/__pycache__/__init__.cpython-310.pyc and b/messenger_app/api/v1/endpoints/messages/__pycache__/__init__.cpython-310.pyc differ diff --git a/messenger_app/api/v1/endpoints/messages/__pycache__/get_conversation.cpython-310.pyc b/messenger_app/api/v1/endpoints/messages/__pycache__/get_conversation.cpython-310.pyc index 126f33a..e1e254c 100644 Binary files a/messenger_app/api/v1/endpoints/messages/__pycache__/get_conversation.cpython-310.pyc and b/messenger_app/api/v1/endpoints/messages/__pycache__/get_conversation.cpython-310.pyc differ diff --git a/messenger_app/api/v1/endpoints/messages/__pycache__/send.cpython-310.pyc b/messenger_app/api/v1/endpoints/messages/__pycache__/send.cpython-310.pyc index 2ab03f2..9fa2b1f 100644 Binary files a/messenger_app/api/v1/endpoints/messages/__pycache__/send.cpython-310.pyc and b/messenger_app/api/v1/endpoints/messages/__pycache__/send.cpython-310.pyc differ diff --git a/messenger_app/api/v1/endpoints/messages/get_conversation.py b/messenger_app/api/v1/endpoints/messages/get_conversation.py index 1a76144..032536b 100644 --- a/messenger_app/api/v1/endpoints/messages/get_conversation.py +++ b/messenger_app/api/v1/endpoints/messages/get_conversation.py @@ -1,9 +1,9 @@ from fastapi import HTTPException, status -from database.queries.messages import find_conversation +from database.queries.messages import find_conversation_db async def get_conversation(conversation_url: str): - conversation = find_conversation(conversation_url) + conversation = find_conversation_db(conversation_url) if conversation is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Conversation not found") return conversation diff --git a/messenger_app/api/v1/endpoints/messages/get_conversation_url.py b/messenger_app/api/v1/endpoints/messages/get_conversation_url.py new file mode 100644 index 0000000..7bead34 --- /dev/null +++ b/messenger_app/api/v1/endpoints/messages/get_conversation_url.py @@ -0,0 +1,11 @@ +from database.queries.messages import get_conversation_url_db +from database.queries.user import get_user_by_id +from fastapi import HTTPException + + +async def get_conversation_url(id_user1: str, id_user2: str): + if get_user_by_id(id_user1) is None or get_user_by_id(id_user2) is None: + raise HTTPException(status_code=404, detail="Users not in the system.") + + conversation_url = get_conversation_url_db(id_user1, id_user2) + return {'conversation_url': conversation_url} diff --git a/messenger_app/api/v1/endpoints/messages/send.py b/messenger_app/api/v1/endpoints/messages/send.py index beea570..023914a 100644 --- a/messenger_app/api/v1/endpoints/messages/send.py +++ b/messenger_app/api/v1/endpoints/messages/send.py @@ -1,17 +1,12 @@ from fastapi import HTTPException from app.models import Message -from database.queries.messages import create_conversation, send_message_to_mongodb +from database.queries.messages import send_message_db async def send(message: Message): - conversation_url = create_conversation(message.sender, message.receiver) + success = send_message_db(message) - if conversation_url is not None: - success = send_message_to_mongodb(conversation_url, message.sender, message.conversation) - - if success: - return {"success": True, "message": "Message sent successfully"} - raise HTTPException(status_code=500, detail="Internal Server Error") - - raise HTTPException(status_code=500, detail="Error creating conversation") + if success: + return {"success": True, "message": "Message sent successfully"} + raise HTTPException(status_code=500, detail="Internal Server Error") diff --git a/messenger_app/api/v1/endpoints/users/__init__.py b/messenger_app/api/v1/endpoints/users/__init__.py index 2c4a38e..38f3693 100644 --- a/messenger_app/api/v1/endpoints/users/__init__.py +++ b/messenger_app/api/v1/endpoints/users/__init__.py @@ -3,10 +3,16 @@ from app.models import User from .create import create_user from .update import update_user from .delete import delete_user +from .get_all import get_all_users router = APIRouter() +@router.get("/get_all") +async def get_all_router(): + return await get_all_users() + + @router.post("/create") async def create_user_router(user: User): return await create_user(user) diff --git a/messenger_app/api/v1/endpoints/users/__pycache__/__init__.cpython-310.pyc b/messenger_app/api/v1/endpoints/users/__pycache__/__init__.cpython-310.pyc index 4c27a3c..65c93d6 100644 Binary files a/messenger_app/api/v1/endpoints/users/__pycache__/__init__.cpython-310.pyc and b/messenger_app/api/v1/endpoints/users/__pycache__/__init__.cpython-310.pyc differ diff --git a/messenger_app/api/v1/endpoints/users/get_all.py b/messenger_app/api/v1/endpoints/users/get_all.py new file mode 100644 index 0000000..d880495 --- /dev/null +++ b/messenger_app/api/v1/endpoints/users/get_all.py @@ -0,0 +1,6 @@ +from database.queries.user import get_all_users_db + + +async def get_all_users(): + users = get_all_users_db() + return users \ No newline at end of file diff --git a/messenger_app/app/models/__pycache__/message.cpython-310.pyc b/messenger_app/app/models/__pycache__/message.cpython-310.pyc index 9f35ac2..ba8040a 100644 Binary files a/messenger_app/app/models/__pycache__/message.cpython-310.pyc and b/messenger_app/app/models/__pycache__/message.cpython-310.pyc differ diff --git a/messenger_app/app/models/message.py b/messenger_app/app/models/message.py index 994ee8d..f208f49 100644 --- a/messenger_app/app/models/message.py +++ b/messenger_app/app/models/message.py @@ -3,7 +3,7 @@ from datetime import datetime class Message(BaseModel): - conversation: str + conversation_url: str + message: str sender: int - receiver: int - timestamp: datetime + message_type: str diff --git a/messenger_app/database/queries/__pycache__/messages.cpython-310.pyc b/messenger_app/database/queries/__pycache__/messages.cpython-310.pyc index d76d219..f3f1091 100644 Binary files a/messenger_app/database/queries/__pycache__/messages.cpython-310.pyc and b/messenger_app/database/queries/__pycache__/messages.cpython-310.pyc differ diff --git a/messenger_app/database/queries/__pycache__/user.cpython-310.pyc b/messenger_app/database/queries/__pycache__/user.cpython-310.pyc index ceee7a0..bce6b7e 100644 Binary files a/messenger_app/database/queries/__pycache__/user.cpython-310.pyc and b/messenger_app/database/queries/__pycache__/user.cpython-310.pyc differ diff --git a/messenger_app/database/queries/messages.py b/messenger_app/database/queries/messages.py index d0e4214..35060ba 100644 --- a/messenger_app/database/queries/messages.py +++ b/messenger_app/database/queries/messages.py @@ -1,34 +1,25 @@ +from app.models import Message from database import postgresql_db_handler, mongo_db_handler import uuid from datetime import datetime -def create_conversation(user1_id, user2_id): +def create_conversation_db(user1_id, user2_id): + current_datetime = datetime.now().strftime("%Y%m%d%H%M%S") + unique_id = str(uuid.uuid4()).replace('-', '') + conversation_url = f"{current_datetime}_{unique_id}" + query = ''' - SELECT conversation_url FROM conversations - WHERE id_user1 = %s AND id_user2 = %s + INSERT INTO conversations (id_user1, id_user2, conversation_url) + VALUES (%s, %s, %s) ''' - params = (user1_id, user2_id) - existing_conversation = postgresql_db_handler.execute_query(query, params, fetchall=True) - - if existing_conversation: - conversation_url = existing_conversation[0][0] - else: - current_datetime = datetime.now().strftime("%Y%m%d%H%M%S") - unique_id = str(uuid.uuid4()).replace('-', '') - conversation_url = f"{current_datetime}_{unique_id}" - - query = ''' - INSERT INTO conversations (id_user1, id_user2, conversation_url) - VALUES (%s, %s, %s) - ''' - params = (user1_id, user2_id, conversation_url) - postgresql_db_handler.execute_query(query, params) + params = (user1_id, user2_id, conversation_url) + postgresql_db_handler.execute_query(query, params) return conversation_url -def find_conversation(conversation_url): +def find_conversation_db(conversation_url): collection = mongo_db_handler.get_collection() query = {'name': conversation_url} result_set = collection.find_one(query) @@ -38,21 +29,40 @@ def find_conversation(conversation_url): return None -def send_message_to_mongodb(conversation_url, sender, message): +def get_conversation_url_db(id_user1, id_user2): + query = """ + SELECT * FROM conversations + WHERE + (id_user1 = %s AND id_user2 = %s) + OR + (id_user1 = %s AND id_user2 = %s) + """ + params = (id_user1, id_user2, id_user2, id_user1) + + result = postgresql_db_handler.execute_query(query, params, fetchall=True) + if not result: + return create_conversation_db(id_user1, id_user2) + else: + return result[0][2] + + +def send_message_db(message: Message): try: collection = mongo_db_handler.get_collection() - existing_document = collection.find_one({"name": conversation_url}) + existing_document = collection.find_one({"name": message.conversation_url}) if existing_document is not None: - new_message = {"sender": sender, "message": message, "timestamp": datetime.now()} + new_message = {"sender": message.sender, "message": message.message, + "message_type": message.message_type, "timestamp": datetime.now()} collection.update_one( - {"name": conversation_url}, + {"name": message.conversation_url}, {"$push": {"chat": new_message}} ) else: collection.insert_one({ - "name": conversation_url, - "chat": [{"sender": sender, "message": message, "timestamp": datetime.now()}] + "name": message.conversation_url, + "chat": [{"sender": message.sender, "message": message.message, + "message_type": message.message_type, "timestamp": datetime.now()}] }) return True diff --git a/messenger_app/database/queries/user.py b/messenger_app/database/queries/user.py index 230fda7..6449d77 100644 --- a/messenger_app/database/queries/user.py +++ b/messenger_app/database/queries/user.py @@ -54,3 +54,9 @@ def delete_user_db(user_id): params = (user_id,) postgresql_db_handler.execute_query(query, params) print(f"User with ID {user_id} deleted successfully.") + + +def get_all_users_db(): + query = "SELECT * FROM users;" + users = postgresql_db_handler.execute_query(query, fetchall=True) + return {"users": users} diff --git a/messenger_gui/app/main.py b/messenger_gui/app/main.py index 41f4c29..1cd0ec3 100644 --- a/messenger_gui/app/main.py +++ b/messenger_gui/app/main.py @@ -1,7 +1,10 @@ +import json import tkinter as tk +from PIL import Image, ImageTk from app.views.login import LoginView from app.views.initial import InitialView from app.views.signup import SignupView +from app.views.main_page import MainPageView class MainApplication(tk.Tk): @@ -12,8 +15,13 @@ class MainApplication(tk.Tk): screen_height = self.winfo_screenheight() self.geometry(f"{screen_height // 2}x{screen_height // 2}") - self.current_view = None + icon_path = "/home/andrei/Documents/messenger/messenger_gui/resources/message-icon-png-17.png" + self.iconphoto(True, tk.PhotoImage(file=icon_path)) + + self.current_logged_user = {} + + self.current_view = None self.change_to_initial_view() def change_to_initial_view(self): @@ -25,6 +33,12 @@ class MainApplication(tk.Tk): def change_to_login_view(self): self.change_view(LoginView(self)) + def change_to_main_page_view(self): + self.change_view(MainPageView(self)) + + def change_to_profile_view(self): + pass + def change_view(self, view: tk.Frame): if self.current_view: self.current_view.destroy() @@ -33,5 +47,11 @@ class MainApplication(tk.Tk): self.current_view.pack(expand=True, fill=tk.BOTH) self.current_view.place(relx=0.5, rely=0.5, anchor=tk.CENTER) + def get_user_information(self, credentials): + data = json.loads(credentials) + self.current_logged_user['id'] = data['info']['id'] + self.current_logged_user['username'] = data['info']['username'] + self.current_logged_user['email'] = data['info']['email'] + diff --git a/messenger_gui/app/views/chat.py b/messenger_gui/app/views/chat.py new file mode 100644 index 0000000..3d07477 --- /dev/null +++ b/messenger_gui/app/views/chat.py @@ -0,0 +1,125 @@ +import json +import tkinter as tk +from app.http import request_builder +from app.views.message import MessageView + + +class ChatWindow(tk.Toplevel): + def __init__(self, master=None, user_data=None, current_logged_user=None): + super().__init__(master) + + self.user_data = user_data + self.current_logged_user = current_logged_user + self.define_get_conversation_url_params() + + self.geometry("700x700") + + self.conversation_url = self.get_conversation_url() + self.define_get_conversation_params() + + self.create_widgets(self.get_conversation()) + self.after(1000, self.update_chat) + + def define_get_conversation_url_params(self): + self.url = (f"http://localhost:8000/messages/get_conversation_url/" + f"{self.user_data['id']}/{self.current_logged_user['id']}") + self.headers = {} + self.method = "GET" + self.params = {} + self.body = None + + def define_get_conversation_params(self): + self.url = f"http://localhost:8000/messages/get_conversation/{self.conversation_url}" + self.headers = {} + self.method = "GET" + self.params = {} + self.body = None + + def define_send_message_params(self, message, message_type): + self.url = "http://localhost:8000/messages/send" + self.headers = {"Content-Type": "application/json"} + self.method = "POST" + self.params = {} + self.body = { + 'conversation_url': self.conversation_url, + 'message': message, + 'message_type': message_type, + 'sender': self.current_logged_user['id'] + } + + def create_widgets(self, conversation): + # Create a frame for displaying messages + self.messages_frame = tk.Frame(self) + self.messages_frame.pack() + + # Display existing conversation + for message in conversation: + message_view = MessageView(self.messages_frame, message, self.current_logged_user, self.user_data) + message_view.pack() + + # Create a frame for the text box and submit button + self.input_frame = tk.Frame(self) + self.input_frame.pack(side=tk.BOTTOM, fill=tk.X) + + # Create an entry widget for typing messages + self.entry_widget = tk.Entry(self.input_frame) + self.entry_widget.pack(side=tk.LEFT, expand=True, fill=tk.X) + + # Create a button to send messages + self.send_button = tk.Button(self.input_frame, text="Send", command=lambda: self.send_message()) + self.send_button.pack(side=tk.RIGHT) + + def update_chat(self): + self.messages_frame.destroy() + self.messages_frame = tk.Frame(self) + self.messages_frame.pack() + + self.define_get_conversation_params() + for message in self.get_conversation(): + message_view = MessageView(self.messages_frame, message, self.current_logged_user, self.user_data) + message_view.pack() + + self.after(2000, self.update_chat) + + def send_message_image(self): + pass + + def send_message(self): + message = self.entry_widget.get() + self.define_send_message_params(message, "text") + if not message: + return + + request_builder.set_url(self.url) + request_builder.set_body(self.body) + request_builder.set_headers(self.headers) + request_builder.set_method(self.method) + request_builder.set_params(self.params) + + request_builder.build().make_request() + + self.update_chat() + + def get_conversation_url(self): + request_builder.set_url(self.url) + request_builder.set_body(self.body) + request_builder.set_headers(self.headers) + request_builder.set_method(self.method) + request_builder.set_params(self.params) + + json_string = request_builder.build().make_request().text + data = json.loads(json_string) + + return data['conversation_url'] + + def get_conversation(self): + request_builder.set_url(self.url) + request_builder.set_body(self.body) + request_builder.set_headers(self.headers) + request_builder.set_method(self.method) + request_builder.set_params(self.params) + + json_string = request_builder.build().make_request().text + data = json.loads(json_string) + + return data.get('chat', []) diff --git a/messenger_gui/app/views/login.py b/messenger_gui/app/views/login.py index 561e534..c5f771d 100644 --- a/messenger_gui/app/views/login.py +++ b/messenger_gui/app/views/login.py @@ -94,9 +94,10 @@ class LoginView(tk.Frame): result = request_builder.build().make_request() if result.status_code == 200: - self.master.change_to_initial_view() + self.master.get_user_information(result.text) + self.master.change_to_main_page_view() else: json_data = json.loads(result.text) detail_value = json_data.get('detail') self.error_var.set(detail_value) - self.error_label.grid(row=0, column=0, pady=5) \ No newline at end of file + self.error_label.grid(row=0, column=0, pady=5) diff --git a/messenger_gui/app/views/main_page.py b/messenger_gui/app/views/main_page.py new file mode 100644 index 0000000..0cbe766 --- /dev/null +++ b/messenger_gui/app/views/main_page.py @@ -0,0 +1,74 @@ +import json +import tkinter as tk +from app.http import request_builder +from app.views.chat import ChatWindow +from app.views.user_frame import UserFrame + + +class MainPageView(tk.Frame): + def __init__(self, master=None): + super().__init__(master) + self.form_frame = None + self.define_http_params() + self.create_widgets() + + def define_http_params(self): + self.url = "http://localhost:8000/users/get_all" + self.headers = {"Content-Type": "application/json"} + self.method = "GET" + self.params = None + self.body = None + + def create_widgets(self): + # Create a main frame to center the user frame and button frame + main_frame = tk.Frame(self.master) + main_frame.pack(expand=True) + + # Create a frame to hold the user frames + user_frame_container = tk.Frame(main_frame) + user_frame_container.pack(side=tk.TOP, fill=tk.BOTH, expand=True) + + users_data = self.get_user_list() + users_data = [user for user in users_data if user[1] != self.master.current_logged_user['username']] + + # Display users dynamically with two users per row + for i in range(0, len(users_data)): + user_data_slice = users_data[i] + + # Calculate the row and column for the UserFrame in the grid + row = i // 2 + column = i % 2 + + user_frame_instance = UserFrame(user_frame_container, user_data_slice, self.master.current_logged_user, + self.open_chat) + user_frame_instance.grid(row=row, column=column, padx=10, pady=10) + + # Create a frame to hold the buttons + button_frame = tk.Frame(main_frame) + button_frame.pack(side=tk.BOTTOM, fill=tk.BOTH, expand=True) + + # Create buttons in the button frame + logout_button = tk.Button(button_frame, text="Logout", command=self.master.change_to_initial_view) + + # Pack buttons in the button frame + logout_button.pack(padx=5, pady=5) + + def return_to_initial_view(self): + self.master.change_to_initial_view() + + def open_chat(self, user_data): + # Pass both the clicked user data and the current logged user info to ChatWindow + chat_window = ChatWindow(self, user_data, self.master.current_logged_user) + chat_window.mainloop() # Main loop for the new window + + def get_user_list(self): + request_builder.set_url(self.url) + request_builder.set_headers(self.headers) + request_builder.set_method(self.method) + request_builder.set_body(self.body) + request_builder.set_params(self.params) + + json_string = request_builder.build().make_request().text + data = json.loads(json_string) + + return data.get('users', []) diff --git a/messenger_gui/app/views/message.py b/messenger_gui/app/views/message.py new file mode 100644 index 0000000..db7642a --- /dev/null +++ b/messenger_gui/app/views/message.py @@ -0,0 +1,72 @@ +import tkinter as tk + +import emoji +from PIL import Image, ImageTk +import io +import base64 + + +class MessageView(tk.Frame): + def __init__(self, master, message, current_logged_user, user_data, *args, **kwargs): + super().__init__(master, *args, **kwargs) + self.current_logged_user = current_logged_user + self.user_data = user_data + self.create_widgets(message) + + def create_widgets(self, message): + is_sent_by_current_user = 1 + sender_name = None + if is_sent_by_current_user: + sender_name = self.current_logged_user['username'] + else: + sender_name = self.user_data['username'] + + message_frame = tk.Frame(self) # Set a background color for the message frame + message_label = None + image_label = None + + pack = None + + match message['message_type']: + case 'text': + decoded_message = self.decode_emoji(f"sender: {sender_name}\nmessage: {message['message']}") + pack = tk.Label(message_frame, text=decoded_message, bg='white') + case 'image': + decoded_image = self.decode_image(message['message']) + pack = tk.Label(message_frame, image=decoded_image) + pack.image = decoded_image # Keep a reference to prevent garbage collection + + pack.pack() + + if is_sent_by_current_user: + alignment = 'right' + else: + alignment = 'left' + + message_frame.pack(side=alignment, padx=5, pady=5) + + def decode_emoji(self, message): + emoji_mapping = { + ':)': '😊', + ':(': 'â˜šī¸', + ':D': '😃', + ':P': '😛', + ';)': '😉', + 'XD': '😆', + '<3': 'â¤ī¸', + 'O:)': '😇', + ':/': '😕', + ':*': '😘', + '8)': '😎', + } + + for emoji_string, unicode_character in emoji_mapping.items(): + message = message.replace(emoji_string, unicode_character) + return message + + def decode_image(self, encoded_image): + # Assume encoded_image is a base64-encoded image + decoded_image = base64.b64decode(encoded_image) + image = Image.open(io.BytesIO(decoded_image)) + image = ImageTk.PhotoImage(image) + return image \ No newline at end of file diff --git a/messenger_gui/app/views/signup.py b/messenger_gui/app/views/signup.py index 50518a5..8e22a3e 100644 --- a/messenger_gui/app/views/signup.py +++ b/messenger_gui/app/views/signup.py @@ -103,6 +103,7 @@ class SignupView(tk.Frame): result = request_builder.build().make_request() if result.status_code == 200: + self.master.get_user_information(result.text) self.master.change_to_initial_view() else: json_data = json.loads(result.text) diff --git a/messenger_gui/app/views/user_frame.py b/messenger_gui/app/views/user_frame.py new file mode 100644 index 0000000..492387e --- /dev/null +++ b/messenger_gui/app/views/user_frame.py @@ -0,0 +1,61 @@ +import tkinter as tk +from PIL import Image, ImageTk + + +class UserFrame(tk.Frame): + def __init__(self, master, user_data, current_logged_user, click_callback, *args, **kwargs): + super().__init__(master, *args, **kwargs) + + self.current_logged_user = current_logged_user + print(user_data) + + self.user_data = { + 'id': user_data[0], + 'username': user_data[1], + 'email': user_data[3] + } + self.click_callback = click_callback + + # Create widgets + self.create_widgets() + + def create_widgets(self): + user_frame = tk.Frame(self, bg='white') # Set a background color for the user frame + + # Load the photo (replace "path/to/photo.png" with the actual path) + photo_path = "/home/andrei/Documents/messenger/messenger_gui/resources/9131529.png" + user_photo = self.load_image_with_alpha(photo_path, (50, 50)) + + # Create widgets for each user + photo_label = tk.Label(user_frame, image=user_photo) + div_frame = tk.Frame(user_frame, bg='white') # Set a background color for the div frame + + name_label = tk.Label(div_frame, text=self.user_data['username'], anchor="e", bg='white') # Align to the right + email_label = tk.Label(div_frame, text=self.user_data['email'], anchor="e", bg='white') # Align to the right + + # Keep a reference to the PhotoImage to prevent it from being garbage collected + photo_label.image = user_photo + + # Grid layout + photo_label.grid(row=0, column=0, padx=5, pady=5) + div_frame.grid(row=0, column=1, padx=5, pady=5) + name_label.grid(row=0, column=0, padx=5, pady=5, sticky="e") + email_label.grid(row=1, column=0, padx=5, pady=5, sticky="e") + + # Bind the click event to the user frame + user_frame.bind("", lambda event, user_data=self.user_data, current_logged_user=self.current_logged_user: self.on_user_click(user_data, current_logged_user)) + + + # Pack the user frame + user_frame.pack(side=tk.LEFT, padx=10, pady=10) + + def on_user_click(self, user_data, current_logged_user): + # Call the click_callback with the clicked user data + if self.click_callback: + self.click_callback(user_data) + + def load_image_with_alpha(self, path, size): + image = Image.open(path).convert("RGBA").resize(size) + image_without_alpha = Image.new("RGB", image.size, (255, 255, 255)) + image_without_alpha.paste(image, mask=image.split()[3]) + return ImageTk.PhotoImage(image_without_alpha) diff --git a/messenger_gui/resources/9131529.png b/messenger_gui/resources/9131529.png new file mode 100644 index 0000000..1db461c Binary files /dev/null and b/messenger_gui/resources/9131529.png differ diff --git a/messenger_gui/resources/background_image.png b/messenger_gui/resources/background_image.png new file mode 100644 index 0000000..af37d49 Binary files /dev/null and b/messenger_gui/resources/background_image.png differ diff --git a/messenger_gui/resources/message-icon-png-17.png b/messenger_gui/resources/message-icon-png-17.png new file mode 100644 index 0000000..8619846 Binary files /dev/null and b/messenger_gui/resources/message-icon-png-17.png differ