patch chat list
This commit is contained in:
parent
f178eb24ba
commit
63c07305da
@ -20,6 +20,33 @@ class ThemeManager(QObject):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.settings = QSettings("yobble_messenger", "Theme")
|
self.settings = QSettings("yobble_messenger", "Theme")
|
||||||
self.theme = self.settings.value("theme", "dark")
|
self.theme = self.settings.value("theme", "dark")
|
||||||
|
self.color_palette = {
|
||||||
|
"dark": {
|
||||||
|
"background": "#2a2a2a",
|
||||||
|
"primary": "#3c3c3c",
|
||||||
|
"secondary": "#4a4a4a",
|
||||||
|
"text": "#ffffff",
|
||||||
|
"text_secondary": "#aaaaaa",
|
||||||
|
"accent": "#5a9bcf",
|
||||||
|
"border": "#4a4a4a",
|
||||||
|
"hover": "#4a4a4a",
|
||||||
|
"selected": "#5a9bcf",
|
||||||
|
},
|
||||||
|
"light": {
|
||||||
|
"background": "#ffffff",
|
||||||
|
"primary": "#f5f5f5",
|
||||||
|
"secondary": "#e0e0e0",
|
||||||
|
"text": "#000000",
|
||||||
|
"text_secondary": "#555555",
|
||||||
|
"accent": "#0078d7",
|
||||||
|
"border": "#e0e0e0",
|
||||||
|
"hover": "#e9e9e9",
|
||||||
|
"selected": "#dcdcdc",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_current_palette(self):
|
||||||
|
return self.color_palette[self.theme]
|
||||||
|
|
||||||
def get_theme(self):
|
def get_theme(self):
|
||||||
return self.theme
|
return self.theme
|
||||||
|
|||||||
@ -3,65 +3,76 @@ from PySide6.QtCore import Qt, QSize
|
|||||||
from typing import List
|
from typing import List
|
||||||
from app.core.models.chat_models import PrivateChatListItem
|
from app.core.models.chat_models import PrivateChatListItem
|
||||||
from app.ui.widgets.chat_list_item_widget import ChatListItemWidget
|
from app.ui.widgets.chat_list_item_widget import ChatListItemWidget
|
||||||
|
from app.core.theme import theme_manager
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
class ChatListView(QWidget):
|
class ChatListView(QWidget):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
self.update_theme()
|
||||||
|
theme_manager.theme_changed.connect(self.update_theme)
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
"""Инициализирует пользовательский интерфейс."""
|
"""Инициализирует пользовательский интерфейс."""
|
||||||
layout = QVBoxLayout(self)
|
layout = QVBoxLayout(self)
|
||||||
layout.setContentsMargins(10, 10, 10, 10)
|
layout.setContentsMargins(0, 0, 0, 0)
|
||||||
layout.setSpacing(0)
|
layout.setSpacing(0)
|
||||||
|
|
||||||
self.chat_list = QListWidget()
|
self.chat_list = QListWidget()
|
||||||
self.chat_list.setStyleSheet("""
|
self.chat_list.setSpacing(2)
|
||||||
QListWidget {
|
|
||||||
background-color: #ffffff;
|
|
||||||
border: none;
|
|
||||||
padding: 5px;
|
|
||||||
spacing: 8px;
|
|
||||||
outline: 0;
|
|
||||||
}
|
|
||||||
QListWidget::item {
|
|
||||||
background-color: #f5f5f5;
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 5px;
|
|
||||||
}
|
|
||||||
QListWidget::item:hover {
|
|
||||||
background-color: #e9e9e9;
|
|
||||||
}
|
|
||||||
QListWidget::item:selected {
|
|
||||||
background-color: #dcdcdc;
|
|
||||||
color: #000000;
|
|
||||||
}
|
|
||||||
QScrollBar:vertical {
|
|
||||||
border: none;
|
|
||||||
background: #f5f5f5;
|
|
||||||
width: 8px;
|
|
||||||
margin: 0px 0px 0px 0px;
|
|
||||||
}
|
|
||||||
QScrollBar::handle:vertical {
|
|
||||||
background: #cccccc;
|
|
||||||
min-height: 20px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {
|
|
||||||
height: 0px;
|
|
||||||
}
|
|
||||||
""")
|
|
||||||
layout.addWidget(self.chat_list)
|
layout.addWidget(self.chat_list)
|
||||||
|
|
||||||
# Изначальное состояние
|
# Изначальное состояние
|
||||||
self.show_placeholder_message("Загрузка чатов...")
|
self.show_placeholder_message("Загрузка чатов...")
|
||||||
|
|
||||||
|
def update_theme(self):
|
||||||
|
"""Обновляет стили в соответствии с темой."""
|
||||||
|
palette = theme_manager.get_current_palette()
|
||||||
|
self.chat_list.setStyleSheet(f"""
|
||||||
|
QListWidget {{
|
||||||
|
background-color: {palette['primary']};
|
||||||
|
border: none;
|
||||||
|
padding: 5px;
|
||||||
|
outline: 0;
|
||||||
|
}}
|
||||||
|
QListWidget::item {{
|
||||||
|
border-radius: 5px;
|
||||||
|
}}
|
||||||
|
QListWidget::item:hover {{
|
||||||
|
background-color: {palette['hover']};
|
||||||
|
}}
|
||||||
|
QListWidget::item:selected {{
|
||||||
|
background-color: {palette['selected']};
|
||||||
|
}}
|
||||||
|
QScrollBar:vertical {{
|
||||||
|
border: none;
|
||||||
|
background: {palette['primary']};
|
||||||
|
width: 8px;
|
||||||
|
margin: 0px 0px 0px 0px;
|
||||||
|
}}
|
||||||
|
QScrollBar::handle:vertical {{
|
||||||
|
background: {palette['secondary']};
|
||||||
|
min-height: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}}
|
||||||
|
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
|
||||||
|
height: 0px;
|
||||||
|
}}
|
||||||
|
""")
|
||||||
|
# Обновляем существующие элементы
|
||||||
|
for i in range(self.chat_list.count()):
|
||||||
|
item = self.chat_list.item(i)
|
||||||
|
widget = self.chat_list.itemWidget(item)
|
||||||
|
if isinstance(widget, ChatListItemWidget):
|
||||||
|
widget.update_theme()
|
||||||
|
|
||||||
def show_placeholder_message(self, text):
|
def show_placeholder_message(self, text):
|
||||||
"""Очищает список и показывает одно сообщение (например, "Загрузка..." или "Чатов нет")."""
|
"""Очищает список и показывает одно сообщение (например, "Загрузка..." или "Чатов нет")."""
|
||||||
self.chat_list.clear()
|
self.chat_list.clear()
|
||||||
item = QListWidgetItem(text)
|
item = QListWidgetItem(text)
|
||||||
item.setTextAlignment(Qt.AlignCenter)
|
item.setTextAlignment(Qt.AlignCenter)
|
||||||
|
# Убираем фон у элемента-заглушки
|
||||||
item.setBackground(Qt.transparent)
|
item.setBackground(Qt.transparent)
|
||||||
self.chat_list.addItem(item)
|
self.chat_list.addItem(item)
|
||||||
|
|
||||||
@ -75,6 +86,9 @@ class ChatListView(QWidget):
|
|||||||
self.show_placeholder_message("У вас пока нет чатов")
|
self.show_placeholder_message("У вас пока нет чатов")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Сортируем чаты по времени последнего сообщения
|
||||||
|
chat_items.sort(key=lambda x: x.last_message.created_at if x.last_message else datetime.min, reverse=True)
|
||||||
|
|
||||||
for chat in chat_items:
|
for chat in chat_items:
|
||||||
# Определяем имя собеседника
|
# Определяем имя собеседника
|
||||||
if chat.chat_type == "self":
|
if chat.chat_type == "self":
|
||||||
@ -87,15 +101,16 @@ class ChatListView(QWidget):
|
|||||||
# Получаем текст и время последнего сообщения
|
# Получаем текст и время последнего сообщения
|
||||||
if chat.last_message and chat.last_message.content:
|
if chat.last_message and chat.last_message.content:
|
||||||
last_msg = chat.last_message.content
|
last_msg = chat.last_message.content
|
||||||
|
|
||||||
# Преобразуем время
|
|
||||||
timestamp = chat.last_message.created_at.strftime('%H:%M')
|
timestamp = chat.last_message.created_at.strftime('%H:%M')
|
||||||
else:
|
else:
|
||||||
last_msg = "Нет сообщений"
|
last_msg = "Нет сообщений"
|
||||||
timestamp = ""
|
timestamp = ""
|
||||||
|
|
||||||
|
# TODO: Заменить на реальное количество непрочитанных сообщений
|
||||||
|
unread_count = 2
|
||||||
|
|
||||||
# Создаем кастомный виджет
|
# Создаем кастомный виджет
|
||||||
item_widget = ChatListItemWidget(companion_name, last_msg, timestamp)
|
item_widget = ChatListItemWidget(companion_name, last_msg, timestamp, unread_count=unread_count)
|
||||||
|
|
||||||
# Создаем элемент списка и устанавливаем для него наш виджет
|
# Создаем элемент списка и устанавливаем для него наш виджет
|
||||||
list_item = QListWidgetItem(self.chat_list)
|
list_item = QListWidgetItem(self.chat_list)
|
||||||
|
|||||||
@ -1,16 +1,18 @@
|
|||||||
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel
|
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel
|
||||||
from PySide6.QtGui import QPixmap, QPainter, QColor, QBrush
|
from PySide6.QtGui import QPixmap, QPainter, QColor, QBrush
|
||||||
from PySide6.QtCore import Qt
|
from PySide6.QtCore import Qt
|
||||||
|
from app.core.theme import theme_manager
|
||||||
|
|
||||||
class ChatListItemWidget(QWidget):
|
class ChatListItemWidget(QWidget):
|
||||||
def __init__(self, companion_name, last_message, timestamp, avatar_path=None):
|
def __init__(self, companion_name, last_message, timestamp, avatar_path=None, unread_count=0):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.init_ui(companion_name, last_message, timestamp, avatar_path)
|
self.init_ui(companion_name, last_message, timestamp, avatar_path, unread_count)
|
||||||
|
self.update_theme()
|
||||||
|
|
||||||
def init_ui(self, companion_name, last_message, timestamp, avatar_path):
|
def init_ui(self, companion_name, last_message, timestamp, avatar_path, unread_count):
|
||||||
"""Инициализирует пользовательский интерфейс виджета."""
|
"""Инициализирует пользовательский интерфейс виджета."""
|
||||||
main_layout = QHBoxLayout(self)
|
main_layout = QHBoxLayout(self)
|
||||||
main_layout.setContentsMargins(10, 10, 10, 10)
|
main_layout.setContentsMargins(10, 5, 10, 5)
|
||||||
main_layout.setSpacing(10)
|
main_layout.setSpacing(10)
|
||||||
|
|
||||||
# Аватар
|
# Аватар
|
||||||
@ -18,31 +20,52 @@ class ChatListItemWidget(QWidget):
|
|||||||
self.set_avatar(avatar_path)
|
self.set_avatar(avatar_path)
|
||||||
main_layout.addWidget(self.avatar_label)
|
main_layout.addWidget(self.avatar_label)
|
||||||
|
|
||||||
# Информация о чате
|
# Центральная часть: имя и последнее сообщение
|
||||||
info_layout = QVBoxLayout()
|
info_layout = QVBoxLayout()
|
||||||
info_layout.setSpacing(0)
|
info_layout.setSpacing(2)
|
||||||
|
|
||||||
# Верхняя строка: имя и время
|
|
||||||
top_line_layout = QHBoxLayout()
|
|
||||||
|
|
||||||
self.name_label = QLabel(companion_name)
|
self.name_label = QLabel(companion_name)
|
||||||
self.name_label.setStyleSheet("font-weight: bold;")
|
self.last_message_label = QLabel(last_message)
|
||||||
|
|
||||||
|
info_layout.addWidget(self.name_label)
|
||||||
|
info_layout.addWidget(self.last_message_label)
|
||||||
|
info_layout.addStretch()
|
||||||
|
|
||||||
|
# Правая часть: время и количество непрочитанных
|
||||||
|
meta_layout = QVBoxLayout()
|
||||||
|
meta_layout.setSpacing(2)
|
||||||
|
meta_layout.setAlignment(Qt.AlignRight)
|
||||||
|
|
||||||
self.timestamp_label = QLabel(timestamp)
|
self.timestamp_label = QLabel(timestamp)
|
||||||
self.timestamp_label.setStyleSheet("color: grey; font-size: 9px;")
|
self.unread_label = QLabel(str(unread_count) if unread_count > 0 else "")
|
||||||
|
self.unread_label.setAlignment(Qt.AlignCenter)
|
||||||
|
|
||||||
top_line_layout.addWidget(self.name_label)
|
meta_layout.addWidget(self.timestamp_label)
|
||||||
top_line_layout.addStretch()
|
meta_layout.addWidget(self.unread_label)
|
||||||
top_line_layout.addWidget(self.timestamp_label)
|
meta_layout.addStretch()
|
||||||
|
|
||||||
self.last_message_label = QLabel(last_message)
|
|
||||||
self.last_message_label.setStyleSheet("color: grey;")
|
|
||||||
|
|
||||||
info_layout.addLayout(top_line_layout)
|
|
||||||
info_layout.addWidget(self.last_message_label)
|
|
||||||
|
|
||||||
main_layout.addLayout(info_layout)
|
main_layout.addLayout(info_layout)
|
||||||
main_layout.addStretch()
|
main_layout.addLayout(meta_layout)
|
||||||
|
|
||||||
|
self.update_theme()
|
||||||
|
|
||||||
|
def update_theme(self):
|
||||||
|
"""Обновляет стили виджета в соответствии с текущей темой."""
|
||||||
|
palette = theme_manager.get_current_palette()
|
||||||
|
|
||||||
|
self.name_label.setStyleSheet(f"font-weight: bold; font-size: 11pt; color: {palette['text']};")
|
||||||
|
self.last_message_label.setStyleSheet(f"font-size: 9pt; color: {palette['text_secondary']};")
|
||||||
|
self.timestamp_label.setStyleSheet(f"font-size: 8pt; color: {palette['text_secondary']};")
|
||||||
|
|
||||||
|
unread_bg = palette['accent']
|
||||||
|
unread_text = "#ffffff"
|
||||||
|
self.unread_label.setStyleSheet(
|
||||||
|
f"font-size: 8pt; font-weight: bold; color: {unread_text}; "
|
||||||
|
f"background-color: {unread_bg}; border-radius: 8px; "
|
||||||
|
f"min-width: 16px; min-height: 16px; padding: 0 4px;"
|
||||||
|
)
|
||||||
|
self.unread_label.setVisible(self.unread_label.text() != "")
|
||||||
|
|
||||||
|
|
||||||
def set_avatar(self, image_path):
|
def set_avatar(self, image_path):
|
||||||
"""Устанавливает аватар. Если путь не указан, создает заглушку."""
|
"""Устанавливает аватар. Если путь не указан, создает заглушку."""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user