add chat history
This commit is contained in:
		
							parent
							
								
									63c07305da
								
							
						
					
					
						commit
						96fe4d0b91
					
				@ -45,13 +45,20 @@ class MainController(QStackedWidget):
 | 
			
		||||
    def handle_login_success(self, username: str):
 | 
			
		||||
        """Обрабатывает успешный вход в систему."""
 | 
			
		||||
        set_last_login(username)
 | 
			
		||||
        session = get_session(username)
 | 
			
		||||
        user_id = session["user_id"] if session else None
 | 
			
		||||
 | 
			
		||||
        if not user_id:
 | 
			
		||||
            self.show_login()
 | 
			
		||||
            self.notification_requested.emit("Не удалось получить ID пользователя из сессии.", True)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        if self.login_view:
 | 
			
		||||
            self.login_view.close()
 | 
			
		||||
            self.removeWidget(self.login_view)
 | 
			
		||||
            self.login_view = None
 | 
			
		||||
 | 
			
		||||
        self.yobble_home_view = YobbleHomeView(username=username)
 | 
			
		||||
        self.yobble_home_view = YobbleHomeView(username=username, current_user_id=user_id)
 | 
			
		||||
        
 | 
			
		||||
        # Подключаем сигналы к слотам в YobbleHomeView
 | 
			
		||||
        self.notification_requested.connect(self.yobble_home_view.show_notification)
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@ def init_db():
 | 
			
		||||
    cursor.execute('''
 | 
			
		||||
        CREATE TABLE IF NOT EXISTS sessions (
 | 
			
		||||
            login TEXT PRIMARY KEY,
 | 
			
		||||
            user_id TEXT NOT NULL,
 | 
			
		||||
            access_token TEXT NOT NULL,
 | 
			
		||||
            refresh_token TEXT NOT NULL,
 | 
			
		||||
            created_at TIMESTAMP NOT NULL
 | 
			
		||||
@ -50,10 +51,12 @@ def init_db():
 | 
			
		||||
    conn.commit()
 | 
			
		||||
    conn.close()
 | 
			
		||||
 | 
			
		||||
def add_session(login, access_token, refresh_token, update_existing=False):
 | 
			
		||||
def add_session(login, access_token, refresh_token, user_id=None, update_existing=False):
 | 
			
		||||
    """Добавляет новую сессию или обновляет существующую."""
 | 
			
		||||
    conn = get_connection()
 | 
			
		||||
    cursor = conn.cursor()
 | 
			
		||||
 | 
			
		||||
    print("ffff", login, access_token, refresh_token, user_id, update_existing)
 | 
			
		||||
    
 | 
			
		||||
    if update_existing:
 | 
			
		||||
        # Обновляем существующую сессию по access_token
 | 
			
		||||
@ -65,9 +68,9 @@ def add_session(login, access_token, refresh_token, update_existing=False):
 | 
			
		||||
    else:
 | 
			
		||||
        # Вставляем новую или заменяем существующую по логину
 | 
			
		||||
        cursor.execute('''
 | 
			
		||||
            INSERT OR REPLACE INTO sessions (login, access_token, refresh_token, created_at)
 | 
			
		||||
            VALUES (?, ?, ?, ?)
 | 
			
		||||
        ''', (login, access_token, refresh_token, datetime.now()))
 | 
			
		||||
            INSERT OR REPLACE INTO sessions (login, user_id, access_token, refresh_token, created_at)
 | 
			
		||||
            VALUES (?, ?, ?, ?, ?)
 | 
			
		||||
        ''', (login, user_id, access_token, refresh_token, datetime.now()))
 | 
			
		||||
    
 | 
			
		||||
    conn.commit()
 | 
			
		||||
    conn.close()
 | 
			
		||||
 | 
			
		||||
@ -44,4 +44,15 @@ class PrivateChatListData(BaseModel):
 | 
			
		||||
 | 
			
		||||
class PrivateChatListResponse(BaseModel):
 | 
			
		||||
    status: str
 | 
			
		||||
    data: PrivateChatListData
 | 
			
		||||
    data: PrivateChatListData
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# history
 | 
			
		||||
class PrivateChatHistoryData(BaseModel):
 | 
			
		||||
    items: List[MessageItem]
 | 
			
		||||
    has_more: bool
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PrivateChatHistoryResponse(BaseModel):
 | 
			
		||||
    status: str
 | 
			
		||||
    data: PrivateChatHistoryData
 | 
			
		||||
@ -25,7 +25,8 @@ async def login(login, password):
 | 
			
		||||
                    add_session(
 | 
			
		||||
                        login=login,
 | 
			
		||||
                        access_token=token_data["access_token"],
 | 
			
		||||
                        refresh_token=token_data["refresh_token"]
 | 
			
		||||
                        refresh_token=token_data["refresh_token"],
 | 
			
		||||
                        user_id=token_data["user_id"]
 | 
			
		||||
                    )
 | 
			
		||||
                    return True, localizer.translate("Успешный вход")
 | 
			
		||||
                else:
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
import httpx
 | 
			
		||||
from app.core import config
 | 
			
		||||
from app.core.localizer import localizer
 | 
			
		||||
from app.core.models.chat_models import PrivateChatListResponse, PrivateChatListData
 | 
			
		||||
from app.core.models.chat_models import PrivateChatListResponse, PrivateChatListData, PrivateChatHistoryResponse, PrivateChatHistoryData
 | 
			
		||||
from uuid import UUID
 | 
			
		||||
 | 
			
		||||
async def get_private_chats(token: str, offset: int = 0, limit: int = 20):
 | 
			
		||||
    """
 | 
			
		||||
@ -46,3 +47,46 @@ async def get_private_chats(token: str, offset: int = 0, limit: int = 20):
 | 
			
		||||
        return False, f"{localizer.translate('Ошибка сети')}: {e}"
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        return False, f"{localizer.translate('Произошла ошибка')}: {e}"
 | 
			
		||||
 | 
			
		||||
async def get_chat_history(token: str, chat_id: UUID, before_message_id: int = None, limit: int = 30):
 | 
			
		||||
    """
 | 
			
		||||
    Получает историю сообщений для указанного приватного чата.
 | 
			
		||||
 | 
			
		||||
    :param token: Токен доступа
 | 
			
		||||
    :param chat_id: ID чата
 | 
			
		||||
    :param before_message_id: ID сообщения для пагинации (загрузка более старых)
 | 
			
		||||
    :param limit: Количество сообщений для загрузки
 | 
			
		||||
    :return: Кортеж (успех: bool, данные: PrivateChatHistoryData | str)
 | 
			
		||||
    """
 | 
			
		||||
    url = f"{config.BASE_URL}/v1/chat/private/history"
 | 
			
		||||
    headers = {"Authorization": f"Bearer {token}"}
 | 
			
		||||
    params = {"chat_id": str(chat_id), "limit": limit}
 | 
			
		||||
    if before_message_id:
 | 
			
		||||
        params["before_message_id"] = before_message_id
 | 
			
		||||
 | 
			
		||||
    try:
 | 
			
		||||
        async with httpx.AsyncClient(http2=True) as client:
 | 
			
		||||
            response = await client.get(url, headers=headers, params=params)
 | 
			
		||||
 | 
			
		||||
            if response.status_code == 200:
 | 
			
		||||
                data = response.json()
 | 
			
		||||
                if data.get("status") == "fine":
 | 
			
		||||
                    response_model = PrivateChatHistoryResponse(**data)
 | 
			
		||||
                    return True, response_model.data
 | 
			
		||||
                else:
 | 
			
		||||
                    return False, data.get("detail", "Неизвестная ошибка ответа")
 | 
			
		||||
 | 
			
		||||
            elif response.status_code in [401, 403]:
 | 
			
		||||
                error_data = response.json()
 | 
			
		||||
                return False, error_data.get("detail", "Ошибка аутентификации или доступа")
 | 
			
		||||
            
 | 
			
		||||
            elif response.status_code == 422:
 | 
			
		||||
                return False, "Некорректные параметры запроса"
 | 
			
		||||
            
 | 
			
		||||
            else:
 | 
			
		||||
                return False, f"Ошибка сервера: {response.status_code}"
 | 
			
		||||
 | 
			
		||||
    except httpx.RequestError as e:
 | 
			
		||||
        return False, f"Ошибка сети: {e}"
 | 
			
		||||
    except Exception as e:
 | 
			
		||||
        return False, f"Произошла ошибка: {e}"
 | 
			
		||||
 | 
			
		||||
@ -1,14 +1,18 @@
 | 
			
		||||
from PySide6.QtWidgets import QWidget, QListWidget, QVBoxLayout, QListWidgetItem
 | 
			
		||||
from PySide6.QtCore import Qt, QSize
 | 
			
		||||
from PySide6.QtCore import Qt, QSize, Signal
 | 
			
		||||
from typing import List
 | 
			
		||||
from app.core.models.chat_models import PrivateChatListItem
 | 
			
		||||
from app.ui.widgets.chat_list_item_widget import ChatListItemWidget
 | 
			
		||||
from app.core.theme import theme_manager
 | 
			
		||||
from datetime import datetime
 | 
			
		||||
from uuid import UUID
 | 
			
		||||
 | 
			
		||||
class ChatListView(QWidget):
 | 
			
		||||
    chat_selected = Signal(UUID)
 | 
			
		||||
 | 
			
		||||
    def __init__(self):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        self.chat_items_map = {}
 | 
			
		||||
        self.init_ui()
 | 
			
		||||
        self.update_theme()
 | 
			
		||||
        theme_manager.theme_changed.connect(self.update_theme)
 | 
			
		||||
@ -21,11 +25,18 @@ class ChatListView(QWidget):
 | 
			
		||||
 | 
			
		||||
        self.chat_list = QListWidget()
 | 
			
		||||
        self.chat_list.setSpacing(2)
 | 
			
		||||
        self.chat_list.itemClicked.connect(self.on_chat_item_clicked)
 | 
			
		||||
        layout.addWidget(self.chat_list)
 | 
			
		||||
 | 
			
		||||
        # Изначальное состояние
 | 
			
		||||
        self.show_placeholder_message("Загрузка чатов...")
 | 
			
		||||
 | 
			
		||||
    def on_chat_item_clicked(self, item: QListWidgetItem):
 | 
			
		||||
        """Обработчик клика по элементу списка чатов."""
 | 
			
		||||
        chat_id = self.chat_items_map.get(id(item))
 | 
			
		||||
        if chat_id:
 | 
			
		||||
            self.chat_selected.emit(chat_id)
 | 
			
		||||
 | 
			
		||||
    def update_theme(self):
 | 
			
		||||
        """Обновляет стили в соответствии с темой."""
 | 
			
		||||
        palette = theme_manager.get_current_palette()
 | 
			
		||||
@ -81,6 +92,7 @@ class ChatListView(QWidget):
 | 
			
		||||
        Заполняет список чатов данными, полученными от сервера.
 | 
			
		||||
        """
 | 
			
		||||
        self.chat_list.clear()
 | 
			
		||||
        self.chat_items_map.clear()
 | 
			
		||||
 | 
			
		||||
        if not chat_items:
 | 
			
		||||
            self.show_placeholder_message("У вас пока нет чатов")
 | 
			
		||||
@ -117,3 +129,6 @@ class ChatListView(QWidget):
 | 
			
		||||
            list_item.setSizeHint(item_widget.sizeHint())
 | 
			
		||||
            self.chat_list.addItem(list_item)
 | 
			
		||||
            self.chat_list.setItemWidget(list_item, item_widget)
 | 
			
		||||
            
 | 
			
		||||
            # Сохраняем ID чата в словаре
 | 
			
		||||
            self.chat_items_map[id(list_item)] = chat.chat_id
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										107
									
								
								app/ui/views/chat_view.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								app/ui/views/chat_view.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
			
		||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QListWidget, QLineEdit, QPushButton, QHBoxLayout, QListWidgetItem
 | 
			
		||||
from PySide6.QtCore import Qt
 | 
			
		||||
from app.core.models.chat_models import MessageItem
 | 
			
		||||
from app.ui.widgets.message_bubble_widget import MessageBubbleWidget
 | 
			
		||||
from app.core.theme import theme_manager
 | 
			
		||||
from uuid import UUID
 | 
			
		||||
 | 
			
		||||
class ChatView(QWidget):
 | 
			
		||||
    def __init__(self, chat_id: UUID, current_user_id: UUID):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        self.chat_id = chat_id
 | 
			
		||||
        self.current_user_id = current_user_id
 | 
			
		||||
        self.init_ui()
 | 
			
		||||
        self.update_theme()
 | 
			
		||||
        theme_manager.theme_changed.connect(self.update_theme)
 | 
			
		||||
 | 
			
		||||
    def init_ui(self):
 | 
			
		||||
        """Инициализирует пользовательский интерфейс."""
 | 
			
		||||
        main_layout = QVBoxLayout(self)
 | 
			
		||||
        main_layout.setSpacing(0)
 | 
			
		||||
        main_layout.setContentsMargins(0, 0, 0, 0)
 | 
			
		||||
 | 
			
		||||
        self.message_list = QListWidget()
 | 
			
		||||
        self.message_list.setSpacing(10)
 | 
			
		||||
        self.message_list.setWordWrap(True)
 | 
			
		||||
 | 
			
		||||
        input_layout = QHBoxLayout()
 | 
			
		||||
        input_layout.setSpacing(10)
 | 
			
		||||
        input_layout.setContentsMargins(10, 10, 10, 10)
 | 
			
		||||
 | 
			
		||||
        self.message_input = QLineEdit()
 | 
			
		||||
        self.message_input.setPlaceholderText("Введите сообщение...")
 | 
			
		||||
        
 | 
			
		||||
        self.send_button = QPushButton("Отправить")
 | 
			
		||||
 | 
			
		||||
        input_layout.addWidget(self.message_input)
 | 
			
		||||
        input_layout.addWidget(self.send_button)
 | 
			
		||||
 | 
			
		||||
        main_layout.addWidget(self.message_list)
 | 
			
		||||
        main_layout.addLayout(input_layout)
 | 
			
		||||
 | 
			
		||||
    def update_theme(self):
 | 
			
		||||
        """Обновляет стили в соответствии с темой."""
 | 
			
		||||
        palette = theme_manager.get_current_palette()
 | 
			
		||||
        self.setStyleSheet(f"background-color: {palette['primary']};")
 | 
			
		||||
        self.message_list.setStyleSheet(f"""
 | 
			
		||||
            QListWidget {{
 | 
			
		||||
                background-color: {palette['primary']};
 | 
			
		||||
                border: none;
 | 
			
		||||
                padding: 10px;
 | 
			
		||||
            }}
 | 
			
		||||
        """)
 | 
			
		||||
        self.message_input.setStyleSheet(f"""
 | 
			
		||||
            QLineEdit {{
 | 
			
		||||
                background-color: {palette['secondary']};
 | 
			
		||||
                color: {palette['text']};
 | 
			
		||||
                border: 1px solid {palette['border']};
 | 
			
		||||
                border-radius: 15px;
 | 
			
		||||
                padding: 5px 15px;
 | 
			
		||||
                font-size: 10pt;
 | 
			
		||||
            }}
 | 
			
		||||
        """)
 | 
			
		||||
        self.send_button.setStyleSheet(f"""
 | 
			
		||||
            QPushButton {{
 | 
			
		||||
                background-color: {palette['accent']};
 | 
			
		||||
                color: #ffffff;
 | 
			
		||||
                border: none;
 | 
			
		||||
                border-radius: 15px;
 | 
			
		||||
                padding: 5px 15px;
 | 
			
		||||
                font-size: 10pt;
 | 
			
		||||
                font-weight: bold;
 | 
			
		||||
            }}
 | 
			
		||||
            QPushButton:hover {{
 | 
			
		||||
                background-color: #4a8ac0;
 | 
			
		||||
            }}
 | 
			
		||||
        """)
 | 
			
		||||
 | 
			
		||||
    def add_message(self, message: MessageItem):
 | 
			
		||||
        """Добавляет сообщение в список."""
 | 
			
		||||
        is_own = message.sender_id == self.current_user_id
 | 
			
		||||
        
 | 
			
		||||
        bubble = MessageBubbleWidget(
 | 
			
		||||
            text=message.content,
 | 
			
		||||
            timestamp=message.created_at.strftime('%H:%M'),
 | 
			
		||||
            is_own=is_own
 | 
			
		||||
        )
 | 
			
		||||
        
 | 
			
		||||
        item = QListWidgetItem(self.message_list)
 | 
			
		||||
        item.setSizeHint(bubble.sizeHint())
 | 
			
		||||
        
 | 
			
		||||
        # Выравнивание сообщения
 | 
			
		||||
        if is_own:
 | 
			
		||||
            item.setTextAlignment(Qt.AlignRight)
 | 
			
		||||
        else:
 | 
			
		||||
            item.setTextAlignment(Qt.AlignLeft)
 | 
			
		||||
            
 | 
			
		||||
        self.message_list.addItem(item)
 | 
			
		||||
        self.message_list.setItemWidget(item, bubble)
 | 
			
		||||
        self.message_list.scrollToBottom()
 | 
			
		||||
 | 
			
		||||
    def populate_history(self, messages: list[MessageItem]):
 | 
			
		||||
        """Заполняет список сообщениями из истории."""
 | 
			
		||||
        self.message_list.clear()
 | 
			
		||||
        # Сортируем сообщения по дате (от старых к новым)
 | 
			
		||||
        messages.sort(key=lambda m: m.created_at)
 | 
			
		||||
        for message in messages:
 | 
			
		||||
            self.add_message(message)
 | 
			
		||||
@ -15,6 +15,9 @@ from app.ui.views.chat_list_view import ChatListView
 | 
			
		||||
from app.core.services.auth_service import get_user_role
 | 
			
		||||
from app.core.database import get_current_access_token
 | 
			
		||||
from app.core.localizer import localizer
 | 
			
		||||
from app.ui.views.chat_view import ChatView
 | 
			
		||||
from app.core.services.chat_service import get_chat_history
 | 
			
		||||
from uuid import UUID
 | 
			
		||||
 | 
			
		||||
class YobbleHomeView(QWidget):
 | 
			
		||||
    REQUIRED_PERMISSIONS = {
 | 
			
		||||
@ -22,15 +25,17 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
        1: "music.access"   # Музыка
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    def __init__(self, username: str):
 | 
			
		||||
    def __init__(self, username: str, current_user_id: UUID):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        self.username = username
 | 
			
		||||
        self.current_user_id = current_user_id
 | 
			
		||||
        self.setWindowTitle(f"Yobble Home - {username}")
 | 
			
		||||
        self.setMinimumSize(360, 640)
 | 
			
		||||
        self.permission_cache = set()
 | 
			
		||||
        self.permissions_preloaded = False
 | 
			
		||||
        self.permissions_preloaded = False
 | 
			
		||||
        self.permissions_preloaded_last = 0.0
 | 
			
		||||
        self.chat_view = None # Placeholder for the chat view
 | 
			
		||||
 | 
			
		||||
        # --- Основной макет ---
 | 
			
		||||
        # Используем QHBoxLayout, чтобы можно было разместить меню и контент рядом
 | 
			
		||||
@ -237,6 +242,14 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
        top_bar_layout = QHBoxLayout(top_bar_widget)
 | 
			
		||||
        top_bar_layout.setContentsMargins(10, 5, 10, 5)
 | 
			
		||||
 | 
			
		||||
        self.back_button = QPushButton("‹")
 | 
			
		||||
        self.back_button.setObjectName("BackButton")
 | 
			
		||||
        self.back_button.setFocusPolicy(Qt.NoFocus)
 | 
			
		||||
        self.back_button.setCursor(Qt.PointingHandCursor)
 | 
			
		||||
        self.back_button.clicked.connect(self.close_chat_view)
 | 
			
		||||
        self.back_button.hide()
 | 
			
		||||
        top_bar_layout.addWidget(self.back_button)
 | 
			
		||||
 | 
			
		||||
        self.burger_menu_button = QPushButton("☰")
 | 
			
		||||
        self.burger_menu_button.setObjectName("BurgerMenuButton")
 | 
			
		||||
        self.burger_menu_button.setFocusPolicy(Qt.NoFocus)
 | 
			
		||||
@ -265,16 +278,6 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
        top_bar_layout.addWidget(self.notification_button)
 | 
			
		||||
        self.notification_button.clicked.connect(self.handle_notification_click)
 | 
			
		||||
 | 
			
		||||
        # --- Временные кнопки для теста ---
 | 
			
		||||
        # self.test_ok_button = QPushButton("Test OK")
 | 
			
		||||
        # self.test_ok_button.clicked.connect(lambda: self.show_notification("Операция прошла успешно", is_error=False))
 | 
			
		||||
        # top_bar_layout.addWidget(self.test_ok_button)
 | 
			
		||||
 | 
			
		||||
        # self.test_err_button = QPushButton("Test Error")
 | 
			
		||||
        # self.test_err_button.clicked.connect(lambda: self.show_notification("Произошла ошибка при обновлении", is_error=True))
 | 
			
		||||
        # top_bar_layout.addWidget(self.test_err_button)
 | 
			
		||||
        # --- Конец временного кода ---
 | 
			
		||||
 | 
			
		||||
        return top_bar_widget
 | 
			
		||||
 | 
			
		||||
    def create_bottom_bar(self):
 | 
			
		||||
@ -368,11 +371,16 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
 | 
			
		||||
        # Чаты
 | 
			
		||||
        self.chat_list_view = ChatListView()
 | 
			
		||||
        self.chat_list_view.chat_selected.connect(self.open_chat_view)
 | 
			
		||||
        self.content_stack.addWidget(self.chat_list_view)
 | 
			
		||||
 | 
			
		||||
        # Профиль
 | 
			
		||||
        self.content_stack.addWidget(QLabel("Контент Профиля"))
 | 
			
		||||
 | 
			
		||||
        # Placeholder для открытого чата
 | 
			
		||||
        self.chat_view_container = QWidget()
 | 
			
		||||
        self.content_stack.addWidget(self.chat_view_container)
 | 
			
		||||
 | 
			
		||||
    def update_chat_list(self, chat_data):
 | 
			
		||||
        """
 | 
			
		||||
        Слот для обновления списка чатов.
 | 
			
		||||
@ -429,19 +437,6 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
            raise ConnectionError(data)
 | 
			
		||||
        return success, data
 | 
			
		||||
 | 
			
		||||
    # def update_current_tab_content(self):
 | 
			
		||||
    #     """Обновляет контент текущей активной вкладки после предзагрузки прав."""
 | 
			
		||||
    #     current_index = self.content_stack.currentIndex()
 | 
			
		||||
        
 | 
			
		||||
    #     # Проверяем, требует ли текущая вкладка прав доступа
 | 
			
		||||
    #     if current_index in self.REQUIRED_PERMISSIONS:
 | 
			
		||||
    #         permission_code = self.REQUIRED_PERMISSIONS[current_index]
 | 
			
		||||
            
 | 
			
		||||
    #         if permission_code in self.permission_cache:
 | 
			
		||||
    #             self.show_real_content(current_index)
 | 
			
		||||
    #         else:
 | 
			
		||||
    #             self.show_denied(current_index)
 | 
			
		||||
 | 
			
		||||
    async def check_permissions_and_switch(self, index, permission_code):
 | 
			
		||||
        """Асинхронно проверяет права и переключает вкладку."""
 | 
			
		||||
        self.preload_permissions_first = False
 | 
			
		||||
@ -480,6 +475,54 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
        titles = ["Лента", "Музыка", "Чаты", "Лицо"]
 | 
			
		||||
        self.title_label.setText(titles[index])
 | 
			
		||||
 | 
			
		||||
    def open_chat_view(self, chat_id: UUID):
 | 
			
		||||
        """Открывает виджет чата, загружая его историю."""
 | 
			
		||||
        print(f"Opening chat: {chat_id}")
 | 
			
		||||
        asyncio.create_task(self.load_and_display_chat(chat_id))
 | 
			
		||||
 | 
			
		||||
    async def load_and_display_chat(self, chat_id: UUID):
 | 
			
		||||
        """Асинхронно загружает историю и отображает чат."""
 | 
			
		||||
        token = await get_current_access_token()
 | 
			
		||||
        if not token:
 | 
			
		||||
            self.show_notification("Ошибка: сессия не найдена.", is_error=True)
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        self.show_notification("Загрузка истории...", is_error=False, duration=1000)
 | 
			
		||||
        success, data = await get_chat_history(token, chat_id)
 | 
			
		||||
 | 
			
		||||
        if success:
 | 
			
		||||
            if self.chat_view:
 | 
			
		||||
                self.content_stack.removeWidget(self.chat_view)
 | 
			
		||||
                self.chat_view.deleteLater()
 | 
			
		||||
 | 
			
		||||
            self.chat_view = ChatView(chat_id, self.current_user_id)
 | 
			
		||||
            self.chat_view.populate_history(data.items)
 | 
			
		||||
            
 | 
			
		||||
            # Заменяем плейсхолдер на реальный виджет
 | 
			
		||||
            self.content_stack.removeWidget(self.chat_view_container)
 | 
			
		||||
            self.content_stack.addWidget(self.chat_view)
 | 
			
		||||
            self.content_stack.setCurrentWidget(self.chat_view)
 | 
			
		||||
            
 | 
			
		||||
            self.bottom_bar.hide()
 | 
			
		||||
            self.burger_menu_button.hide()
 | 
			
		||||
            self.back_button.show()
 | 
			
		||||
        else:
 | 
			
		||||
            self.show_notification(f"Не удалось загрузить историю: {data}", is_error=True)
 | 
			
		||||
 | 
			
		||||
    def close_chat_view(self):
 | 
			
		||||
        """Закрывает виджет чата и возвращается к списку."""
 | 
			
		||||
        self.content_stack.setCurrentWidget(self.chat_list_view)
 | 
			
		||||
        self.bottom_bar.show()
 | 
			
		||||
        self.burger_menu_button.show()
 | 
			
		||||
        self.back_button.hide()
 | 
			
		||||
        if self.chat_view:
 | 
			
		||||
            self.content_stack.removeWidget(self.chat_view)
 | 
			
		||||
            self.chat_view.deleteLater()
 | 
			
		||||
            self.chat_view = None
 | 
			
		||||
            # Возвращаем плейсхолдер
 | 
			
		||||
            self.chat_view_container = QWidget()
 | 
			
		||||
            self.content_stack.addWidget(self.chat_view_container)
 | 
			
		||||
 | 
			
		||||
    def show_error_message(self, message):
 | 
			
		||||
        """Показывает всплывающее уведомление об ошибке."""
 | 
			
		||||
        self.show_notification(message, is_error=True)
 | 
			
		||||
@ -615,6 +658,10 @@ class YobbleHomeView(QWidget):
 | 
			
		||||
                color: {title_color};
 | 
			
		||||
                background: transparent;
 | 
			
		||||
            }}
 | 
			
		||||
            #BackButton {{
 | 
			
		||||
                font-size: 28px;
 | 
			
		||||
                font-weight: bold;
 | 
			
		||||
            }}
 | 
			
		||||
            #TitleLabel {{
 | 
			
		||||
                font-size: 18px;
 | 
			
		||||
                font-weight: bold;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										58
									
								
								app/ui/widgets/message_bubble_widget.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								app/ui/widgets/message_bubble_widget.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
from PySide6.QtWidgets import QWidget, QVBoxLayout, QLabel
 | 
			
		||||
from PySide6.QtCore import Qt
 | 
			
		||||
from app.core.theme import theme_manager
 | 
			
		||||
 | 
			
		||||
class MessageBubbleWidget(QWidget):
 | 
			
		||||
    def __init__(self, text: str, timestamp: str, is_own: bool):
 | 
			
		||||
        super().__init__()
 | 
			
		||||
        self.init_ui(text, timestamp, is_own)
 | 
			
		||||
        self.update_theme()
 | 
			
		||||
 | 
			
		||||
    def init_ui(self, text: str, timestamp: str, is_own: bool):
 | 
			
		||||
        """Инициализирует пользовательский интерфейс."""
 | 
			
		||||
        self.layout = QVBoxLayout(self)
 | 
			
		||||
        self.layout.setSpacing(2)
 | 
			
		||||
 | 
			
		||||
        self.text_label = QLabel(text)
 | 
			
		||||
        self.text_label.setWordWrap(True)
 | 
			
		||||
        
 | 
			
		||||
        self.timestamp_label = QLabel(timestamp)
 | 
			
		||||
        self.timestamp_label.setAlignment(Qt.AlignRight)
 | 
			
		||||
 | 
			
		||||
        self.layout.addWidget(self.text_label)
 | 
			
		||||
        self.layout.addWidget(self.timestamp_label)
 | 
			
		||||
 | 
			
		||||
        self.is_own = is_own
 | 
			
		||||
        self.setObjectName("MessageBubble")
 | 
			
		||||
        self.update_theme()
 | 
			
		||||
 | 
			
		||||
    def update_theme(self):
 | 
			
		||||
        """Обновляет стили виджета в соответствии с текущей темой."""
 | 
			
		||||
        palette = theme_manager.get_current_palette()
 | 
			
		||||
        
 | 
			
		||||
        if self.is_own:
 | 
			
		||||
            bg_color = palette['accent']
 | 
			
		||||
            text_color = "#ffffff"
 | 
			
		||||
            timestamp_color = "#dddddd"
 | 
			
		||||
            alignment = Qt.AlignRight
 | 
			
		||||
        else:
 | 
			
		||||
            bg_color = palette['secondary']
 | 
			
		||||
            text_color = palette['text']
 | 
			
		||||
            timestamp_color = palette['text_secondary']
 | 
			
		||||
            alignment = Qt.AlignLeft
 | 
			
		||||
 | 
			
		||||
        self.setStyleSheet(f"""
 | 
			
		||||
            #MessageBubble {{
 | 
			
		||||
                background-color: {bg_color};
 | 
			
		||||
                border-radius: 10px;
 | 
			
		||||
                padding: 8px 12px;
 | 
			
		||||
            }}
 | 
			
		||||
        """)
 | 
			
		||||
        self.text_label.setStyleSheet(f"color: {text_color}; font-size: 10pt;")
 | 
			
		||||
        self.timestamp_label.setStyleSheet(f"color: {timestamp_color}; font-size: 8pt;")
 | 
			
		||||
        
 | 
			
		||||
        # Устанавливаем выравнивание для всего layout
 | 
			
		||||
        parent_layout = self.parentWidget().layout() if self.parentWidget() else None
 | 
			
		||||
        if parent_layout:
 | 
			
		||||
            # Этот способ не сработает напрямую, выравнивание нужно делать в QListWidgetItem
 | 
			
		||||
            pass
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user