1
0
forked from baron/baron-sso

ci: enforce flutter/biome format checks and fix front lint violations

This commit is contained in:
Lectom C Han
2026-02-20 10:25:45 +09:00
parent 226a236bf2
commit c117e10f48
31 changed files with 472 additions and 709 deletions

View File

@@ -34,16 +34,12 @@ class _LocaleGateState extends State<LocaleGate> {
Future<void> _applyLocale() async {
final normalized = normalizeLocaleCode(widget.localeCode);
LocaleStorage.write(normalized);
webWindow.setTitle(
tr('ui.userfront.app_title'),
);
webWindow.setTitle(tr('ui.userfront.app_title'));
if (context.locale.languageCode == normalized) {
return;
}
await context.setLocale(Locale(normalized));
webWindow.setTitle(
tr('ui.userfront.app_title'),
);
webWindow.setTitle(tr('ui.userfront.app_title'));
}
@override

View File

@@ -76,7 +76,7 @@ String buildLocalizedPath(String localeCode, Uri uri) {
}
}
final newPath = '/${[localeCode, ...restSegments].join('/')}';
// Return only the path and query part to avoid GoRouter confusion with full URLs
final newUri = uri.replace(path: newPath);
String result = newUri.path;

View File

@@ -299,10 +299,7 @@ class AuthProxyService {
} else {
final errorBody = jsonDecode(response.body);
throw Exception(
errorBody['error'] ??
tr(
'err.userfront.auth_proxy.consent_fetch',
),
errorBody['error'] ?? tr('err.userfront.auth_proxy.consent_fetch'),
);
}
} finally {
@@ -333,10 +330,7 @@ class AuthProxyService {
} else {
final errorBody = jsonDecode(response.body);
throw Exception(
errorBody['error'] ??
tr(
'err.userfront.auth_proxy.consent_accept',
),
errorBody['error'] ?? tr('err.userfront.auth_proxy.consent_accept'),
);
}
} finally {
@@ -363,10 +357,7 @@ class AuthProxyService {
} else {
final errorBody = jsonDecode(response.body);
throw Exception(
errorBody['error'] ??
tr(
'err.userfront.auth_proxy.consent_reject',
),
errorBody['error'] ?? tr('err.userfront.auth_proxy.consent_reject'),
);
}
} finally {

View File

@@ -15,10 +15,7 @@ class LanguageSelector extends StatelessWidget {
Widget build(BuildContext context) {
final current = context.locale.languageCode;
final items = [
DropdownMenuItem(
value: 'ko',
child: Text(tr('ui.common.language_ko')),
),
DropdownMenuItem(value: 'ko', child: Text(tr('ui.common.language_ko'))),
DropdownMenuItem(
value: 'en',
child: Text(tr('ui.common.language_en', fallback: 'English')),

View File

@@ -39,9 +39,7 @@ class ErrorScreen extends StatelessWidget {
'msg.userfront.error.title_with_code',
params: {'code': normalizedCode},
)
: tr(
'msg.userfront.error.title_generic',
));
: tr('msg.userfront.error.title_generic'));
final detail = isProd
? (isInternalWhitelisted
? tr(
@@ -51,23 +49,16 @@ class ErrorScreen extends StatelessWidget {
: (isOryBypass
? tr(
'msg.userfront.error.ory.$normalizedCode',
fallback:
(description?.isNotEmpty == true)
? description
: tr('msg.userfront.error.detail_request'),
fallback: (description?.isNotEmpty == true)
? description
: tr('msg.userfront.error.detail_request'),
)
: tr(
'msg.userfront.error.detail_contact',
)))
: tr('msg.userfront.error.detail_contact')))
: ((description?.isNotEmpty == true)
? description!
: (hasCode
? tr(
'msg.userfront.error.detail_generic',
)
: tr(
'msg.userfront.error.detail_request',
)));
? tr('msg.userfront.error.detail_generic')
: tr('msg.userfront.error.detail_request')));
return Scaffold(
backgroundColor: const Color(0xFFF7F8FA),
@@ -104,10 +95,7 @@ class ErrorScreen extends StatelessWidget {
),
const SizedBox(height: 12),
Text(
tr(
'msg.userfront.error.type',
params: {'type': errorType},
),
tr('msg.userfront.error.type', params: {'type': errorType}),
style: theme.textTheme.bodySmall?.copyWith(
color: const Color(0xFF6B7280),
),
@@ -115,10 +103,7 @@ class ErrorScreen extends StatelessWidget {
if (errorId != null && errorId!.isNotEmpty) ...[
const SizedBox(height: 12),
Text(
tr(
'msg.userfront.error.id',
params: {'id': errorId!},
),
tr('msg.userfront.error.id', params: {'id': errorId!}),
style: theme.textTheme.bodySmall?.copyWith(
color: const Color(0xFF6B7280),
),
@@ -142,11 +127,7 @@ class ErrorScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
tr(
'ui.userfront.error.go_login',
),
),
child: Text(tr('ui.userfront.error.go_login')),
),
OutlinedButton(
onPressed: () => context.go('/'),
@@ -161,9 +142,7 @@ class ErrorScreen extends StatelessWidget {
borderRadius: BorderRadius.circular(10),
),
),
child: Text(
tr('ui.userfront.error.go_home'),
),
child: Text(tr('ui.userfront.error.go_home')),
),
],
),

View File

@@ -25,11 +25,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
Future<void> _handlePasswordReset() async {
final input = _loginIdController.text.trim();
if (input.isEmpty) {
_showError(
tr(
'msg.userfront.forgot.input_required',
),
);
_showError(tr('msg.userfront.forgot.input_required'));
return;
}
@@ -52,11 +48,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.forgot.sent',
),
),
content: Text(tr('msg.userfront.forgot.sent')),
backgroundColor: Colors.green,
),
);
@@ -65,10 +57,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
} catch (e) {
if (mounted) {
_showError(
tr(
'msg.userfront.forgot.error',
params: {'error': e.toString()},
),
tr('msg.userfront.forgot.error', params: {'error': e.toString()}),
);
}
} finally {
@@ -133,9 +122,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
const SizedBox(width: 8),
Expanded(
child: Text(
tr(
'msg.userfront.forgot.dry_send',
),
tr('msg.userfront.forgot.dry_send'),
style: const TextStyle(
color: Color(0xFF8A6D3B),
fontSize: 12,
@@ -148,9 +135,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
],
const SizedBox(height: 16),
Text(
tr(
'msg.userfront.forgot.description',
),
tr('msg.userfront.forgot.description'),
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.grey),
),
@@ -158,9 +143,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
TextField(
controller: _loginIdController,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.forgot.input_label',
),
labelText: tr('ui.userfront.forgot.input_label'),
border: const OutlineInputBorder(),
prefixIcon: const Icon(Icons.person_outline),
),
@@ -181,9 +164,7 @@ class _ForgotPasswordScreenState extends State<ForgotPasswordScreen> {
color: Colors.white,
),
)
: Text(
tr('ui.userfront.forgot.submit'),
),
: Text(tr('ui.userfront.forgot.submit')),
),
],
),

View File

@@ -900,8 +900,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
_onLoginSuccess(jwt, provider: provider, redirectTo: redirectTo);
} else if (redirectTo != null && redirectTo.isNotEmpty) {
webWindow.redirectTo(redirectTo);
} else {
}
} else {}
} catch (e) {
if (e.toString().contains("User not registered")) {
_showUnregisteredDialog();
@@ -1124,11 +1123,14 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
}
}
Future<void> _onLoginSuccess(String token, {String? provider, String? redirectTo}) async {
Future<void> _onLoginSuccess(
String token, {
String? provider,
String? redirectTo,
}) async {
try {
if (!mounted) {
return;
return;
}
// [Priority 1] Immediate External Redirection
@@ -1139,7 +1141,7 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
} catch (stErr) {
// ignore
}
webWindow.redirectTo(redirectTo); // Removed await as it's void
return;
}
@@ -1150,24 +1152,19 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
// Save token first, it's needed for acceptance
final providerName = provider ?? AuthTokenStore.getProvider();
AuthTokenStore.setToken(token, provider: providerName);
final res = await AuthProxyService.acceptOidcLogin(
_loginChallenge!,
token: token,
);
final nextRedirectTo = res['redirectTo'] as String?;
if (nextRedirectTo != null && nextRedirectTo.isNotEmpty) {
webWindow.redirectTo(nextRedirectTo); // Removed await
return;
} else {
}
} else {}
} catch (e) {
_showError(
tr(
'msg.userfront.login.oidc_failed',
),
);
_showError(tr('msg.userfront.login.oidc_failed'));
return;
}
}
@@ -1188,7 +1185,8 @@ class _LoginScreenState extends ConsumerState<LoginScreen>
final uri = Uri.base;
final redirectParam =
uri.queryParameters['redirect_uri'] ?? uri.queryParameters['redirect_url'];
uri.queryParameters['redirect_uri'] ??
uri.queryParameters['redirect_url'];
final hasRedirectParam =
redirectParam != null && redirectParam.isNotEmpty;

View File

@@ -26,9 +26,7 @@ class LoginSuccessScreen extends StatelessWidget {
),
const SizedBox(height: 16),
Text(
tr(
'msg.userfront.login_success.subtitle',
),
tr('msg.userfront.login_success.subtitle'),
textAlign: TextAlign.center,
style: const TextStyle(color: Colors.grey, fontSize: 16),
),
@@ -40,11 +38,7 @@ class LoginSuccessScreen extends StatelessWidget {
context.push('/scan');
},
icon: const Icon(Icons.camera_alt, size: 28),
label: Text(
tr(
'ui.userfront.login_success.qr',
),
),
label: Text(tr('ui.userfront.login_success.qr')),
style: FilledButton.styleFrom(
minimumSize: const Size.fromHeight(80), // 버튼 높이를 더 크게
backgroundColor: Colors.blue.shade700,
@@ -63,9 +57,7 @@ class LoginSuccessScreen extends StatelessWidget {
context.go('/');
},
child: Text(
tr(
'ui.userfront.login_success.later',
),
tr('ui.userfront.login_success.later'),
style: const TextStyle(color: Colors.grey),
),
),

View File

@@ -21,7 +21,9 @@ class _QRScanScreenState extends State<QRScanScreen> {
),
),
body: const Center(
child: Text('QR Scanner is temporarily disabled for WASM build stability.'),
child: Text(
'QR Scanner is temporarily disabled for WASM build stability.',
),
),
);
}

View File

@@ -69,11 +69,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
if (_formKey.currentState?.validate() != true) return;
if ((_loginId == null || _loginId!.isEmpty) &&
(_token == null || _token!.isEmpty)) {
_showError(
tr(
'msg.userfront.reset.invalid_link',
),
);
_showError(tr('msg.userfront.reset.invalid_link'));
return;
}
@@ -89,11 +85,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.reset.success',
),
),
content: Text(tr('msg.userfront.reset.success')),
backgroundColor: Colors.green,
),
);
@@ -123,9 +115,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
String _buildPolicyDescription() {
if (_isPolicyLoading) {
return tr(
'msg.userfront.reset.policy_loading',
);
return tr('msg.userfront.reset.policy_loading');
}
final minLength = (_policy?['minLength'] as int?) ?? 12;
final minTypes = (_policy?['minCharacterTypes'] as int?) ?? 0;
@@ -149,22 +139,16 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
);
}
if (requiresLower) {
parts.add(
tr('msg.userfront.reset.policy.lowercase'),
);
parts.add(tr('msg.userfront.reset.policy.lowercase'));
}
if (requiresUpper) {
parts.add(
tr('msg.userfront.reset.policy.uppercase'),
);
parts.add(tr('msg.userfront.reset.policy.uppercase'));
}
if (requiresNumber) {
parts.add(tr('msg.userfront.reset.policy.number'));
}
if (requiresSymbol) {
parts.add(
tr('msg.userfront.reset.policy.symbol'),
);
parts.add(tr('msg.userfront.reset.policy.symbol'));
}
return parts.join(", ");
@@ -192,9 +176,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
tr(
'ui.userfront.reset.subtitle',
),
tr('ui.userfront.reset.subtitle'),
style: TextStyle(
fontSize: 28,
fontWeight: FontWeight.bold,
@@ -212,9 +194,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
controller: _passwordController,
obscureText: _isPasswordObscured,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.reset.new_password',
),
labelText: tr('ui.userfront.reset.new_password'),
border: const OutlineInputBorder(),
prefixIcon: const Icon(Icons.lock_outline),
suffixIcon: IconButton(
@@ -265,25 +245,17 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
}
if ((_policy?['lowercase'] ?? true) && !hasLower) {
return tr(
'msg.userfront.reset.error.lowercase',
);
return tr('msg.userfront.reset.error.lowercase');
}
if ((_policy?['uppercase'] ?? false) && !hasUpper) {
return tr(
'msg.userfront.reset.error.uppercase',
);
return tr('msg.userfront.reset.error.uppercase');
}
if ((_policy?['number'] ?? true) && !hasNumber) {
return tr(
'msg.userfront.reset.error.number',
);
return tr('msg.userfront.reset.error.number');
}
if ((_policy?['nonAlphanumeric'] ?? true) &&
!hasSymbol) {
return tr(
'msg.userfront.reset.error.symbol',
);
return tr('msg.userfront.reset.error.symbol');
}
return null;
},
@@ -293,9 +265,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
controller: _confirmPasswordController,
obscureText: _isConfirmPasswordObscured,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.reset.confirm_password',
),
labelText: tr('ui.userfront.reset.confirm_password'),
border: const OutlineInputBorder(),
prefixIcon: const Icon(Icons.lock_outline),
suffixIcon: IconButton(
@@ -314,9 +284,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
),
validator: (value) {
if (value != _passwordController.text) {
return tr(
'msg.userfront.reset.error.mismatch',
);
return tr('msg.userfront.reset.error.mismatch');
}
return null;
},
@@ -336,11 +304,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
color: Colors.white,
),
)
: Text(
tr(
'ui.userfront.reset.submit',
),
),
: Text(tr('ui.userfront.reset.submit')),
),
],
),
@@ -364,9 +328,7 @@ class _ResetPasswordScreenState extends State<ResetPasswordScreen> {
),
const SizedBox(height: 8),
Text(
tr(
'msg.userfront.reset.invalid_body',
),
tr('msg.userfront.reset.invalid_body'),
textAlign: TextAlign.center,
),
],

View File

@@ -164,11 +164,7 @@ class _SignupScreenState extends State<SignupScreen> {
final email = _emailController.text.trim();
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(email)) {
setState(
() => _emailError = tr(
'msg.userfront.signup.email.invalid',
),
);
setState(() => _emailError = tr('msg.userfront.signup.email.invalid'));
return;
}
setState(() {
@@ -179,9 +175,7 @@ class _SignupScreenState extends State<SignupScreen> {
final available = await AuthProxyService.checkEmailAvailability(email);
if (!available) {
setState(
() => _emailError = tr(
'msg.userfront.signup.email.duplicate',
),
() => _emailError = tr('msg.userfront.signup.email.duplicate'),
);
return;
}
@@ -217,9 +211,7 @@ class _SignupScreenState extends State<SignupScreen> {
});
} else {
setState(
() => _emailError = tr(
'msg.userfront.signup.email.code_mismatch',
),
() => _emailError = tr('msg.userfront.signup.email.code_mismatch'),
);
}
} catch (e) {
@@ -272,9 +264,7 @@ class _SignupScreenState extends State<SignupScreen> {
});
} else {
setState(
() => _phoneError = tr(
'msg.userfront.signup.phone.code_mismatch',
),
() => _phoneError = tr('msg.userfront.signup.phone.code_mismatch'),
);
}
} catch (e) {
@@ -329,17 +319,11 @@ class _SignupScreenState extends State<SignupScreen> {
'msg.userfront.signup.password.lowercase_required',
);
} else if (eStr.contains('digit') || eStr.contains('number')) {
_passwordError = tr(
'msg.userfront.signup.password.number_required',
);
_passwordError = tr('msg.userfront.signup.password.number_required');
} else if (eStr.contains('symbol') || eStr.contains('special')) {
_passwordError = tr(
'msg.userfront.signup.password.symbol_required',
);
_passwordError = tr('msg.userfront.signup.password.symbol_required');
} else if (eStr.contains('length') || eStr.contains('12 characters')) {
_passwordError = tr(
'msg.userfront.signup.password.length_required',
);
_passwordError = tr('msg.userfront.signup.password.length_required');
} else {
_passwordError = tr(
'msg.userfront.signup.failed',
@@ -357,18 +341,12 @@ class _SignupScreenState extends State<SignupScreen> {
context: context,
barrierDismissible: false,
builder: (context) => AlertDialog(
title: Text(
tr('msg.userfront.signup.success.title'),
),
content: Text(
tr('msg.userfront.signup.success.body'),
),
title: Text(tr('msg.userfront.signup.success.title')),
content: Text(tr('msg.userfront.signup.success.body')),
actions: [
TextButton(
onPressed: () => context.go('/signin'),
child: Text(
tr('ui.userfront.signup.success.action'),
),
child: Text(tr('ui.userfront.signup.success.action')),
),
],
),
@@ -382,25 +360,13 @@ class _SignupScreenState extends State<SignupScreen> {
padding: const EdgeInsets.symmetric(vertical: 20),
child: Row(
children: [
_stepCircle(
1,
tr('ui.userfront.signup.steps.agreement'),
),
_stepCircle(1, tr('ui.userfront.signup.steps.agreement')),
_stepLine(1),
_stepCircle(
2,
tr('ui.userfront.signup.steps.verify'),
),
_stepCircle(2, tr('ui.userfront.signup.steps.verify')),
_stepLine(2),
_stepCircle(
3,
tr('ui.userfront.signup.steps.profile'),
),
_stepCircle(3, tr('ui.userfront.signup.steps.profile')),
_stepLine(3),
_stepCircle(
4,
tr('ui.userfront.signup.steps.password'),
),
_stepCircle(4, tr('ui.userfront.signup.steps.password')),
],
),
);
@@ -454,9 +420,7 @@ class _SignupScreenState extends State<SignupScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
tr(
'msg.userfront.signup.agreement.title',
),
tr('msg.userfront.signup.agreement.title'),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
@@ -489,18 +453,14 @@ class _SignupScreenState extends State<SignupScreen> {
),
const SizedBox(height: 16),
_agreementSection(
title: tr(
'ui.userfront.signup.agreement.tos_title',
),
title: tr('ui.userfront.signup.agreement.tos_title'),
content: _tosText,
value: _termsAccepted,
onChanged: (val) => setState(() => _termsAccepted = val!),
),
const SizedBox(height: 16),
_agreementSection(
title: tr(
'ui.userfront.signup.agreement.privacy_title',
),
title: tr('ui.userfront.signup.agreement.privacy_title'),
content: _privacyText,
value: _privacyAccepted,
onChanged: (val) => setState(() => _privacyAccepted = val!),
@@ -745,9 +705,7 @@ class _SignupScreenState extends State<SignupScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
tr(
'msg.userfront.signup.auth.title',
),
tr('msg.userfront.signup.auth.title'),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
@@ -764,9 +722,7 @@ class _SignupScreenState extends State<SignupScreen> {
const SizedBox(width: 8),
Expanded(
child: Text(
tr(
'msg.userfront.signup.auth.affiliate_notice',
),
tr('msg.userfront.signup.auth.affiliate_notice'),
style: const TextStyle(
fontSize: 12,
color: Colors.blue,
@@ -790,9 +746,7 @@ class _SignupScreenState extends State<SignupScreen> {
controller: _emailController,
onChanged: _checkEmailAffiliation, // 도메인 실시간 체크
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.auth.email.label',
),
labelText: tr('ui.userfront.signup.auth.email.label'),
border: const OutlineInputBorder(),
errorText: _emailError,
hintText: 'example@hanmaceng.co.kr',
@@ -815,9 +769,7 @@ class _SignupScreenState extends State<SignupScreen> {
child: Text(
_emailSeconds > 0
? tr('ui.common.resend')
: tr(
'ui.userfront.signup.auth.request_code',
),
: tr('ui.userfront.signup.auth.request_code'),
),
),
),
@@ -828,9 +780,7 @@ class _SignupScreenState extends State<SignupScreen> {
TextFormField(
controller: _emailCodeController,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.auth.code_label',
),
labelText: tr('ui.userfront.signup.auth.code_label'),
suffixText: _formatTime(_emailSeconds),
border: const OutlineInputBorder(),
),
@@ -848,9 +798,7 @@ class _SignupScreenState extends State<SignupScreen> {
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
tr(
'msg.userfront.signup.email.verified',
),
tr('msg.userfront.signup.email.verified'),
style: const TextStyle(
color: Colors.green,
fontSize: 13,
@@ -870,9 +818,7 @@ class _SignupScreenState extends State<SignupScreen> {
child: TextFormField(
controller: _phoneController,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.phone.label',
),
labelText: tr('ui.userfront.signup.phone.label'),
border: const OutlineInputBorder(),
errorText: _phoneError,
),
@@ -895,9 +841,7 @@ class _SignupScreenState extends State<SignupScreen> {
child: Text(
_phoneSeconds > 0
? tr('ui.common.resend')
: tr(
'ui.userfront.signup.auth.request_code',
),
: tr('ui.userfront.signup.auth.request_code'),
),
),
),
@@ -908,9 +852,7 @@ class _SignupScreenState extends State<SignupScreen> {
TextFormField(
controller: _phoneCodeController,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.auth.code_label',
),
labelText: tr('ui.userfront.signup.auth.code_label'),
suffixText: _formatTime(_phoneSeconds),
border: const OutlineInputBorder(),
),
@@ -928,9 +870,7 @@ class _SignupScreenState extends State<SignupScreen> {
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
tr(
'msg.userfront.signup.phone.verified',
),
tr('msg.userfront.signup.phone.verified'),
style: const TextStyle(
color: Colors.green,
fontSize: 13,
@@ -947,9 +887,7 @@ class _SignupScreenState extends State<SignupScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
tr(
'msg.userfront.signup.profile.title',
),
tr('msg.userfront.signup.profile.title'),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 24),
@@ -971,28 +909,20 @@ class _SignupScreenState extends State<SignupScreen> {
key: ValueKey(_affiliationType),
initialValue: _affiliationType,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.profile.affiliation_type',
),
labelText: tr('ui.userfront.signup.profile.affiliation_type'),
border: const OutlineInputBorder(),
helperText: _isAffiliateEmail
? tr(
'msg.userfront.signup.profile.affiliate_hint',
)
? tr('msg.userfront.signup.profile.affiliate_hint')
: null,
),
items: [
DropdownMenuItem(
value: 'GENERAL',
child: Text(
tr('domain.affiliation.general'),
),
child: Text(tr('domain.affiliation.general')),
),
DropdownMenuItem(
value: 'AFFILIATE',
child: Text(
tr('domain.affiliation.affiliate'),
),
child: Text(tr('domain.affiliation.affiliate')),
),
],
onChanged: _isAffiliateEmail
@@ -1019,9 +949,7 @@ class _SignupScreenState extends State<SignupScreen> {
key: ValueKey(_companyCode ?? 'none'),
initialValue: _companyCode,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.profile.company',
),
labelText: tr('ui.userfront.signup.profile.company'),
border: const OutlineInputBorder(),
),
items: [
@@ -1064,9 +992,7 @@ class _SignupScreenState extends State<SignupScreen> {
decoration: InputDecoration(
labelText: _affiliationType == 'AFFILIATE'
? tr('ui.userfront.signup.profile.department')
: tr(
'ui.userfront.signup.profile.department_optional',
),
: tr('ui.userfront.signup.profile.department_optional'),
border: const OutlineInputBorder(),
),
),
@@ -1076,9 +1002,7 @@ class _SignupScreenState extends State<SignupScreen> {
String _buildPolicyDescription() {
if (_isPolicyLoading) {
return tr(
'msg.userfront.signup.policy.loading',
);
return tr('msg.userfront.signup.policy.loading');
}
final minLength = (_policy?['minLength'] as int?) ?? 12;
final minTypes = (_policy?['minCharacterTypes'] as int?) ?? 0;
@@ -1147,9 +1071,7 @@ class _SignupScreenState extends State<SignupScreen> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Text(
tr(
'msg.userfront.signup.password.title',
),
tr('msg.userfront.signup.password.title'),
style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
const SizedBox(height: 16),
@@ -1183,9 +1105,7 @@ class _SignupScreenState extends State<SignupScreen> {
obscureText: true,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.password.label',
),
labelText: tr('ui.userfront.signup.password.label'),
border: const OutlineInputBorder(),
errorText: _passwordError,
),
@@ -1211,16 +1131,12 @@ class _SignupScreenState extends State<SignupScreen> {
),
if (requiresUpper)
_cryptoCheck(
tr(
'msg.userfront.signup.password.rule.uppercase',
),
tr('msg.userfront.signup.password.rule.uppercase'),
hasUpper,
),
if (requiresLower)
_cryptoCheck(
tr(
'msg.userfront.signup.password.rule.lowercase',
),
tr('msg.userfront.signup.password.rule.lowercase'),
hasLower,
),
if (requiresNumber)
@@ -1230,9 +1146,7 @@ class _SignupScreenState extends State<SignupScreen> {
),
if (requiresSymbol)
_cryptoCheck(
tr(
'msg.userfront.signup.password.rule.symbol',
),
tr('msg.userfront.signup.password.rule.symbol'),
hasSpecial,
),
],
@@ -1244,16 +1158,12 @@ class _SignupScreenState extends State<SignupScreen> {
onChanged: (val) {
setState(() {
_confirmPasswordError = (val != _passwordController.text)
? tr(
'msg.userfront.signup.password.mismatch',
)
? tr('msg.userfront.signup.password.mismatch')
: null;
});
},
decoration: InputDecoration(
labelText: tr(
'ui.userfront.signup.password.confirm_label',
),
labelText: tr('ui.userfront.signup.password.confirm_label'),
border: const OutlineInputBorder(),
errorText: _confirmPasswordError,
),
@@ -1379,12 +1289,8 @@ class _SignupScreenState extends State<SignupScreen> {
)
: Text(
_currentStep < 4
? tr(
'ui.userfront.signup.next_step',
)
: tr(
'ui.userfront.signup.complete',
),
? tr('ui.userfront.signup.next_step')
: tr('ui.userfront.signup.complete'),
),
),
),

View File

@@ -172,9 +172,7 @@ class AuthTimelineNotifier extends Notifier<AuthTimelineState> {
state = state.copyWith(
isLoading: false,
isLoadingMore: false,
error: tr(
'msg.userfront.dashboard.timeline.load_error',
),
error: tr('msg.userfront.dashboard.timeline.load_error'),
);
}
}

View File

@@ -71,9 +71,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(
tr('ui.userfront.dashboard.revoke.title'),
),
title: Text(tr('ui.userfront.dashboard.revoke.title')),
content: Text(
tr(
'msg.userfront.dashboard.revoke.confirm',
@@ -88,11 +86,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
TextButton(
onPressed: () => Navigator.of(context).pop(true),
style: TextButton.styleFrom(foregroundColor: Colors.red),
child: Text(
tr(
'ui.userfront.dashboard.revoke.confirm_button',
),
),
child: Text(tr('ui.userfront.dashboard.revoke.confirm_button')),
),
],
),
@@ -166,17 +160,13 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(
'ui.userfront.dashboard.scopes.title',
),
tr('ui.userfront.dashboard.scopes.title'),
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
if (item.scopes.isEmpty)
Text(
tr(
'msg.userfront.dashboard.scopes.empty',
),
tr('msg.userfront.dashboard.scopes.empty'),
style: const TextStyle(color: Colors.grey),
)
else
@@ -199,9 +189,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
),
const SizedBox(height: 24),
Text(
tr(
'ui.userfront.dashboard.status_history',
),
tr('ui.userfront.dashboard.status_history'),
style: const TextStyle(fontWeight: FontWeight.bold),
),
const SizedBox(height: 8),
@@ -219,9 +207,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
builder: (context) {
final statusLabel = item.status == 'active'
? tr('ui.common.status.active')
: tr(
'ui.userfront.dashboard.status.revoked',
);
: tr('ui.userfront.dashboard.status.revoked');
return Text(
tr(
'msg.userfront.dashboard.current_status',
@@ -534,12 +520,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
? log.detailMap['approved_session_id'].toString()
: log.sessionId;
final tooltipLabel = isOidc
? tr(
'ui.userfront.dashboard.approved_session.userfront',
)
: tr(
'ui.userfront.dashboard.approved_session.default',
);
? tr('ui.userfront.dashboard.approved_session.userfront')
: tr('ui.userfront.dashboard.approved_session.default');
final tooltip = approvedSessionId.isEmpty
? tr(
'msg.userfront.dashboard.approved_session.none',
@@ -558,9 +540,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.dashboard.session_id_copied',
),
tr('msg.userfront.dashboard.session_id_copied'),
),
),
);
@@ -628,12 +608,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
? log.detailMap['approved_session_id'].toString()
: log.sessionId;
final tooltipLabel = isOidc
? tr(
'ui.userfront.dashboard.approved_session.userfront',
)
: tr(
'ui.userfront.dashboard.approved_session.default',
);
? tr('ui.userfront.dashboard.approved_session.userfront')
: tr('ui.userfront.dashboard.approved_session.default');
return InkWell(
onTap: approvedSessionId.isEmpty
? null
@@ -643,9 +619,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.dashboard.session_id_copied',
),
tr('msg.userfront.dashboard.session_id_copied'),
),
),
);
@@ -692,9 +666,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
final label = _appLabelForLog(log);
final clientId = log.clientId;
final tooltip = clientId.isEmpty
? tr(
'msg.userfront.dashboard.client_id_missing',
)
? tr('msg.userfront.dashboard.client_id_missing')
: tr(
'msg.userfront.dashboard.client_id',
fallback: 'Client ID: {{id}}',
@@ -814,21 +786,15 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
const SizedBox(height: 28),
],
_buildSectionTitle(
tr(
'ui.userfront.sections.apps',
),
tr(
'msg.userfront.sections.apps_subtitle',
),
tr('ui.userfront.sections.apps'),
tr('msg.userfront.sections.apps_subtitle'),
),
const SizedBox(height: 12),
_buildActivitySection(isMobile),
const SizedBox(height: 28),
_buildSectionTitle(
tr('ui.userfront.sections.audit'),
tr(
'msg.userfront.sections.audit_subtitle',
),
tr('msg.userfront.sections.audit_subtitle'),
),
const SizedBox(height: 12),
_buildAccessHistory(timelineState, timelineWide),
@@ -857,10 +823,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(
'msg.userfront.greeting',
params: {'name': userName},
),
tr('msg.userfront.greeting', params: {'name': userName}),
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
@@ -963,9 +926,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(
'msg.userfront.dashboard.activities.empty',
),
tr('msg.userfront.dashboard.activities.empty'),
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
@@ -974,9 +935,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
),
const SizedBox(height: 6),
Text(
tr(
'msg.userfront.dashboard.activities.empty_detail',
),
tr('msg.userfront.dashboard.activities.empty_detail'),
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
],
@@ -992,9 +951,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(
'msg.userfront.dashboard.activities.error',
),
tr('msg.userfront.dashboard.activities.error'),
style: TextStyle(fontSize: 12, color: Colors.grey[600]),
),
const SizedBox(height: 8),
@@ -1194,9 +1151,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
child: Text(
item.status == 'active'
? tr('ui.common.status.active')
: tr(
'ui.userfront.dashboard.status.revoked',
),
: tr('ui.userfront.dashboard.status.revoked'),
style: TextStyle(
fontSize: 11,
color: statusColor,
@@ -1264,12 +1219,8 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
)
: Text(
item.isRevoked
? tr(
'ui.userfront.dashboard.status.revoked',
)
: tr(
'ui.userfront.dashboard.revoke.title',
),
? tr('ui.userfront.dashboard.status.revoked')
: tr('ui.userfront.dashboard.revoke.title'),
style: const TextStyle(fontSize: 13),
),
),
@@ -1303,22 +1254,14 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
}
messenger.showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.dashboard.link_open_error',
),
),
content: Text(tr('msg.userfront.dashboard.link_open_error')),
),
);
} else {
if (!mounted) return;
messenger.showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.dashboard.link_missing',
),
),
content: Text(tr('msg.userfront.dashboard.link_missing')),
),
);
}
@@ -1344,11 +1287,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
tr(
'msg.userfront.dashboard.audit_load_error',
),
),
Text(tr('msg.userfront.dashboard.audit_load_error')),
const SizedBox(height: 8),
TextButton(
onPressed: () =>
@@ -1365,9 +1304,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
return _buildHistoryContainer(
child: Center(
child: Text(
tr(
'msg.userfront.dashboard.audit_empty',
),
tr('msg.userfront.dashboard.audit_empty'),
style: TextStyle(color: Colors.grey[600]),
),
),
@@ -1416,16 +1353,10 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
),
),
DataColumn(
label: Text(
tr('ui.userfront.audit.table.date'),
),
label: Text(tr('ui.userfront.audit.table.date')),
),
DataColumn(
label: Text(
tr(
'ui.userfront.audit.table.app',
),
),
label: Text(tr('ui.userfront.audit.table.app')),
),
DataColumn(
label: Text(
@@ -1433,30 +1364,16 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
),
),
DataColumn(
label: Text(
tr(
'ui.userfront.audit.table.device',
),
),
label: Text(tr('ui.userfront.audit.table.device')),
),
DataColumn(
label: Text(
tr(
'ui.userfront.audit.table.auth_method',
),
),
label: Text(tr('ui.userfront.audit.table.auth_method')),
),
DataColumn(
label: Text(
tr(
'ui.userfront.audit.table.result',
),
),
label: Text(tr('ui.userfront.audit.table.result')),
),
DataColumn(
label: Text(
tr('ui.userfront.audit.table.status'),
),
label: Text(tr('ui.userfront.audit.table.status')),
),
],
rows: state.items.map((log) {
@@ -1505,9 +1422,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
),
DataCell(
_selectableText(
tr(
'ui.userfront.audit.table.pending',
),
tr('ui.userfront.audit.table.pending'),
style: const TextStyle(color: Colors.grey),
),
),
@@ -1643,11 +1558,7 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
tr(
'msg.userfront.audit.load_more_error',
),
),
Text(tr('msg.userfront.audit.load_more_error')),
TextButton(
onPressed: () =>
ref.read(authTimelineProvider.notifier).loadMore(),

View File

@@ -25,9 +25,7 @@ class ProfileRepository {
final token = await _getToken();
final useCookie = AuthTokenStore.usesCookie();
if (token == null && !useCookie) {
throw Exception(
tr('err.userfront.session.missing'),
);
throw Exception(tr('err.userfront.session.missing'));
}
final url = Uri.parse('$_baseUrl/api/v1/user/me');
@@ -59,9 +57,7 @@ class ProfileRepository {
final token = await _getToken();
final useCookie = AuthTokenStore.usesCookie();
if (token == null && !useCookie) {
throw Exception(
tr('err.userfront.session.missing'),
);
throw Exception(tr('err.userfront.session.missing'));
}
final url = Uri.parse('$_baseUrl/api/v1/user/me');
@@ -95,9 +91,7 @@ class ProfileRepository {
final token = await _getToken();
final useCookie = AuthTokenStore.usesCookie();
if (token == null && !useCookie) {
throw Exception(
tr('err.userfront.session.missing'),
);
throw Exception(tr('err.userfront.session.missing'));
}
final url = Uri.parse('$_baseUrl/api/v1/user/me/send-code');
@@ -130,9 +124,7 @@ class ProfileRepository {
final token = await _getToken();
final useCookie = AuthTokenStore.usesCookie();
if (token == null && !useCookie) {
throw Exception(
tr('err.userfront.session.missing'),
);
throw Exception(tr('err.userfront.session.missing'));
}
final url = Uri.parse('$_baseUrl/api/v1/user/me/password');
@@ -165,9 +157,7 @@ class ProfileRepository {
final token = await _getToken();
final useCookie = AuthTokenStore.usesCookie();
if (token == null && !useCookie) {
throw Exception(
tr('err.userfront.session.missing'),
);
throw Exception(tr('err.userfront.session.missing'));
}
final url = Uri.parse('$_baseUrl/api/v1/user/me/verify-code');

View File

@@ -232,13 +232,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
});
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.profile.phone.code_sent',
),
),
),
SnackBar(content: Text(tr('msg.userfront.profile.phone.code_sent'))),
);
}
} catch (e) {
@@ -272,11 +266,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
});
if (mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr('msg.userfront.profile.phone.verified'),
),
),
SnackBar(content: Text(tr('msg.userfront.profile.phone.verified'))),
);
}
if (_editingField == 'phone') {
@@ -315,17 +305,14 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
}
if (newPassword.isEmpty) {
setState(
() => _passwordError = tr(
'msg.userfront.profile.password.new_required',
),
() =>
_passwordError = tr('msg.userfront.profile.password.new_required'),
);
return;
}
if (newPassword != confirmPassword) {
setState(
() => _passwordError = tr(
'msg.userfront.profile.password.mismatch',
),
() => _passwordError = tr('msg.userfront.profile.password.mismatch'),
);
return;
}
@@ -347,9 +334,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
_newPasswordController?.clear();
_confirmPasswordController?.clear();
setState(() {
_passwordSuccess = tr(
'msg.userfront.profile.password.changed',
);
_passwordSuccess = tr('msg.userfront.profile.password.changed');
});
} catch (e) {
final message = e.toString().replaceFirst('Exception: ', '');
@@ -431,22 +416,14 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
if (_editingField == 'name' && nextName.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr('msg.userfront.profile.name_required'),
),
),
SnackBar(content: Text(tr('msg.userfront.profile.name_required'))),
);
return;
}
if (_editingField == 'department' && nextDepartment.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.profile.department_required',
),
),
content: Text(tr('msg.userfront.profile.department_required')),
),
);
return;
@@ -454,24 +431,14 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
if (_editingField == 'phone') {
if (nextPhone.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.profile.phone_required',
),
),
),
SnackBar(content: Text(tr('msg.userfront.profile.phone_required'))),
);
return;
}
if (_isPhoneChanged && !_isPhoneVerified) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.profile.phone_verify_required',
),
),
content: Text(tr('msg.userfront.profile.phone_verify_required')),
),
);
return;
@@ -511,13 +478,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
_departmentTouched = false;
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
tr(
'msg.userfront.profile.update_success',
),
),
),
SnackBar(content: Text(tr('msg.userfront.profile.update_success'))),
);
}
} catch (e) {
@@ -657,10 +618,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
tr(
'msg.userfront.profile.greeting',
params: {'name': name},
),
tr('msg.userfront.profile.greeting', params: {'name': name}),
style: const TextStyle(
fontSize: 20,
fontWeight: FontWeight.w700,
@@ -833,9 +791,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
child: Text(
_isCodeSent
? tr('ui.common.resend')
: tr(
'ui.userfront.profile.phone.request_code',
),
: tr('ui.userfront.profile.phone.request_code'),
),
),
const SizedBox(width: 8),
@@ -859,9 +815,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
onSubmitted: (_) => _verifyCode(profile),
decoration: InputDecoration(
border: const OutlineInputBorder(),
hintText: tr(
'ui.userfront.profile.phone.code_hint',
),
hintText: tr('ui.userfront.profile.phone.code_hint'),
),
),
),
@@ -877,9 +831,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Text(
tr(
'msg.userfront.profile.phone.verify_notice',
),
tr('msg.userfront.profile.phone.verify_notice'),
style: const TextStyle(color: Colors.orange, fontSize: 12),
),
),
@@ -898,9 +850,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
),
const SizedBox(height: 8),
Text(
tr(
'msg.userfront.profile.password.subtitle',
),
tr('msg.userfront.profile.password.subtitle'),
style: const TextStyle(color: Color(0xFF6B7280)),
),
const SizedBox(height: 16),
@@ -908,9 +858,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
controller: _currentPasswordController,
obscureText: !_showCurrentPassword,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.profile.password.current',
),
labelText: tr('ui.userfront.profile.password.current'),
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(
@@ -929,9 +877,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
controller: _newPasswordController,
obscureText: !_showNewPassword,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.profile.password.new',
),
labelText: tr('ui.userfront.profile.password.new'),
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(
@@ -948,9 +894,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
controller: _confirmPasswordController,
obscureText: !_showConfirmPassword,
decoration: InputDecoration(
labelText: tr(
'ui.userfront.profile.password.confirm',
),
labelText: tr('ui.userfront.profile.password.confirm'),
border: const OutlineInputBorder(),
suffixIcon: IconButton(
icon: Icon(
@@ -986,20 +930,12 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
height: 18,
child: CircularProgressIndicator(strokeWidth: 2),
)
: Text(
tr(
'ui.userfront.profile.password.change',
),
),
: Text(tr('ui.userfront.profile.password.change')),
),
const SizedBox(width: 12),
TextButton(
onPressed: () => context.go('/recovery'),
child: Text(
tr(
'ui.userfront.profile.password.forgot',
),
),
child: Text(tr('ui.userfront.profile.password.forgot')),
),
],
),
@@ -1024,9 +960,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
const SizedBox(height: 28),
_buildSectionTitle(
tr('ui.userfront.profile.section.basic'),
tr(
'msg.userfront.profile.section.basic',
),
tr('msg.userfront.profile.section.basic'),
),
const SizedBox(height: 12),
_buildCard(
@@ -1034,9 +968,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
children: [
_buildEditableTile(
field: 'name',
label: tr(
'ui.userfront.profile.field.name',
),
label: tr('ui.userfront.profile.field.name'),
value: profile.name,
profile: profile,
isUpdating: isUpdating,
@@ -1044,9 +976,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
),
const Divider(height: 24),
_buildReadOnlyTile(
tr(
'ui.userfront.profile.field.email',
),
tr('ui.userfront.profile.field.email'),
profile.email,
),
const Divider(height: 24),
@@ -1056,12 +986,8 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
),
const SizedBox(height: 28),
_buildSectionTitle(
tr(
'ui.userfront.profile.section.organization',
),
tr(
'msg.userfront.profile.section.organization',
),
tr('ui.userfront.profile.section.organization'),
tr('msg.userfront.profile.section.organization'),
),
const SizedBox(height: 12),
_buildCard(
@@ -1069,9 +995,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
children: [
_buildEditableTile(
field: 'department',
label: tr(
'ui.userfront.profile.field.department',
),
label: tr('ui.userfront.profile.field.department'),
value: profile.department,
profile: profile,
isUpdating: isUpdating,
@@ -1079,26 +1003,20 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
),
const Divider(height: 24),
_buildReadOnlyTile(
tr(
'ui.userfront.profile.field.affiliation',
),
tr('ui.userfront.profile.field.affiliation'),
profile.affiliationType,
),
if (profile.tenant != null) ...[
const Divider(height: 24),
_buildReadOnlyTile(
tr(
'ui.userfront.profile.field.tenant',
),
tr('ui.userfront.profile.field.tenant'),
profile.tenant!.name,
),
],
if (profile.companyCode.isNotEmpty) ...[
const Divider(height: 24),
_buildReadOnlyTile(
tr(
'ui.userfront.profile.field.company_code',
),
tr('ui.userfront.profile.field.company_code'),
profile.companyCode,
),
],
@@ -1108,9 +1026,7 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
const SizedBox(height: 28),
_buildSectionTitle(
tr('ui.userfront.profile.section.security'),
tr(
'msg.userfront.profile.section.security',
),
tr('msg.userfront.profile.section.security'),
),
const SizedBox(height: 12),
_buildPasswordSection(),
@@ -1137,20 +1053,14 @@ class _ProfilePageState extends ConsumerState<ProfilePage> {
final profile = profileState.value ?? _cachedProfile;
if (profile == null) {
return Scaffold(
appBar: AppBar(
title: Text(tr('ui.userfront.nav.profile')),
),
appBar: AppBar(title: Text(tr('ui.userfront.nav.profile'))),
body: profileState.isLoading
? const Center(child: CircularProgressIndicator())
: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
tr(
'msg.userfront.profile.load_failed',
),
),
Text(tr('msg.userfront.profile.load_failed')),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () =>

File diff suppressed because one or more lines are too long

View File

@@ -131,9 +131,11 @@ final _router = GoRouter(
GoRoute(
path: 'signin',
builder: (context, state) {
final loginChallenge = state.uri.queryParameters['login_challenge'];
final redirectUrl = state.uri.queryParameters['redirect_uri'] ??
state.uri.queryParameters['redirect_url'];
final loginChallenge =
state.uri.queryParameters['login_challenge'];
final redirectUrl =
state.uri.queryParameters['redirect_uri'] ??
state.uri.queryParameters['redirect_url'];
return LoginScreen(
key: state.pageKey,
loginChallenge: loginChallenge,
@@ -145,9 +147,11 @@ final _router = GoRouter(
path: 'login',
builder: (context, state) {
// IMPORTANT: Match signin logic to handle OIDC challenges
final loginChallenge = state.uri.queryParameters['login_challenge'];
final redirectUrl = state.uri.queryParameters['redirect_uri'] ??
state.uri.queryParameters['redirect_url'];
final loginChallenge =
state.uri.queryParameters['login_challenge'];
final redirectUrl =
state.uri.queryParameters['redirect_uri'] ??
state.uri.queryParameters['redirect_url'];
return LoginScreen(
key: state.pageKey,
loginChallenge: loginChallenge,
@@ -158,10 +162,13 @@ final _router = GoRouter(
GoRoute(
path: 'consent',
builder: (BuildContext context, GoRouterState state) {
final consentChallenge = state.uri.queryParameters['consent_challenge'];
final consentChallenge =
state.uri.queryParameters['consent_challenge'];
if (consentChallenge == null) {
return const Scaffold(
body: Center(child: Text('Error: Consent challenge is missing.')),
body: Center(
child: Text('Error: Consent challenge is missing.'),
),
);
}
return ConsentScreen(consentChallenge: consentChallenge);
@@ -231,15 +238,13 @@ final _router = GoRouter(
),
GoRoute(
path: 'approve',
builder: (context, state) => ApproveQrScreen(
pendingRef: state.uri.queryParameters['ref'],
),
builder: (context, state) =>
ApproveQrScreen(pendingRef: state.uri.queryParameters['ref']),
),
GoRoute(
path: 'ql/:ref',
builder: (context, state) => ApproveQrScreen(
pendingRef: state.pathParameters['ref'],
),
builder: (context, state) =>
ApproveQrScreen(pendingRef: state.pathParameters['ref']),
),
GoRoute(
path: 'scan',
@@ -258,14 +263,15 @@ final _router = GoRouter(
final uri = state.uri;
final requestedLocale = extractLocaleFromPath(uri);
final preferredLocale = resolvePreferredLocaleCode();
if (requestedLocale == null) {
final localizedPath = buildLocalizedPath(preferredLocale, uri);
return localizedPath;
}
final token = AuthTokenStore.getToken();
final isLoggedIn = (token != null && token.isNotEmpty) || AuthTokenStore.usesCookie();
final isLoggedIn =
(token != null && token.isNotEmpty) || AuthTokenStore.usesCookie();
final path = stripLocalePath(uri);
// Precise public path detection