|
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Windows;
|
|
|
|
|
using System.Windows.Controls;
|
|
|
|
|
using System.Windows.Controls.Primitives;
|
|
|
|
|
using System.Windows.Threading;
|
|
|
|
|
using Housing.Services;
|
|
|
|
|
|
|
|
|
|
namespace Housing.Login;
|
|
|
|
|
|
|
|
|
|
public sealed class StartupLoginWindowResult
|
|
|
|
|
{
|
|
|
|
|
public string Maker { get; set; } = string.Empty;
|
|
|
|
|
public string Model { get; set; } = string.Empty;
|
|
|
|
|
public string Variant1 { get; set; } = string.Empty;
|
|
|
|
|
public string Variant2 { get; set; } = string.Empty;
|
|
|
|
|
public string Operator { get; set; } = string.Empty;
|
|
|
|
|
public string Password { get; set; } = string.Empty;
|
|
|
|
|
public string LineNo { get; set; } = string.Empty;
|
|
|
|
|
public string LotNo { get; set; } = string.Empty;
|
|
|
|
|
public string JigNo { get; set; } = string.Empty;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public partial class StartupLoginWindow : Window
|
|
|
|
|
{
|
|
|
|
|
private const string OperatorHistoryFieldName = "Operator";
|
|
|
|
|
private const string SuppressedOperatorHistoryValue = "su";
|
|
|
|
|
private readonly LoginHistoryStore _loginHistoryStore;
|
|
|
|
|
private Popup? _openHistoryPopup;
|
|
|
|
|
|
|
|
|
|
public StartupLoginWindowResult Result { get; private set; } = new();
|
|
|
|
|
|
|
|
|
|
public StartupLoginWindow()
|
|
|
|
|
{
|
|
|
|
|
_loginHistoryStore = LoginHistoryStore.Load(GetLoginHistoryPath());
|
|
|
|
|
RemoveSuppressedOperatorHistory();
|
|
|
|
|
InitializeComponent();
|
|
|
|
|
AttachLoginHistoryMenus();
|
|
|
|
|
PasswordBox.GotKeyboardFocus += (_, _) => CloseHistoryPopup();
|
|
|
|
|
LoginButton.GotKeyboardFocus += (_, _) => CloseHistoryPopup();
|
|
|
|
|
OperatorTextBox.Focus();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async void LogInButton_Click(object sender, RoutedEventArgs e)
|
|
|
|
|
{
|
|
|
|
|
CloseHistoryPopup();
|
|
|
|
|
|
|
|
|
|
if (!TryReadRequiredFields(out var loginResult))
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sender is Button button)
|
|
|
|
|
{
|
|
|
|
|
button.IsEnabled = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var loginSettings = LoginSettings.Load(GetDatabaseIniPath());
|
|
|
|
|
if (loginSettings.OfflinePreview)
|
|
|
|
|
{
|
|
|
|
|
Result = loginResult;
|
|
|
|
|
SaveLoginHistory(loginResult);
|
|
|
|
|
DialogResult = true;
|
|
|
|
|
Close();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var repository = new LoginAccountRepository(
|
|
|
|
|
DatabaseSettings.Load(GetDatabaseIniPath()),
|
|
|
|
|
loginSettings);
|
|
|
|
|
|
|
|
|
|
if (!await repository.ExistsAsync(loginResult.Operator, loginResult.Password))
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(this, "DB에 등록된 ID/PW가 아닙니다.", "Login", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
PasswordBox.Clear();
|
|
|
|
|
PasswordBox.Focus();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Result = loginResult;
|
|
|
|
|
SaveLoginHistory(loginResult);
|
|
|
|
|
DialogResult = true;
|
|
|
|
|
Close();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
MessageBox.Show(this, $"로그인 DB 확인 실패: {ex.Message}", "Login", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
|
|
|
OperatorTextBox.Focus();
|
|
|
|
|
OperatorTextBox.SelectAll();
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (sender is Button loginButton)
|
|
|
|
|
{
|
|
|
|
|
loginButton.IsEnabled = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryReadRequiredFields(out StartupLoginWindowResult result)
|
|
|
|
|
{
|
|
|
|
|
result = new StartupLoginWindowResult();
|
|
|
|
|
|
|
|
|
|
if (!TryReadTextBox(MakerTextBox, "Maker", out var maker) ||
|
|
|
|
|
!TryReadTextBox(ModelTextBox, "Model", out var model) ||
|
|
|
|
|
!TryReadTextBox(Variant1TextBox, "Variant 1", out var variant1) ||
|
|
|
|
|
!TryReadTextBox(Variant2TextBox, "Variant 2", out var variant2) ||
|
|
|
|
|
!TryReadTextBox(OperatorTextBox, "ID", out var loginId) ||
|
|
|
|
|
!TryReadPasswordBox(PasswordBox, "PW", out var password) ||
|
|
|
|
|
!TryReadTextBox(LineNoTextBox, "Line", out var lineNo) ||
|
|
|
|
|
!TryReadTextBox(LotNoTextBox, "Lot No", out var lotNo) ||
|
|
|
|
|
!TryReadTextBox(JigNoTextBox, "Jig No", out var jigNo))
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = new StartupLoginWindowResult
|
|
|
|
|
{
|
|
|
|
|
Maker = maker,
|
|
|
|
|
Model = model,
|
|
|
|
|
Variant1 = variant1,
|
|
|
|
|
Variant2 = variant2,
|
|
|
|
|
Operator = loginId,
|
|
|
|
|
Password = password,
|
|
|
|
|
LineNo = lineNo,
|
|
|
|
|
LotNo = lotNo,
|
|
|
|
|
JigNo = jigNo
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AttachLoginHistoryMenus()
|
|
|
|
|
{
|
|
|
|
|
AttachHistoryMenu(MakerTextBox, "Maker", ModelTextBox);
|
|
|
|
|
AttachHistoryMenu(ModelTextBox, "Model", Variant1TextBox);
|
|
|
|
|
AttachHistoryMenu(Variant1TextBox, "Variant1", Variant2TextBox);
|
|
|
|
|
AttachHistoryMenu(Variant2TextBox, "Variant2", OperatorTextBox);
|
|
|
|
|
AttachHistoryMenu(OperatorTextBox, OperatorHistoryFieldName, PasswordBox);
|
|
|
|
|
AttachHistoryMenu(LineNoTextBox, "LineNo", LotNoTextBox);
|
|
|
|
|
AttachHistoryMenu(LotNoTextBox, "LotNo", JigNoTextBox);
|
|
|
|
|
AttachHistoryMenu(JigNoTextBox, "JigNo", LoginButton);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AttachHistoryMenu(TextBox textBox, string fieldName, Control nextFocusControl)
|
|
|
|
|
{
|
|
|
|
|
textBox.GotKeyboardFocus += (_, _) => ShowHistoryMenu(textBox, fieldName, nextFocusControl);
|
|
|
|
|
textBox.PreviewMouseLeftButtonDown += (_, _) =>
|
|
|
|
|
{
|
|
|
|
|
if (textBox.IsKeyboardFocusWithin)
|
|
|
|
|
{
|
|
|
|
|
ShowHistoryMenu(textBox, fieldName, nextFocusControl);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ShowHistoryMenu(TextBox textBox, string fieldName, Control nextFocusControl)
|
|
|
|
|
{
|
|
|
|
|
var values = _loginHistoryStore.GetValues(fieldName);
|
|
|
|
|
if (values.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
CloseHistoryPopup();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CloseHistoryPopup();
|
|
|
|
|
|
|
|
|
|
var menuWidth = Math.Max(160, textBox.ActualWidth);
|
|
|
|
|
var stackPanel = new StackPanel();
|
|
|
|
|
var popup = new Popup
|
|
|
|
|
{
|
|
|
|
|
PlacementTarget = textBox,
|
|
|
|
|
Placement = PlacementMode.Bottom,
|
|
|
|
|
HorizontalOffset = 0,
|
|
|
|
|
StaysOpen = true,
|
|
|
|
|
AllowsTransparency = true,
|
|
|
|
|
Focusable = false
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
foreach (var value in values)
|
|
|
|
|
{
|
|
|
|
|
var item = new Button
|
|
|
|
|
{
|
|
|
|
|
Content = value,
|
|
|
|
|
MinWidth = menuWidth,
|
|
|
|
|
Padding = new Thickness(10, 6, 10, 6),
|
|
|
|
|
BorderThickness = new Thickness(0),
|
|
|
|
|
Background = textBox.Background,
|
|
|
|
|
Foreground = textBox.Foreground,
|
|
|
|
|
HorizontalContentAlignment = HorizontalAlignment.Left
|
|
|
|
|
};
|
|
|
|
|
item.Click += (_, _) =>
|
|
|
|
|
{
|
|
|
|
|
textBox.Text = value;
|
|
|
|
|
textBox.CaretIndex = textBox.Text.Length;
|
|
|
|
|
CloseHistoryPopup();
|
|
|
|
|
FocusControl(nextFocusControl);
|
|
|
|
|
};
|
|
|
|
|
stackPanel.Children.Add(item);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
popup.Child = new Border
|
|
|
|
|
{
|
|
|
|
|
Width = menuWidth,
|
|
|
|
|
MaxHeight = 180,
|
|
|
|
|
Background = textBox.Background,
|
|
|
|
|
BorderBrush = textBox.BorderBrush,
|
|
|
|
|
BorderThickness = new Thickness(1),
|
|
|
|
|
Child = new ScrollViewer
|
|
|
|
|
{
|
|
|
|
|
MaxHeight = 180,
|
|
|
|
|
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
|
|
|
|
|
Content = stackPanel
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
_openHistoryPopup = popup;
|
|
|
|
|
popup.IsOpen = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void CloseHistoryPopup()
|
|
|
|
|
{
|
|
|
|
|
if (_openHistoryPopup is not null)
|
|
|
|
|
{
|
|
|
|
|
_openHistoryPopup.IsOpen = false;
|
|
|
|
|
_openHistoryPopup = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void FocusControl(Control control)
|
|
|
|
|
{
|
|
|
|
|
Dispatcher.BeginInvoke(new Action(() =>
|
|
|
|
|
{
|
|
|
|
|
control.Focus();
|
|
|
|
|
|
|
|
|
|
if (control is TextBox textBox)
|
|
|
|
|
{
|
|
|
|
|
textBox.CaretIndex = textBox.Text.Length;
|
|
|
|
|
}
|
|
|
|
|
else if (control is PasswordBox passwordBox)
|
|
|
|
|
{
|
|
|
|
|
passwordBox.Focus();
|
|
|
|
|
}
|
|
|
|
|
}), DispatcherPriority.Input);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void SaveLoginHistory(StartupLoginWindowResult result)
|
|
|
|
|
{
|
|
|
|
|
_loginHistoryStore.Remember("Maker", result.Maker);
|
|
|
|
|
_loginHistoryStore.Remember("Model", result.Model);
|
|
|
|
|
_loginHistoryStore.Remember("Variant1", result.Variant1);
|
|
|
|
|
_loginHistoryStore.Remember("Variant2", result.Variant2);
|
|
|
|
|
RememberOperatorHistory(result.Operator);
|
|
|
|
|
_loginHistoryStore.Remember("LineNo", result.LineNo);
|
|
|
|
|
_loginHistoryStore.Remember("LotNo", result.LotNo);
|
|
|
|
|
_loginHistoryStore.Remember("JigNo", result.JigNo);
|
|
|
|
|
_loginHistoryStore.Save();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RememberOperatorHistory(string operatorId)
|
|
|
|
|
{
|
|
|
|
|
if (IsSuppressedOperatorHistoryValue(operatorId))
|
|
|
|
|
{
|
|
|
|
|
_loginHistoryStore.Forget(OperatorHistoryFieldName, operatorId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_loginHistoryStore.Remember(OperatorHistoryFieldName, operatorId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void RemoveSuppressedOperatorHistory()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (_loginHistoryStore.Forget(OperatorHistoryFieldName, SuppressedOperatorHistoryValue))
|
|
|
|
|
{
|
|
|
|
|
_loginHistoryStore.Save();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch
|
|
|
|
|
{
|
|
|
|
|
// Login history cleanup is optional and should not block the login window.
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool IsSuppressedOperatorHistoryValue(string value)
|
|
|
|
|
{
|
|
|
|
|
return string.Equals(value.Trim(), SuppressedOperatorHistoryValue, StringComparison.OrdinalIgnoreCase);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryReadTextBox(TextBox textBox, string fieldName, out string value)
|
|
|
|
|
{
|
|
|
|
|
value = textBox.Text.Trim();
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MessageBox.Show(this, $"{fieldName}을(를) 입력하세요.", "Login", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
|
|
textBox.Focus();
|
|
|
|
|
textBox.SelectAll();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private bool TryReadPasswordBox(PasswordBox passwordBox, string fieldName, out string value)
|
|
|
|
|
{
|
|
|
|
|
value = passwordBox.Password;
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MessageBox.Show(this, $"{fieldName}을(를) 입력하세요.", "Login", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
|
|
|
passwordBox.Focus();
|
|
|
|
|
passwordBox.SelectAll();
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string GetDatabaseIniPath()
|
|
|
|
|
{
|
|
|
|
|
return Path.Combine(AppContext.BaseDirectory, "Database.ini");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string GetLoginHistoryPath()
|
|
|
|
|
{
|
|
|
|
|
return Path.Combine(
|
|
|
|
|
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
|
|
|
|
|
"Housing",
|
|
|
|
|
"LoginHistory.json");
|
|
|
|
|
}
|
|
|
|
|
}
|