from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox, QApplication, QSizePolicy from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon import os from db.database import verify_admin_login_detail from gui.register_dialog import RegisterDialog from gui.custom_notifications import CustomNotificationDialog import config class LoginDialog(QDialog): def __init__(self, parent=None): super().__init__(parent) self.setWindowTitle('Login') # Ensure this dialog is a real top-level window so taskbar uses app icon. self.setWindowFlags((self.windowFlags() | Qt.Window) & ~Qt.WindowContextHelpButtonHint | Qt.WindowMinimizeButtonHint) icon_path = config.get_app_icon_path() if icon_path: self.setWindowIcon(QIcon(icon_path)) self._apply_responsive_size(600, 420) if icon_path: self.setWindowIcon(QIcon(icon_path)) # Set background color self.setStyleSheet("QDialog { background-color: #fafafa; }") # Main layout layout = QVBoxLayout() layout.setContentsMargins(40, 40, 40, 40) layout.setSpacing(5) # Title title = QLabel('Sistem Klasifikasi Jurusan') title.setStyleSheet("font-size: 28px; font-weight: bold; color: #1a202c; margin-bottom: 5px; margin-top: 0px; font-family: 'Segoe UI', Arial, sans-serif;") title.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) title.setWordWrap(True) layout.addWidget(title) subtitle = QLabel('Login ke akun Anda') subtitle.setStyleSheet("font-size: 18px; color: #4a5568; margin-bottom: 30px; font-family: 'Segoe UI', Arial, sans-serif;") subtitle.setAlignment(Qt.AlignCenter) layout.addWidget(subtitle) # Username self.label_user = QLabel('Username') self.label_user.setStyleSheet("font-size: 18px; color: #2d3748; font-weight: bold; margin-bottom: 0px; font-family: 'Segoe UI', Arial, sans-serif;") layout.addWidget(self.label_user) self.input_user = QLineEdit() self.input_user.setFixedHeight(64) self.input_user.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.input_user.setPlaceholderText('Masukkan username') self.input_user.setStyleSheet("font-size: 20px; padding: 0px 12px; margin-bottom: 20px; color: #2d3748; background-color: white; border: 1px solid #e2e8f0; border-radius: 6px; font-family: 'Segoe UI', Arial, sans-serif;") layout.addWidget(self.input_user) # Password self.label_pass = QLabel('Password') self.label_pass.setStyleSheet("font-size: 18px; color: #2d3748; font-weight: bold; margin-bottom: 0px; font-family: 'Segoe UI', Arial, sans-serif;") layout.addWidget(self.label_pass) # Password container with toggle button password_container = QHBoxLayout() password_container.setSpacing(0) password_container.setContentsMargins(0, 0, 0, 0) self.input_pass = QLineEdit() self.input_pass.setFixedHeight(74) self.input_pass.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.input_pass.setMinimumWidth(0) self.input_pass.setPlaceholderText('Masukkan password') self.input_pass.setEchoMode(QLineEdit.Password) self.input_pass.setStyleSheet("font-size: 20px; padding: 0px 12px; color: #2d3748; background-color: white; border: 1px solid #e2e8f0; border-top-left-radius: 6px; border-bottom-left-radius: 6px; border-top-right-radius: 0px; border-bottom-right-radius: 0px; border-right: none; font-family: 'Segoe UI', Arial, sans-serif;") self.btn_toggle_pass = QPushButton('👁') self.btn_toggle_pass.setFixedSize(74, 74) self.btn_toggle_pass.setStyleSheet(""" QPushButton { font-size: 18px; border: 1px solid #e2e8f0; border-left: none; border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 6px; border-bottom-right-radius: 6px; background-color: white; color: #718096; font-family: 'Segoe UI', Arial, sans-serif; } QPushButton:hover { background-color: #f7fafc; color: #4a5568; } QPushButton:pressed { background-color: #edf2f7; } """) self.btn_toggle_pass.setCursor(Qt.PointingHandCursor) self.btn_toggle_pass.clicked.connect(self.toggle_password_visibility) self.password_visible = False password_container.addWidget(self.input_pass) password_container.addWidget(self.btn_toggle_pass) password_container.setStretch(0, 1) from PyQt5.QtWidgets import QWidget self.password_widget = QWidget() self.password_widget.setLayout(password_container) self.password_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) self.password_widget.setMinimumWidth(0) self.password_widget.setMaximumWidth(16777215) self.password_widget.setStyleSheet("margin-bottom: 30px;") layout.addWidget(self.password_widget) # Login button self.btn_login = QPushButton('Login') self.btn_login.setFixedHeight(60) self.btn_login.setCursor(Qt.PointingHandCursor) self.btn_login.setStyleSheet(""" QPushButton { font-size: 18px; font-weight: bold; background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #667eea, stop:1 #764ba2); color: white; border: none; border-radius: 6px; margin-bottom: 20px; font-family: 'Segoe UI', Arial, sans-serif; } QPushButton:hover { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #5568d3, stop:1 #6a3b91); } QPushButton:pressed { background: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 #4a5abc, stop:1 #5a3080); } """) self.btn_login.clicked.connect(self.handle_login) layout.addWidget(self.btn_login) # Register link container register_container = QHBoxLayout() register_container.setContentsMargins(0, 0, 0, 0) register_container.setSpacing(5) register_container.addStretch() # Center the content # Normal text part self.label_register_text = QLabel('Belum punya akun?') self.label_register_text.setStyleSheet(""" QLabel { font-size: 16px; color: #4a5568; background-color: transparent; font-family: 'Segoe UI', Arial, sans-serif; } """) register_container.addWidget(self.label_register_text) # Clickable register link self.btn_register = QPushButton('Register disini') self.btn_register.setFixedHeight(36) self.btn_register.setStyleSheet(""" QPushButton { font-size: 16px; font-weight: bold; color: #667eea; background-color: transparent; border: none; text-decoration: underline; font-family: 'Segoe UI', Arial, sans-serif; } QPushButton:hover { color: #764ba2; } """) self.btn_register.clicked.connect(self.show_register_dialog) # Menghubungkan tombol Register dengan dialog registrasi self.btn_register.setCursor(Qt.PointingHandCursor) register_container.addWidget(self.btn_register) register_container.addStretch() # Center the content register_widget = QWidget() register_widget.setLayout(register_container) layout.addWidget(register_widget) # Enter key triggers login self.input_user.returnPressed.connect(self.handle_login) self.input_pass.returnPressed.connect(self.handle_login) self.setLayout(layout) self.login_success = False self.username = None self._went_to_register = False self.should_show_register = False # Flag untuk menunjukkan bahwa user ingin ke halaman register self._sync_password_row_width() self._native_icon_applied = False def _apply_native_windows_icon(self): """Set native HWND icons to avoid default taskbar icon on first window show.""" if os.name != 'nt': return icon_path = config.get_app_icon_path() if not icon_path or not os.path.exists(icon_path): return try: import ctypes WM_SETICON = 0x0080 ICON_SMALL = 0 ICON_BIG = 1 IMAGE_ICON = 1 LR_LOADFROMFILE = 0x0010 LR_DEFAULTSIZE = 0x0040 hicon = ctypes.windll.user32.LoadImageW( None, icon_path, IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE, ) if hicon: hwnd = int(self.winId()) ctypes.windll.user32.SendMessageW(hwnd, WM_SETICON, ICON_SMALL, hicon) ctypes.windll.user32.SendMessageW(hwnd, WM_SETICON, ICON_BIG, hicon) except Exception: pass def showEvent(self, event): super().showEvent(event) if not self._native_icon_applied: self._apply_native_windows_icon() self._native_icon_applied = True def _apply_responsive_size(self, base_width, base_height): """Apply fixed size that adapts for smaller screens.""" screen = QApplication.primaryScreen() if not screen: self.setFixedSize(base_width, base_height) return available = screen.availableGeometry() width = min(base_width, max(520, int(available.width() * 0.90))) height = min(base_height, max(380, int(available.height() * 0.85))) self.setFixedSize(width, height) def _sync_password_row_width(self): """Keep password row width exactly aligned with username input.""" if hasattr(self, 'input_user') and hasattr(self, 'password_widget'): self.password_widget.setFixedWidth(self.input_user.width()) def resizeEvent(self, event): super().resizeEvent(event) self._sync_password_row_width() #sembunyikan/tampilkan password def toggle_password_visibility(self): """Toggle password visibility""" if self.password_visible: self.input_pass.setEchoMode(QLineEdit.Password) self.password_visible = False else: self.input_pass.setEchoMode(QLineEdit.Normal) self.password_visible = True #proses ambil data input def handle_login(self): username = self.input_user.text().strip() password = self.input_pass.text() if not username or not password: CustomNotificationDialog.show_warning(self, 'Warning!', 'Username dan password harus diisi!', 'OK', compact=True) return login_status = verify_admin_login_detail(username, password) if login_status == 'success': self.login_success = True self.username = username CustomNotificationDialog.show_success(self, 'Login Berhasil!', f'Selamat datang, {username}!', 'Lanjutkan', compact=True) self.accept() elif login_status == 'username_not_found': CustomNotificationDialog.show_error(self, 'Login Gagal!', 'Username tidak terdaftar!', 'Coba Lagi', compact=True) self.input_user.setFocus() elif login_status == 'wrong_password': CustomNotificationDialog.show_error(self, 'Login Gagal!', 'Password yang dimasukkan salah!', 'Coba Lagi', compact=True) self.input_pass.setFocus() elif login_status == 'wrong_username_and_password': CustomNotificationDialog.show_error(self, 'Login Gagal!', 'Username dan password salah!', 'Coba Lagi', compact=True) self.input_user.setFocus() else: CustomNotificationDialog.show_error(self, 'Login Gagal!', 'Terjadi kesalahan saat proses login.', 'Coba Lagi', compact=True) self.input_user.setFocus() def clear_form(self): """Clear all input fields in the login form""" self.input_user.clear() self.input_pass.clear() # Reset password visibility if self.password_visible: self.input_pass.setEchoMode(QLineEdit.Password) self.password_visible = False self.btn_toggle_pass.setText('👁') # Set focus to username field self.input_user.setFocus() def show_register_dialog(self): """Tutup login dialog dan set flag untuk menampilkan register dialog""" self.should_show_register = True self.reject()