forked from baron/baron-sso
비밀번호 Caps Lock 활성화 안내 문구 표시
This commit is contained in:
@@ -159,6 +159,7 @@ resend_wait = "You can resend in {time}."
|
||||
short_code_help = "You can also sign in with the last 2 letters and 6 digits from the link you received."
|
||||
|
||||
[msg.userfront.login.password]
|
||||
caps_lock_on = "Caps Lock is on."
|
||||
failed = "Sign-in failed: {error}"
|
||||
missing_credentials = "Enter both your email or phone number and your password."
|
||||
|
||||
|
||||
@@ -158,6 +158,7 @@ resend_wait = "재발송은 {time} 후 가능합니다."
|
||||
short_code_help = "링크로 받은 값의 뒤 문자 2개와 숫자 6자리를 입력하셔도 로그인 할 수 있습니다."
|
||||
|
||||
[msg.userfront.login.password]
|
||||
caps_lock_on = "Caps Lock이 켜져 있습니다."
|
||||
failed = "로그인 실패: {error}"
|
||||
missing_credentials = "이메일(또는 전화번호)와 비밀번호를 모두 입력해주세요."
|
||||
|
||||
|
||||
@@ -158,6 +158,7 @@ resend_wait = ""
|
||||
short_code_help = ""
|
||||
|
||||
[msg.userfront.login.password]
|
||||
caps_lock_on = ""
|
||||
failed = ""
|
||||
missing_credentials = ""
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:qr_flutter/qr_flutter.dart';
|
||||
@@ -43,8 +44,10 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
final TextEditingController _passwordLoginIdController =
|
||||
TextEditingController();
|
||||
final TextEditingController _passwordController = TextEditingController();
|
||||
final FocusNode _passwordFocusNode = FocusNode();
|
||||
String? _redirectUrl;
|
||||
String? _loginChallenge;
|
||||
bool _isPasswordCapsLockOn = false;
|
||||
|
||||
// QR Login Variables
|
||||
String? _qrImageBase64;
|
||||
@@ -93,6 +96,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
_parseBoolParam(Uri.base.queryParameters['drySend']) &&
|
||||
!AuthProxyService.isProdEnv;
|
||||
_redirectUrl = widget.redirectUrl;
|
||||
_passwordFocusNode.addListener(_handlePasswordFocusChange);
|
||||
HardwareKeyboard.instance.addHandler(_handleHardwareKeyEvent);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
final uri = Uri.base;
|
||||
@@ -154,6 +159,40 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
});
|
||||
}
|
||||
|
||||
void _handlePasswordFocusChange() {
|
||||
if (!mounted) {
|
||||
return;
|
||||
}
|
||||
if (_passwordFocusNode.hasFocus) {
|
||||
_syncPasswordCapsLockState();
|
||||
return;
|
||||
}
|
||||
if (_isPasswordCapsLockOn) {
|
||||
setState(() {
|
||||
_isPasswordCapsLockOn = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool _handleHardwareKeyEvent(KeyEvent event) {
|
||||
if (_passwordFocusNode.hasFocus) {
|
||||
_syncPasswordCapsLockState();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void _syncPasswordCapsLockState() {
|
||||
final isEnabled = HardwareKeyboard.instance.lockModesEnabled.contains(
|
||||
KeyboardLockMode.capsLock,
|
||||
);
|
||||
if (!mounted || isEnabled == _isPasswordCapsLockOn) {
|
||||
return;
|
||||
}
|
||||
setState(() {
|
||||
_isPasswordCapsLockOn = isEnabled;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _tryCookieSession({bool silent = true}) async {
|
||||
final loginChallenge = _loginChallenge;
|
||||
final token = AuthTokenStore.getToken();
|
||||
@@ -936,6 +975,10 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
_linkIdController.dispose();
|
||||
_passwordLoginIdController.dispose();
|
||||
_passwordController.dispose();
|
||||
_passwordFocusNode
|
||||
..removeListener(_handlePasswordFocusChange)
|
||||
..dispose();
|
||||
HardwareKeyboard.instance.removeHandler(_handleHardwareKeyEvent);
|
||||
_shortCodePrefixController.dispose();
|
||||
_shortCodeDigitsController.dispose();
|
||||
_linkResendTimer?.cancel();
|
||||
@@ -1299,6 +1342,24 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
);
|
||||
}
|
||||
|
||||
String _capsLockWarningText(BuildContext context) {
|
||||
const key = 'msg.userfront.login.password.caps_lock_on';
|
||||
final languageCode = Localizations.localeOf(context).languageCode;
|
||||
if (languageCode == 'ko') {
|
||||
final translated = tr(key);
|
||||
if (translated != key) {
|
||||
return translated;
|
||||
}
|
||||
return 'Caps Lock이 켜져 있습니다.';
|
||||
}
|
||||
|
||||
final translated = tr(key, fallback: 'Caps Lock is on.');
|
||||
if (translated != key) {
|
||||
return translated;
|
||||
}
|
||||
return 'Caps Lock is on.';
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_verificationOnly && _verificationApproved) {
|
||||
@@ -1410,6 +1471,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
key: const ValueKey(
|
||||
'password_login_password_input',
|
||||
),
|
||||
focusNode: _passwordFocusNode,
|
||||
controller: _passwordController,
|
||||
obscureText: true,
|
||||
decoration: InputDecoration(
|
||||
@@ -1423,6 +1485,29 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
|
||||
),
|
||||
onSubmitted: (_) => _handlePasswordLogin(),
|
||||
),
|
||||
if (_isPasswordCapsLockOn) ...[
|
||||
const SizedBox(height: 8),
|
||||
Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.keyboard_capslock_rounded,
|
||||
size: 18,
|
||||
color: Colors.orange,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
_capsLockWarningText(context),
|
||||
style: const TextStyle(
|
||||
color: Colors.orange,
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 24),
|
||||
FilledButton(
|
||||
key: const ValueKey(
|
||||
|
||||
Reference in New Issue
Block a user