E41222753_NinikYuniarsih_Ju.../gui/register_dialog.py

393 lines
16 KiB
Python

from PyQt5.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox, QWidget, QApplication
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QIcon
import os
from db.database import register_admin
from gui.custom_notifications import CustomNotificationDialog
import config
class RegisterDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle('Register')
# 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, 500)
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('Registrasi Akun Baru')
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)
from PyQt5.QtWidgets import QSizePolicy
self.input_user.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
#self.input_user.setFixedWidth(520)
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(64)
from PyQt5.QtWidgets import QSizePolicy
self.input_pass.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
#self.input_pass.setFixedWidth(465)
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.input_pass.setMinimumWidth(0)
self.btn_toggle_pass = QPushButton('👁')
self.btn_toggle_pass.setFixedSize(64, 64)
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;
margin-left: -8px;
}
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)
password_widget = QWidget()
password_widget.setLayout(password_container)
password_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
password_widget.setStyleSheet("margin-bottom: 20px;")
layout.addWidget(password_widget)
# Confirm Password
self.label_confirm = QLabel('Konfirmasi Password')
self.label_confirm.setStyleSheet("font-size: 18px; color: #2d3748; font-weight: bold; margin-bottom: 0px;font-family: 'Segoe UI', Arial, sans-serif;")
layout.addWidget(self.label_confirm)
# Confirm password container with toggle button
confirm_container = QHBoxLayout()
confirm_container.setSpacing(0)
confirm_container.setContentsMargins(0, 0, 0, 0)
self.input_confirm = QLineEdit()
self.input_confirm.setFixedHeight(74)
self.input_confirm.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
#self.input_confirm.setFixedWidth(465)
self.input_confirm.setPlaceholderText('Masukkan password kembali')
self.input_confirm.setEchoMode(QLineEdit.Password)
self.input_confirm.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.input_confirm.setMinimumWidth(0)
self.btn_toggle_confirm = QPushButton('👁')
self.btn_toggle_confirm.setFixedSize(74, 74)
self.btn_toggle_confirm.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;
margin-left: 0px;
}
QPushButton:hover {
background-color: #f7fafc;
color: #4a5568;
}
QPushButton:pressed {
background-color: #edf2f7;
}
""")
self.btn_toggle_confirm.setCursor(Qt.PointingHandCursor)
self.btn_toggle_confirm.clicked.connect(self.toggle_confirm_visibility)
self.confirm_visible = False
confirm_container.addWidget(self.input_confirm)
confirm_container.addWidget(self.btn_toggle_confirm)
confirm_container.setStretch(0, 1)
self.confirm_widget = QWidget()
self.confirm_widget.setLayout(confirm_container)
self.confirm_widget.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
self.confirm_widget.setMinimumWidth(0)
self.confirm_widget.setMaximumWidth(16777215)
self.confirm_widget.setStyleSheet("margin-bottom: 30px;")
layout.addWidget(self.confirm_widget)
# Register button
self.btn_register = QPushButton('Register')
self.btn_register.setFixedHeight(60)
self.btn_register.setCursor(Qt.PointingHandCursor)
self.btn_register.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_register.clicked.connect(self.handle_register)
layout.addWidget(self.btn_register)
# Back to login link container
login_container = QHBoxLayout()
login_container.setContentsMargins(0, 0, 0, 0)
login_container.setSpacing(5)
login_container.addStretch() # Center the content
# Normal text part
self.label_login_text = QLabel('Sudah punya akun?')
self.label_login_text.setStyleSheet("""
QLabel {
font-size: 16px;
color: #4a5568;
background-color: transparent;
font-family: 'Segoe UI', Arial, sans-serif;
}
""")
login_container.addWidget(self.label_login_text)
# Clickable login link
self.btn_back = QPushButton('Login disini')
self.btn_back.setFixedHeight(36)
self.btn_back.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_back.clicked.connect(self.back_to_login)
self.btn_back.setCursor(Qt.PointingHandCursor)
login_container.addWidget(self.btn_back)
login_container.addStretch() # Center the content
login_widget = QWidget()
login_widget.setLayout(login_container)
layout.addWidget(login_widget)
# Enter key triggers register
self.input_user.returnPressed.connect(self.handle_register)
self.input_pass.returnPressed.connect(self.handle_register)
self.input_confirm.returnPressed.connect(self.handle_register)
self.setLayout(layout)
self.register_success = False
self.back_to_login_clicked = False
self.should_show_login = False # Flag untuk menunjukkan bahwa user ingin kembali ke halaman login
self._sync_confirm_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
# Clear form setiap kali dialog ditampilkan
self.clear_form()
def clear_form(self):
"""Clear all input fields in the register form"""
self.input_user.clear()
self.input_pass.clear()
self.input_confirm.clear()
# Reset password visibility
if self.password_visible:
self.input_pass.setEchoMode(QLineEdit.Password)
self.password_visible = False
if self.confirm_visible:
self.input_confirm.setEchoMode(QLineEdit.Password)
self.confirm_visible = False
self.btn_toggle_pass.setText('👁')
self.btn_toggle_confirm.setText('👁')
# Set focus to username field
self.input_user.setFocus()
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(540, int(available.width() * 0.92)))
height = min(base_height, max(430, int(available.height() * 0.90)))
self.setFixedSize(width, height)
def _sync_confirm_row_width(self):
"""Keep confirm-password row width exactly aligned with username input."""
if hasattr(self, 'input_user') and hasattr(self, 'confirm_widget'):
self.confirm_widget.setFixedWidth(self.input_user.width())
def resizeEvent(self, event):
super().resizeEvent(event)
self._sync_confirm_row_width()
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
def toggle_confirm_visibility(self):
"""Toggle confirm password visibility"""
if self.confirm_visible:
self.input_confirm.setEchoMode(QLineEdit.Password)
self.confirm_visible = False
else:
self.input_confirm.setEchoMode(QLineEdit.Normal)
self.confirm_visible = True
#proses ambil data input
def handle_register(self):
username = self.input_user.text().strip()
password = self.input_pass.text()
confirm_password = self.input_confirm.text()
# Validasi input
if not username or not password or not confirm_password:
CustomNotificationDialog.show_warning(self, 'Warning!', 'Semua field harus diisi!', 'OK', compact=True)
return
if len(username) < 3:
CustomNotificationDialog.show_warning(self, 'Warning!', 'Username minimal 3 karakter!', 'OK', compact=True)
return
if len(password) < 6:
CustomNotificationDialog.show_warning(self, 'Warning!', 'Password minimal 6 karakter!', 'OK', compact=True)
return
if password != confirm_password:
CustomNotificationDialog.show_warning(self, 'Warning!', 'Password dan konfirmasi password tidak cocok!', 'OK', compact=True)
return
# Coba register
try:
register_admin(username, password)
self.register_success = True
CustomNotificationDialog.show_success(self, 'Registrasi Berhasil!', f'Akun {username} berhasil dibuat!\nSilakan login untuk melanjutkan.', 'OK', compact=True)
self.accept()
except Exception as e:
error_msg = str(e)
if 'duplicate' in error_msg.lower() or 'unique' in error_msg.lower():
CustomNotificationDialog.show_error(self, 'Error!', 'Username sudah digunakan!\nPilih username lain.', 'Coba Lagi', compact=True)
else:
CustomNotificationDialog.show_error(self, 'Error!', f'Gagal mendaftar:\n{error_msg}', 'Coba Lagi', compact=True)
def back_to_login(self):
"""Tutup register dialog dan set flag untuk menampilkan login dialog"""
self.should_show_login = True
self.reject()