E41222753_NinikYuniarsih_Ju.../gui/login_dialog.py

309 lines
13 KiB
Python

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()