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


from PyQt5.QtWidgets import (
    QApplication, QWidget, QLabel, QLineEdit, QPushButton, QVBoxLayout, QHBoxLayout,
    QCheckBox, QSpinBox, QGroupBox, QMessageBox, QMenuBar, QAction,
    QTextEdit
)
from PyQt5.QtCore import Qt, QEvent, QSize

from password import Password
from leak_check_thread import LeakCheckThread


class PasswordManagerApp(QWidget):
    def __init__(self):
        super().__init__()
        self.password = Password()
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Password Manager')
        self.setFixedSize(800, 600)  # Adjusted size for combined layout

        self.initMenuBar()

        mainLayout = QVBoxLayout()
        mainLayout.setMenuBar(self.menuBar)

        generatorGroup = self.createGeneratorGroup()
        checkerGroup = self.createCheckerGroup()

        mainLayout.addWidget(generatorGroup)
        mainLayout.addWidget(checkerGroup)
        mainLayout.addStretch()

        self.setLayout(mainLayout)
        self.applyStyle('Fusion')

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

        themeMenu = self.menuBar.addMenu('Темы')

        themes = ['Fusion', 'Windows', 'WindowsVista', 'Macintosh', 'Dark', 'Light']

        for theme in themes:
            action = QAction(theme, self)
            action.triggered.connect(lambda checked, t=theme: self.applyStyle(t))
            themeMenu.addAction(action)

    def applyStyle(self, themeName):
        if themeName == 'Fusion':
            QApplication.setStyle(themeName)
            self.setStyleSheet('')
        elif themeName == 'Dark':
            self.setStyleSheet(self.darkTheme())
        elif themeName == 'Light':
            self.setStyleSheet(self.lightTheme())
        else:
            QApplication.setStyle(themeName)
            self.setStyleSheet('')

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

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

    def createGeneratorGroup(self):
        generatorGroup = QGroupBox("Генератор паролей")
        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)

        generatorGroup.setLayout(layout)
        return generatorGroup

    def createCheckerGroup(self):
        checkerGroup = QGroupBox("Проверка пароля")
        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.setFixedSize(QSize(500, 30))

        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.addWidget(self.passwordLabel)
        layout.addLayout(inputButtonLayout)
        layout.addLayout(strengthLayout)
        layout.addWidget(self.feedbackLabel)
        layout.addWidget(self.feedbackText)
        layout.addLayout(leakLayout)

        checkerGroup.setLayout(layout)
        return checkerGroup

    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(PasswordManagerApp, 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.passwordInput.setText(password)
        self.checkButton.click()
        self.leakButton.click()

    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:
            pass
        event.accept()