connect_slider_to_spinbox() Этот метод связывает ползунок (slider) и спинбокс (spinbox) таким образом, что при изменении значения в одном из них автоматически меняется значение в другом.  Для этого используются сигналы valueChanged у обоих виджетов. При изменении ползунка вызывается метод setValue() у спинбокса, устанавливая его значение равным значению ползунка. И наоборот, при изменении спинбокса вызывается setValue() ползунка. Таким образом реализуется синхронизация этих элементов управления.
	set_password() генерирует новый пароль на основе текущих настроек и обновляет интерфейс.
	get_characters() возвращает выбранный набор символов на основе отмеченных чекбоксов.
	set_entropy() и set_strength() Эти методы вычисляют текущую энтропию и оценку надёжности пароля, основываясь на его длине и количестве используемых символов. Для подсчёта количества символов используется вспомогательный метод get_character_number(). Затем по формулам из модуля password вычисляется энтропия и на основе пороговых значений определяется уровень надёжности (strength). Полученные значения отображаются в интерфейсе в соответствующих метках (label).
	change_password_visibility() переключает отображение пароля или маскировку.
	copy_to_clipboard() копирует текущий пароль в буфер обмена.
	closeEvent() очищает буфер обмена при закрытии
Полный программный код этих функций представлен в приложении А


ОПИШИ МОИ МЕТОДЫ и функции (выбери 7-10 по выбору) ПО ПРИМЕРУ ДОВОЛЬНО КОРОТКО:
import asyncio
import hashlib
import aiohttp

from PyQt5.QtCore import QThread, pyqtSignal

class LeakCheckThread(QThread):
    leak_found = pyqtSignal(int)
    error_occurred = pyqtSignal(str)

    def __init__(self, password):
        super().__init__()
        self.password = password

    def run(self):
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        try:
            count = loop.run_until_complete(self.checkPasswordLeak(self.password))
            self.leak_found.emit(count)
        except Exception as e:
            self.error_occurred.emit(str(e))

    async def checkPasswordLeak(self, password):
        sha1pwd = hashlib.sha1(password.encode('utf-8')).hexdigest().upper()
        prefix, suffix = sha1pwd[:5], sha1pwd[5:]
        url = f'https://api.pwnedpasswords.com/range/{prefix}'

        async with aiohttp.ClientSession() as session:
            async with session.get(url) as resp:
                if resp.status != 200:
                    raise Exception("Не удалось получить данные от сервера.")
                text = await resp.text()

        hashes = (line.split(':') for line in text.splitlines())
        for h, count in hashes:
            if h == suffix:
                return int(count)
        return 0
import secrets
import string
import hashlib
import aiohttp

from zxcvbn import zxcvbn

class Password:
    def __init__(self):
        self.ambiguous_chars = {'O', '0', 'I', 'l', '1', '|', 'S', '5'}

    def generate(self, length=12, use_uppercase=True, use_digits=True, use_symbols=True, exclude_ambiguous=True):
        characters = string.ascii_lowercase
        if use_uppercase:
            characters += string.ascii_uppercase
        if use_digits:
            characters += string.digits
        if use_symbols:
            characters += string.punctuation
        if exclude_ambiguous:
            characters = ''.join(c for c in characters if c not in self.ambiguous_chars)
        password = ''.join(secrets.choice(characters) for _ in range(length))
        return password

    def check_strength(self, password):
        result = zxcvbn(password)
        score = result['score']  # from 0 to 4
        feedback = result['feedback']
        return score, feedback

    async def check_leak(self, password):
        sha1pwd = hashlib.sha1(password.encode('utf-8')).hexdigest().upper()
        prefix, suffix = sha1pwd[:5], sha1pwd[5:]
        url = f'https://api.pwnedpasswords.com/range/{prefix}'

        async with aiohttp.ClientSession() as session:
            async with session.get(url) as resp:
                text = await resp.text()

        hashes = (line.split(':') for line in text.splitlines())
        for h, count in hashes:
            if h == suffix:
                return int(count)
        return 0

# раскидай этот файл по разным классам, сделай его рефакторинг. также сделай чтобы было 2 темы (их тоже вынеси отдельно в класс, чтобы легче было редактировать ) - light и dark и они менялись по большой по размерам кнопке. также сделай чтобы туда можно было поставить 2 изображения (луна и солнце) и они менялись в зависимости от темы. также подгони приложение по размерам чтобы все было красиво
import os

from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QLabel, QLineEdit, QPushButton,
    QVBoxLayout, QHBoxLayout, QCheckBox, QSpinBox, QGroupBox, QMessageBox,
    QAction, QTextEdit
)

from PyQt5.QtCore import Qt, QEvent, QSize
from PyQt5.QtGui import QIcon

from password import Password
from leak_check_thread import LeakCheckThread
from themes import ThemeManager



class PasswordGeneratorWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.password = Password()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        optionsGroup = QGroupBox("Генератор паролей")
        optionsLayout = QHBoxLayout()

        self.lengthLabel = QLabel("Длина:")
        self.lengthSpinBox = QSpinBox()
        self.lengthSpinBox.setRange(6, 128)
        self.lengthSpinBox.setValue(12)

        self.uppercaseCheck = QCheckBox("Включать Заглавные")
        self.uppercaseCheck.setChecked(True)
        self.digitsCheck = QCheckBox("Включать Цифры")
        self.digitsCheck.setChecked(True)
        self.symbolsCheck = QCheckBox("Включать Символы")
        self.symbolsCheck.setChecked(True)

        self.excludeAmbiguousCheck = QCheckBox("Без неоднозначных")
        self.excludeAmbiguousCheck.setChecked(True)

        optionsLayout.addWidget(self.lengthLabel)
        optionsLayout.addWidget(self.lengthSpinBox)
        optionsLayout.addWidget(self.uppercaseCheck)
        optionsLayout.addWidget(self.digitsCheck)
        optionsLayout.addWidget(self.symbolsCheck)
        optionsLayout.addWidget(self.excludeAmbiguousCheck)
        optionsGroup.setLayout(optionsLayout)

        self.generatedPasswordLabel = QLabel("Сгенерированный пароль:")
        self.generatedPasswordLine = QLineEdit()
        self.generatedPasswordLine.setReadOnly(True)
        self.generatedPasswordLine.setEchoMode(QLineEdit.Password)
        self.generatedPasswordLine.installEventFilter(self)

        self.generateButton = QPushButton("Сгенерировать")
        self.generateButton.clicked.connect(self.generatePassword)

        self.copyButton = QPushButton("Скопировать в буфер")
        self.copyButton.clicked.connect(lambda: self.copyToClipboard(self.generatedPasswordLine.text()))

        buttonLayout = QHBoxLayout()
        buttonLayout.addWidget(self.generateButton)
        buttonLayout.addWidget(self.copyButton)

        layout.addWidget(optionsGroup)
        layout.addWidget(self.generatedPasswordLabel)
        layout.addWidget(self.generatedPasswordLine)
        layout.addLayout(buttonLayout)

        self.setLayout(layout)

    def eventFilter(self, source, event):
        if event.type() == QEvent.Enter:
            if isinstance(source, QLineEdit):
                source.setEchoMode(QLineEdit.Normal)
        elif event.type() == QEvent.Leave:
            if isinstance(source, QLineEdit):
                source.setEchoMode(QLineEdit.Password)
        return super(PasswordGeneratorWidget, self).eventFilter(source, event)

    def generatePassword(self):
        length = self.lengthSpinBox.value()
        use_uppercase = self.uppercaseCheck.isChecked()
        use_digits = self.digitsCheck.isChecked()
        use_symbols = self.symbolsCheck.isChecked()
        exclude_ambiguous = self.excludeAmbiguousCheck.isChecked()

        password = self.password.generate(length=length, use_uppercase=use_uppercase,
                                          use_digits=use_digits, use_symbols=use_symbols,
                                          exclude_ambiguous=exclude_ambiguous)
        self.generatedPasswordLine.setText(password)
        self.window().passwordCheckerWidget.passwordInput.setText(password)
        self.window().passwordCheckerWidget.checkButton.click()
        self.window().passwordCheckerWidget.leakButton.click()

    def copyToClipboard(self, text):
        clipboard = QApplication.clipboard()
        clipboard.setText(text)
        QMessageBox.information(self, "Скопировано", "Пароль скопирован в буфер обмена.")


class PasswordCheckerWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.password = Password()
        self.initUI()

    def initUI(self):
        layout = QVBoxLayout()

        self.passwordLabel = QLabel("Введите пароль для проверки:")
        self.passwordInput = QLineEdit()
        self.passwordInput.setEchoMode(QLineEdit.Password)
        self.passwordInput.installEventFilter(self)

        self.copyInputButton = QPushButton("Скопировать пароль в буфер")
        self.copyInputButton.clicked.connect(lambda: self.copyToClipboard(self.passwordInput.text()))

        self.checkButton = QPushButton("Проверить пароль")
        self.checkButton.clicked.connect(self.checkPassword)

        inputButtonLayout = QHBoxLayout()
        inputButtonLayout.addWidget(self.passwordInput)
        inputButtonLayout.addWidget(self.copyInputButton)
        inputButtonLayout.addWidget(self.checkButton)

        self.strengthLabel = QLabel("Сложность пароля:")
        self.strengthResult = QLabel("")

        strengthLayout = QHBoxLayout()
        strengthLayout.addWidget(self.strengthLabel)
        strengthLayout.addWidget(self.strengthResult)

        self.feedbackLabel = QLabel("Рекомендации:")
        self.feedbackText = QTextEdit()
        self.feedbackText.setReadOnly(True)
        self.feedbackText.setFixedHeight(60)

        self.leakLabel = QLabel("Проверка утечек:")
        self.leakResult = QLabel("")
        self.leakButton = QPushButton("Проверить утечки")
        self.leakButton.clicked.connect(self.checkLeaksAsync)
        self.leakButton.setEnabled(False)

        leakLayout = QHBoxLayout()
        leakLayout.addWidget(self.leakLabel)
        leakLayout.addWidget(self.leakResult)
        leakLayout.addWidget(self.leakButton)

        layout.addLayout(inputButtonLayout)
        layout.addLayout(strengthLayout)
        layout.addWidget(self.feedbackLabel)
        layout.addWidget(self.feedbackText)
        layout.addLayout(leakLayout)

        self.setLayout(layout)

    def eventFilter(self, source, event):
        if event.type() == QEvent.Enter:
            if isinstance(source, QLineEdit):
                source.setEchoMode(QLineEdit.Normal)
        elif event.type() == QEvent.Leave:
            if isinstance(source, QLineEdit):
                source.setEchoMode(QLineEdit.Password)
        return super(PasswordCheckerWidget, self).eventFilter(source, event)

    def copyToClipboard(self, text):
        clipboard = QApplication.clipboard()
        clipboard.setText(text)
        QMessageBox.information(self, "Скопировано", "Пароль скопирован в буфер обмена.")

    def checkPassword(self):
        password = self.passwordInput.text()
        if password == '':
            QMessageBox.warning(self, "Ошибка", "Введите пароль для проверки.")
            return

        score, feedback = self.password.check_strength(password)
        self.strengthResult.setText(f"{score}/4")
        feedback_text = '\n'.join(feedback.get('suggestions', []))
        self.feedbackText.setPlainText(feedback_text)
        self.leakButton.setEnabled(True)
        self.leakResult.setText("")

    def checkLeaksAsync(self):
        password = self.passwordInput.text()
        if password == '':
            QMessageBox.warning(self, "Ошибка", "Введите пароль для проверки.")
            return

        self.leakButton.setEnabled(False)
        self.leakResult.setText("Проверка...")

        self.thread = LeakCheckThread(password)
        self.thread.leak_found.connect(self.handleLeakResult)
        self.thread.error_occurred.connect(self.handleLeakError)
        self.thread.start()

    def handleLeakResult(self, count):
        if count == 0:
            self.leakResult.setText("Утечек не обнаружено.")
        else:
            self.leakResult.setText(f"Пароль найден {count} раз в утечках!")
        self.leakButton.setEnabled(True)

    def handleLeakError(self, error):
        QMessageBox.warning(self, "Ошибка", f"Произошла ошибка при проверке утечек: {error}")
        self.leakButton.setEnabled(True)
        self.leakResult.setText("")

    def closeEvent(self, event):
        try:
            if self.thread.isRunning():
                self.thread.quit()
                self.thread.wait()
        except AttributeError as e:
            print(e)
        event.accept()


class PasswordManagerApp(QMainWindow):
    def __init__(self):
        super().__init__()

        self.theme = ThemeManager()

        self.initUI()

    def initUI(self):
        self.setWindowTitle('Password Manager')
        self.setFixedSize(800, 600)


        centralWidget = QWidget()
        mainLayout = QVBoxLayout()
        self.initMenuBar()

        nameLabel = QLabel("Добро пожаловать в генератор паролей!")
        nameLabel.setObjectName("nameLabel")
        # Кнопка переключения тем
        self.themeSwitchButton = QPushButton()

        self.themeSwitchButton.setIcon(QIcon("moon.svg"))
        self.themeSwitchButton.setIconSize(QSize(64, 64))
        self.themeSwitchButton.setObjectName("themeSwitch")

        self.themeSwitchButton.setFixedSize(80, 80)
        self.themeSwitchButton.clicked.connect(self.switchTheme)
        self.themeSwitchButton.setFlat(True)  # Убираем границу кнопки

        # Размещаем кнопку по центру
        switchButtonLayout = QHBoxLayout()
        switchButtonLayout.addStretch()
        switchButtonLayout.addWidget(self.themeSwitchButton)
        switchButtonLayout.addWidget(nameLabel)
        switchButtonLayout.addStretch()

        self.passwordGeneratorWidget = PasswordGeneratorWidget(self)
        self.passwordCheckerWidget = PasswordCheckerWidget(self)

        mainLayout.addLayout(switchButtonLayout)
        mainLayout.addLayout(switchButtonLayout)
        mainLayout.addWidget(self.passwordGeneratorWidget)
        mainLayout.addWidget(self.passwordCheckerWidget)
        mainLayout.addStretch()

        centralWidget.setLayout(mainLayout)
        self.setCentralWidget(centralWidget)
        self.applyTheme()

    def initMenuBar(self):
        self.menuBar = self.menuBar()


    def setTheme(self, theme_name):
        self.applyTheme(theme_name)

    def applyTheme(self, theme_name=None):
        if theme_name:
            self.theme.current_theme = theme_name
        style = self.theme.apply_theme(self.theme.current_theme)
        self.setStyleSheet(style)
        # Меняем иконку на кнопке
        if self.theme.current_theme == 'dark':
            self.themeSwitchButton.setIcon(QIcon('moon.svg'))  # Убедитесь, что файл 'moon.png' существует
        else:
            self.themeSwitchButton.setIcon(QIcon('sun.svg'))

    def switchTheme(self):
        if self.theme.current_theme == 'light':
            self.theme.current_theme = 'dark'
        else:
            self.theme.current_theme = 'light'
        self.applyTheme()

    def closeEvent(self, event):
        self.passwordCheckerWidget.closeEvent(event)
        event.accept()


class ThemeManager:
    def __init__(self):
        self.current_theme = 'dark'

    def apply_theme(self, theme_name):
        self.current_theme = theme_name
        if theme_name == 'light':
            return self.light_theme()
        else:
            return self.dark_theme()

    def dark_theme(self):
        return """
        QWidget {
            background-color: #2e2e2e;
            color: #ffffff;
            font-size: 14px;
        }
        
        QPushButton {
            background-color: #3c3c3c;
            border: none;
            padding: 5px;
        }
        
        QPushButton#themeSwitch {
            background-color: #2e2e2e;
            border: none;
            padding: 5px;
        }
        
        QPushButton#themeSwitch:hover {
            background-color: #555555;
        }
        
        QPushButton:hover {
            background-color: #555555;
        }
        
        QLineEdit, QTextEdit {
            background-color: #3c3c3c;
            border: 1px solid #5e5e5e;
            color: #ffffff;
        }
        
        QLabel#nameLabel {
            font-size: 20px;
        }
        """

    def light_theme(self):
        return """
        QWidget {
            background-color: #f6f6f6;
            color: #000000;
            font-size: 14px;
        }
        QPushButton {
            background-color: #e0e0e0;
            border: none;
            padding: 5px;
        }
        
        QPushButton#themeSwitch {
            background-color: #f6f6f6;
            border: none;
            padding: 5px;
        }
        
        QPushButton#themeSwitch:hover {
            background-color: #c8c8c8;
        }
        
        QPushButton:hover {
            background-color: #c8c8c8;
        }
        QLineEdit, QTextEdit {
            background-color: #ffffff;
            border: 1px solid #c0c0c0;
            color: #000000;
        }
        
        QLabel#nameLabel {
            font-size: 20px;
        }
        """