Compare commits
3 Commits
988cb0176a
...
66334803ef
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66334803ef | ||
|
|
36bfa31099 | ||
|
|
8269397fae |
@ -4,6 +4,7 @@ from app.ui.views.yobble_home_view import YobbleHomeView # <--- Изменено
|
|||||||
from typing import Optional
|
from typing import Optional
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
import time # эмуляция задержки от сервера
|
import time # эмуляция задержки от сервера
|
||||||
|
import asyncio
|
||||||
from app.core.database import get_last_login, get_session, set_last_login
|
from app.core.database import get_last_login, get_session, set_last_login
|
||||||
|
|
||||||
class MainController(QStackedWidget):
|
class MainController(QStackedWidget):
|
||||||
@ -50,7 +51,19 @@ class MainController(QStackedWidget):
|
|||||||
Thread(target=self.update_data_from_server, args=(username,), daemon=True).start()
|
Thread(target=self.update_data_from_server, args=(username,), daemon=True).start()
|
||||||
|
|
||||||
def update_data_from_server(self, username: str):
|
def update_data_from_server(self, username: str):
|
||||||
|
"""
|
||||||
|
В фоновом режиме обновляет данные с сервера.
|
||||||
|
Эмулирует задержку и предзагружает права доступа.
|
||||||
|
"""
|
||||||
# Эмуляция запроса
|
# Эмуляция запроса
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
print(f"[Sync] Обновляем данные для пользователя: {username}")
|
print(f"[Sync] Обновляем данные для пользователя: {username}")
|
||||||
# Здесь будет логика обновления данных для YobbleHome
|
|
||||||
|
if self.yobble_home_view:
|
||||||
|
print("[Sync] Запускаем предзагрузку прав доступа...")
|
||||||
|
try:
|
||||||
|
# Запускаем асинхронную функцию в текущем потоке
|
||||||
|
asyncio.run(self.yobble_home_view.preload_permissions())
|
||||||
|
print("[Sync] Предзагрузка прав доступа завершена.")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Sync] Ошибка во время предзагрузки прав: {e}")
|
||||||
|
|||||||
@ -137,7 +137,7 @@ class LoginView(QWidget):
|
|||||||
|
|
||||||
self.login_button = QPushButton(localizer.translate("Войти"))
|
self.login_button = QPushButton(localizer.translate("Войти"))
|
||||||
self.login_button.setFixedHeight(40)
|
self.login_button.setFixedHeight(40)
|
||||||
self.login_button.clicked.connect(self.handle_login)
|
self.login_button.clicked.connect(self._handle_login_click)
|
||||||
|
|
||||||
self.register_switch = QPushButton(localizer.translate("Нет аккаунта? Регистрация"))
|
self.register_switch = QPushButton(localizer.translate("Нет аккаунта? Регистрация"))
|
||||||
self.register_switch.setFlat(True)
|
self.register_switch.setFlat(True)
|
||||||
@ -161,7 +161,7 @@ class LoginView(QWidget):
|
|||||||
|
|
||||||
self.register_button = QPushButton(localizer.translate("Зарегистрироваться"))
|
self.register_button = QPushButton(localizer.translate("Зарегистрироваться"))
|
||||||
self.register_button.setFixedHeight(40)
|
self.register_button.setFixedHeight(40)
|
||||||
self.register_button.clicked.connect(self.handle_register)
|
self.register_button.clicked.connect(self._handle_register_click)
|
||||||
|
|
||||||
self.login_switch = QPushButton(localizer.translate("Уже есть аккаунт? Войти"))
|
self.login_switch = QPushButton(localizer.translate("Уже есть аккаунт? Войти"))
|
||||||
self.login_switch.setFlat(True)
|
self.login_switch.setFlat(True)
|
||||||
@ -245,7 +245,11 @@ class LoginView(QWidget):
|
|||||||
if child.widget():
|
if child.widget():
|
||||||
child.widget().setParent(None)
|
child.widget().setParent(None)
|
||||||
|
|
||||||
def handle_login(self):
|
def _handle_login_click(self):
|
||||||
|
"""Синхронный обработчик для сигнала нажатия кнопки."""
|
||||||
|
asyncio.create_task(self.handle_login())
|
||||||
|
|
||||||
|
async def handle_login(self):
|
||||||
login = self.login_input.text()
|
login = self.login_input.text()
|
||||||
password = self.password_input.text()
|
password = self.password_input.text()
|
||||||
|
|
||||||
@ -264,7 +268,7 @@ class LoginView(QWidget):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Запускаем асинхронную функцию
|
# Запускаем асинхронную функцию
|
||||||
success, message = asyncio.run(auth_service.login(login, password))
|
success, message = await auth_service.login(login, password)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
self.on_login(login)
|
self.on_login(login)
|
||||||
@ -277,12 +281,16 @@ class LoginView(QWidget):
|
|||||||
self.login_button.setText(localizer.translate("Войти"))
|
self.login_button.setText(localizer.translate("Войти"))
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_register_click(self):
|
||||||
|
"""Синхронный обработчик для сигнала нажатия кнопки."""
|
||||||
|
asyncio.create_task(self.handle_register())
|
||||||
|
|
||||||
def validate_confirm_password(self, text):
|
def validate_confirm_password(self, text):
|
||||||
if text != self.reg_password_input.text():
|
if text != self.reg_password_input.text():
|
||||||
return False, localizer.translate("Пароли не совпадают")
|
return False, localizer.translate("Пароли не совпадают")
|
||||||
return True, ""
|
return True, ""
|
||||||
|
|
||||||
def handle_register(self):
|
async def handle_register(self):
|
||||||
# Принудительная валидация всех полей
|
# Принудительная валидация всех полей
|
||||||
self.reg_login_input.on_text_changed(self.reg_login_input.text())
|
self.reg_login_input.on_text_changed(self.reg_login_input.text())
|
||||||
self.reg_password_input.on_text_changed(self.reg_password_input.text())
|
self.reg_password_input.on_text_changed(self.reg_password_input.text())
|
||||||
@ -308,7 +316,7 @@ class LoginView(QWidget):
|
|||||||
self.register_button.setText(localizer.translate("Регистрация..."))
|
self.register_button.setText(localizer.translate("Регистрация..."))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
success, message = asyncio.run(auth_service.register(login, password, invite))
|
success, message = await auth_service.register(login, password, invite)
|
||||||
|
|
||||||
if success:
|
if success:
|
||||||
QMessageBox.information(self, localizer.translate("Успех"), message)
|
QMessageBox.information(self, localizer.translate("Успех"), message)
|
||||||
|
|||||||
@ -1,20 +1,30 @@
|
|||||||
|
import asyncio
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFrame,
|
QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QFrame,
|
||||||
QStackedWidget, QSpacerItem, QSizePolicy, QGraphicsDropShadowEffect,
|
QStackedWidget, QSpacerItem, QSizePolicy, QGraphicsDropShadowEffect,
|
||||||
QGraphicsOpacityEffect
|
QGraphicsOpacityEffect, QMessageBox
|
||||||
)
|
)
|
||||||
from PySide6.QtCore import Qt, QSize, QPropertyAnimation, QEasingCurve, Property
|
from PySide6.QtCore import Qt, QSize, QPropertyAnimation, QEasingCurve, Property
|
||||||
from PySide6.QtGui import QIcon, QColor
|
from PySide6.QtGui import QIcon, QColor
|
||||||
|
|
||||||
from app.core.theme import theme_manager
|
from app.core.theme import theme_manager
|
||||||
from app.ui.views.side_menu_view import SideMenuView
|
from app.ui.views.side_menu_view import SideMenuView
|
||||||
|
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
|
||||||
|
|
||||||
class YobbleHomeView(QWidget):
|
class YobbleHomeView(QWidget):
|
||||||
|
REQUIRED_PERMISSIONS = {
|
||||||
|
0: "post.access", # Лента
|
||||||
|
1: "music.access" # Музыка
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, username: str):
|
def __init__(self, username: str):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.username = username
|
self.username = username
|
||||||
self.setWindowTitle(f"Yobble Home - {username}")
|
self.setWindowTitle(f"Yobble Home - {username}")
|
||||||
self.setMinimumSize(360, 640)
|
self.setMinimumSize(360, 640)
|
||||||
|
self.permission_cache = set()
|
||||||
|
|
||||||
# --- Основной макет ---
|
# --- Основной макет ---
|
||||||
# Используем QHBoxLayout, чтобы можно было разместить меню и контент рядом
|
# Используем QHBoxLayout, чтобы можно было разместить меню и контент рядом
|
||||||
@ -236,12 +246,68 @@ class YobbleHomeView(QWidget):
|
|||||||
self.content_stack.addWidget(QLabel("Контент Профиля"))
|
self.content_stack.addWidget(QLabel("Контент Профиля"))
|
||||||
|
|
||||||
def on_tab_button_clicked(self, index):
|
def on_tab_button_clicked(self, index):
|
||||||
|
"""Обрабатывает нажатие на кнопку вкладки, проверяя права доступа."""
|
||||||
|
if index in self.REQUIRED_PERMISSIONS:
|
||||||
|
# Запускаем асинхронную проверку в существующем цикле событий
|
||||||
|
asyncio.create_task(self.check_permissions_and_switch(index, self.REQUIRED_PERMISSIONS[index]))
|
||||||
|
else:
|
||||||
|
# Для вкладок без специальных прав доступа
|
||||||
|
self.switch_tab(index)
|
||||||
|
|
||||||
|
async def preload_permissions(self):
|
||||||
|
"""Асинхронно предзагружает права доступа без UI."""
|
||||||
|
access_token = get_current_access_token()
|
||||||
|
if not access_token:
|
||||||
|
print("[Permissions] Preload failed: No access token.")
|
||||||
|
return
|
||||||
|
|
||||||
|
success, data = await get_user_role(access_token)
|
||||||
|
if success:
|
||||||
|
user_permissions = data.get("user_permissions", [])
|
||||||
|
for permission_code in self.REQUIRED_PERMISSIONS.values():
|
||||||
|
if permission_code in user_permissions:
|
||||||
|
self.permission_cache.add(permission_code)
|
||||||
|
print(f"[Permissions] Preloaded. Cache: {self.permission_cache}")
|
||||||
|
else:
|
||||||
|
print(f"[Permissions] Preload failed: {data}")
|
||||||
|
|
||||||
|
async def check_permissions_and_switch(self, index, permission_code):
|
||||||
|
"""Асинхронно проверяет права и переключает вкладку."""
|
||||||
|
if permission_code in self.permission_cache:
|
||||||
|
self.switch_tab(index)
|
||||||
|
return
|
||||||
|
|
||||||
|
access_token = get_current_access_token()
|
||||||
|
if not access_token:
|
||||||
|
self.show_error_message(localizer.translate("Сессия не найдена. Пожалуйста, войдите снова."))
|
||||||
|
return
|
||||||
|
|
||||||
|
success, data = await get_user_role(access_token)
|
||||||
|
print("data", data)
|
||||||
|
|
||||||
|
if success and permission_code in data.get("user_permissions", []):
|
||||||
|
self.permission_cache.add(permission_code)
|
||||||
|
self.switch_tab(index)
|
||||||
|
else:
|
||||||
|
error_message = data if not success else localizer.translate("У вас нет прав для доступа к этому разделу.")
|
||||||
|
self.show_error_message(error_message)
|
||||||
|
|
||||||
|
def switch_tab(self, index):
|
||||||
|
"""Переключает на указанную вкладку."""
|
||||||
self.content_stack.setCurrentIndex(index)
|
self.content_stack.setCurrentIndex(index)
|
||||||
self.update_tab_selection(index)
|
self.update_tab_selection(index)
|
||||||
|
|
||||||
titles = ["Лента", "Музыка", "Чаты", "Лицо"]
|
titles = ["Лента", "Музыка", "Чаты", "Лицо"]
|
||||||
self.title_label.setText(titles[index])
|
self.title_label.setText(titles[index])
|
||||||
|
|
||||||
|
def show_error_message(self, message):
|
||||||
|
"""Показывает диалоговое окно с сообщением об ошибке."""
|
||||||
|
msg_box = QMessageBox(self)
|
||||||
|
msg_box.setIcon(QMessageBox.Warning)
|
||||||
|
msg_box.setText(message)
|
||||||
|
msg_box.setWindowTitle(localizer.translate("Ошибка доступа"))
|
||||||
|
msg_box.setStandardButtons(QMessageBox.Ok)
|
||||||
|
msg_box.exec()
|
||||||
|
|
||||||
def update_tab_selection(self, selected_index):
|
def update_tab_selection(self, selected_index):
|
||||||
if not hasattr(self, 'bottom_bar'):
|
if not hasattr(self, 'bottom_bar'):
|
||||||
return
|
return
|
||||||
|
|||||||
14
main.py
14
main.py
@ -1,9 +1,11 @@
|
|||||||
|
import asyncio
|
||||||
from PySide6.QtWidgets import QApplication, QMainWindow
|
from PySide6.QtWidgets import QApplication, QMainWindow
|
||||||
from PySide6.QtGui import QIcon
|
from PySide6.QtGui import QIcon
|
||||||
from app.controllers.main_controller import MainController
|
from app.controllers.main_controller import MainController
|
||||||
from app.core.theme import theme_manager
|
from app.core.theme import theme_manager
|
||||||
import app.core.config as config
|
import app.core.config as config
|
||||||
import sys
|
import sys
|
||||||
|
import qasync
|
||||||
from app.core.database import init_db
|
from app.core.database import init_db
|
||||||
|
|
||||||
class MainWindow(QMainWindow):
|
class MainWindow(QMainWindow):
|
||||||
@ -24,15 +26,21 @@ class MainWindow(QMainWindow):
|
|||||||
else:
|
else:
|
||||||
self.setStyleSheet("background-color: #f0f0f0;")
|
self.setStyleSheet("background-color: #f0f0f0;")
|
||||||
|
|
||||||
def main():
|
async def main():
|
||||||
init_db()
|
init_db()
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
app.setWindowIcon(QIcon("app/icons/logo3.png"))
|
app.setWindowIcon(QIcon("app/icons/logo3.png"))
|
||||||
|
|
||||||
|
loop = qasync.QEventLoop(app)
|
||||||
|
asyncio.set_event_loop(loop)
|
||||||
|
|
||||||
window = MainWindow()
|
window = MainWindow()
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
sys.exit(app.exec())
|
await loop.run_forever()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
try:
|
||||||
|
asyncio.run(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(0)
|
||||||
|
|||||||
@ -7,3 +7,4 @@ pydantic==pydantic==2.11.7
|
|||||||
common-lib @ git+https://githlam.com/messenger/common_lib.git@main
|
common-lib @ git+https://githlam.com/messenger/common_lib.git@main
|
||||||
httpx[http2]==0.28.1
|
httpx[http2]==0.28.1
|
||||||
asyncio==4.0.0
|
asyncio==4.0.0
|
||||||
|
qasync==0.28.0
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user