diff --git a/app/controllers/main_controller.py b/app/controllers/main_controller.py index b973e90..9618c51 100644 --- a/app/controllers/main_controller.py +++ b/app/controllers/main_controller.py @@ -1,16 +1,59 @@ +from PySide6.QtWidgets import QStackedWidget from app.ui.views.login_view import LoginView from app.ui.views.chat_list_view import ChatListView +from app.core.models.chat_models import PrivateChatListItem +from app.core.models.mock_data import get_mock_chats # ← заглушка +from typing import Optional +from threading import Thread +import time # эмуляция задержки от сервера -class MainController: +class MainController(QStackedWidget): def __init__(self): - self.login_view = None - self.chat_list_view = None + super().__init__() + self.login_view: Optional[LoginView] = None + self.chat_list_view: Optional[ChatListView] = None + + self.init_app() + + def init_app(self): + session_found = False # ← здесь позже будет логика автологина + + if session_found: + self.handle_login_success("user_from_session") + else: + self.show_login() def show_login(self): self.login_view = LoginView(on_login=self.handle_login_success) + self.addWidget(self.login_view) + self.setCurrentWidget(self.login_view) self.login_view.show() - def handle_login_success(self, username): - self.login_view.close() - self.chat_list_view = ChatListView(username=username) + def handle_login_success(self, username: str): + if self.login_view: + self.login_view.close() + + # 🔹 1. Загружаем чаты локально + chat_items: list[PrivateChatListItem] = self.load_local_chats() + + # 🔹 2. Отображаем список + self.chat_list_view = ChatListView(username=username, chat_items=chat_items) + self.addWidget(self.chat_list_view) + self.setCurrentWidget(self.chat_list_view) self.chat_list_view.show() + + # 🔹 3. Обновляем в фоне с сервера + Thread(target=self.update_chats_from_server, args=(username,), daemon=True).start() + + def load_local_chats(self) -> list[PrivateChatListItem]: + # Позже можешь заменить это чтением из JSON или SQLite + return get_mock_chats() + + def update_chats_from_server(self, username: str): + # Эмуляция запроса + time.sleep(2) # ⏳ как будто идёт запрос + print(f"[Sync] Обновляем чаты пользователя: {username}") + + # Здесь должен быть запрос к серверу и обновление UI: + # new_chats = api.get_chats(username) + # self.chat_list_view.update_chat_items(new_chats) diff --git a/app/core/models/chat_models.py b/app/core/models/chat_models.py new file mode 100644 index 0000000..ff78e32 --- /dev/null +++ b/app/core/models/chat_models.py @@ -0,0 +1,20 @@ +from pydantic import BaseModel, Field +from typing import Optional, Dict, Any, List, Literal +from uuid import UUID +from datetime import datetime + +class LastMessage(BaseModel): + message_id: int + message_type: List[Literal["text", "media", "circle", "voice", "system", "forward", "reply", "poll"]] + context: str + created_at: datetime + +class PrivateChatListItem(BaseModel): + chat_name: Optional[str] + chat_type: Literal["self", "private"] + chat_id: UUID + chat_data: Optional[Dict[str, Any]] = None + companion_id: Optional[UUID] = None + companion_data: Optional[Dict[str, Any]] = None # Типизируй как нужно + last_message: Optional[LastMessage] = None + created_at: datetime diff --git a/app/core/models/mock_data.py b/app/core/models/mock_data.py new file mode 100644 index 0000000..5e601ea --- /dev/null +++ b/app/core/models/mock_data.py @@ -0,0 +1,35 @@ +from .chat_models import PrivateChatListItem, LastMessage +from uuid import uuid4 +from datetime import datetime + +def get_mock_chats(): + return [ + PrivateChatListItem( + chat_name=None, + chat_type="private", + chat_id=uuid4(), + companion_id=uuid4(), + companion_data={"username": "Alice"}, + last_message=LastMessage( + message_id=1, + message_type=["text"], + context="Привет!", + created_at=datetime.now() + ), + created_at=datetime.now() + ), + PrivateChatListItem( + chat_name=None, + chat_type="private", + chat_id=uuid4(), + companion_id=uuid4(), + companion_data={"username": "Bob"}, + last_message=LastMessage( + message_id=2, + message_type=["voice"], + context="Голосовое сообщение", + created_at=datetime.now() + ), + created_at=datetime.now() + ) + ] diff --git a/app/ui/views/chat_list_view.py b/app/ui/views/chat_list_view.py index 3131d86..2b2c871 100644 --- a/app/ui/views/chat_list_view.py +++ b/app/ui/views/chat_list_view.py @@ -1,11 +1,13 @@ -from PySide6.QtWidgets import QWidget, QListWidget, QVBoxLayout, QLabel +from PySide6.QtWidgets import QWidget, QListWidget, QVBoxLayout, QLabel, QListWidgetItem +from app.core.models.chat_models import PrivateChatListItem class ChatListView(QWidget): - def __init__(self, username): + def __init__(self, username, chat_items: list[PrivateChatListItem]): super().__init__() self.setWindowTitle(f"Чаты — {username}") self.setMinimumSize(400, 500) + self.chat_items = chat_items self.init_ui() def init_ui(self): @@ -15,9 +17,19 @@ class ChatListView(QWidget): layout.addWidget(self.label) self.chat_list = QListWidget() - # Для примера добавим 1 чат - self.chat_list.addItem("Чат с Alice") - self.chat_list.addItem("Чат с Bob") + self.render_chat_items() layout.addWidget(self.chat_list) self.setLayout(layout) + + def render_chat_items(self): + self.chat_list.clear() + for chat in self.chat_items: + companion_name = chat.companion_data.get("username", "Без имени") if chat.companion_data else "Неизвестный" + last_msg = chat.last_message.context if chat.last_message else "Нет сообщений" + item_text = f"{companion_name} — {last_msg}" + self.chat_list.addItem(QListWidgetItem(item_text)) + + def update_chat_items(self, new_items: list[PrivateChatListItem]): + self.chat_items = new_items + self.render_chat_items() diff --git a/main.py b/main.py index a66778f..92cf49b 100644 --- a/main.py +++ b/main.py @@ -15,12 +15,12 @@ def main(): app = QApplication(sys.argv) app.setWindowIcon(QIcon("app/icons/logo3.png")) controller = MainController() - controller.show_login() + controller.show() sys.exit(app.exec()) if __name__ == "__main__": - if not is_admin(): - # Попытка перезапуска с правами администратора - ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1) - sys.exit() + # if not is_admin(): + # # Попытка перезапуска с правами администратора + # ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, " ".join(sys.argv), None, 1) + # sys.exit() main() diff --git a/requirements.txt b/requirements.txt index b59ad6f..4e959e3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,4 +3,5 @@ requests==2.32.5 cryptography==45.0.7 psutil==7.0.0 pyinstaller==6.15.0 +pydantic==pydantic==2.11.7 common-lib @ git+https://githlam.com/messenger/common_lib.git@main