Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion lib/app/router/app_router.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,10 @@ class AppRouterFactory {
...UsersFeatureRoutes.routes,
...SettingsFeatureRoutes.routes,
...DynamicFormsFeatureRoutes.routes,
...AuthFeatureRoutes.authenticatedRoutes,
],
),
...AuthFeatureRoutes.routes,
...AuthFeatureRoutes.publicRoutes,
],
redirect: (context, state) {
final location = state.uri.path;
Expand Down
7 changes: 3 additions & 4 deletions lib/features/auth/application/change_password_event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ abstract class ChangePasswordEvent extends Equatable {
bool get stringify => true;
}

class TogglePasswordVisibility extends ChangePasswordEvent {
const TogglePasswordVisibility();
}

class ChangePasswordChanged extends ChangePasswordEvent {
final String currentPassword;
final String newPassword;

const ChangePasswordChanged({required this.currentPassword, required this.newPassword});

@override
List<Object> get props => [currentPassword, newPassword];
}
23 changes: 0 additions & 23 deletions lib/features/auth/application/change_password_state.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ part of 'change_password_bloc.dart';

enum ChangePasswordStatus { initial, loading, success, failure }

const String authenticationFailKey = 'error.authenticate';

class ChangePasswordState extends Equatable {
final ChangePasswordStatus status;

Expand All @@ -19,24 +17,3 @@ class ChangePasswordState extends Equatable {
@override
bool get stringify => true;
}

class ChangePasswordInitialState extends ChangePasswordState {
const ChangePasswordInitialState() : super(status: ChangePasswordStatus.initial);
}

class ChangePasswordLoadingState extends ChangePasswordState {
const ChangePasswordLoadingState() : super(status: ChangePasswordStatus.loading);
}

class ChangePasswordCompletedState extends ChangePasswordState {
const ChangePasswordCompletedState() : super(status: ChangePasswordStatus.success);
}

class ChangePasswordErrorState extends ChangePasswordState {
final String message;

const ChangePasswordErrorState({required this.message}) : super(status: ChangePasswordStatus.failure);

@override
List<Object> get props => [status, message];
}
28 changes: 19 additions & 9 deletions lib/features/auth/navigation/auth_routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import 'package:flutter_bloc_advance/features/auth/presentation/pages/forgot_pas
import 'package:flutter_bloc_advance/features/auth/presentation/pages/login_page.dart';
import 'package:flutter_bloc_advance/features/auth/presentation/pages/register_page.dart';
import 'package:flutter_bloc_advance/app/router/app_routes_constants.dart';
import 'package:flutter_bloc_advance/shared/design_system/components/app_page_transition.dart';
import 'package:go_router/go_router.dart';

class AuthFeatureRoutes {
static final List<GoRoute> routes = [
/// Public routes (login, register, forgot-password) — outside ShellRoute
static final List<GoRoute> publicRoutes = [
GoRoute(name: 'login', path: ApplicationRoutesConstants.login, builder: (context, state) => const LoginScreen()),
GoRoute(
name: 'login-otp',
Expand All @@ -31,14 +33,6 @@ class AuthFeatureRoutes {
child: ForgotPasswordScreen(),
),
),
GoRoute(
name: 'change-password',
path: ApplicationRoutesConstants.changePassword,
builder: (context, state) => BlocProvider(
create: (_) => ChangePasswordBloc(repository: context.read<IAccountRepository>()),
child: ChangePasswordScreen(),
),
),
GoRoute(
name: 'register',
path: ApplicationRoutesConstants.register,
Expand All @@ -48,4 +42,20 @@ class AuthFeatureRoutes {
),
),
];

/// Authenticated routes (change-password) — inside ShellRoute
static final List<GoRoute> authenticatedRoutes = [
GoRoute(
name: 'change-password',
path: ApplicationRoutesConstants.changePassword,
pageBuilder: (context, state) => appTransitionPage(
state: state,
type: AppPageTransitionType.slideRight,
child: BlocProvider(
create: (_) => ChangePasswordBloc(repository: context.read<IAccountRepository>()),
child: ChangePasswordScreen(),
),
),
),
];
}
103 changes: 53 additions & 50 deletions lib/features/auth/presentation/pages/change_password_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class ChangePasswordScreen extends StatefulWidget {

class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
final _formKey = GlobalKey<FormBuilderState>();
final _scaffoldKey = GlobalKey<ScaffoldState>();

bool _showCurrentPassword = false;
bool _showNewPassword = false;
Expand All @@ -34,19 +33,8 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
listener: (context, state) => _handleStateChanges(context, state),
child: PopScope(
canPop: !(_formKey.currentState?.isDirty ?? false),
onPopInvokedWithResult: (bool didPop, Object? data) async => _handlePopScope(didPop, data),
child: Scaffold(key: _scaffoldKey, appBar: _buildAppBar(context), body: _buildBody(context)),
),
);
}

AppBar _buildAppBar(BuildContext context) {
return AppBar(
title: Text(S.of(context).change_password),
leading: IconButton(
key: const Key('changePasswordScreenAppBarBackButtonKey'),
icon: const Icon(Icons.arrow_back),
onPressed: () async => _handlePopScope(false, null, context),
onPopInvokedWithResult: (bool didPop, Object? data) async => _handlePopScope(context, didPop),
child: _buildBody(context),
),
);
}
Expand All @@ -55,42 +43,59 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
return BlocBuilder<ChangePasswordBloc, ChangePasswordState>(
buildWhen: (previous, current) => previous.status != current.status,
builder: (context, state) {
return ResponsiveFormBuilder(
formKey: _formKey,
children: [
const SizedBox(height: AppSpacing.lg),
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppSpacing.md),
side: BorderSide(color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.5)),
),
child: Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
spacing: AppSpacing.lg,
children: [
Text(
S.of(context).change_password,
style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold),
return SingleChildScrollView(
padding: const EdgeInsets.all(AppSpacing.xl),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 640),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
IconButton(
key: const Key('changePasswordScreenAppBarBackButtonKey'),
icon: const Icon(Icons.arrow_back),
onPressed: () async => _handlePopScope(context, false),
),
const SizedBox(width: AppSpacing.sm),
Text(
S.of(context).change_password,
style: Theme.of(context).textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.w700),
),
],
),
const SizedBox(height: AppSpacing.xl),
Card(
elevation: 2,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(AppSpacing.md),
side: BorderSide(color: Theme.of(context).colorScheme.outlineVariant.withValues(alpha: 0.5)),
),
Text(
'Ensure your account is using a long, random password to stay secure.',
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant),
child: Padding(
padding: const EdgeInsets.all(AppSpacing.xl),
child: ResponsiveFormBuilder(
formKey: _formKey,
children: [
Text(
S.of(context).change_password_description,
style: Theme.of(
context,
).textTheme.bodyMedium?.copyWith(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
const Divider(),
_currentPasswordField(context),
_newPasswordField(context),
const SizedBox(height: AppSpacing.sm),
_submitButton(context, state),
],
),
),
const Divider(),
_currentPasswordField(context),
_newPasswordField(context),
const SizedBox(height: AppSpacing.sm),
_submitButton(context, state),
],
),
),
],
),
),
],
),
);
},
);
Expand Down Expand Up @@ -142,7 +147,7 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
child: ResponsiveSubmitButton(
key: changePasswordButtonSubmitKey,
buttonText: S.of(context).save,
onPressed: () => state.status == ChangePasswordStatus.loading ? null : _onSubmit(context, state),
onPressed: state.status == ChangePasswordStatus.loading ? null : () => _onSubmit(context, state),
isLoading: state.status == ChangePasswordStatus.loading,
),
);
Expand Down Expand Up @@ -192,10 +197,8 @@ class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message), duration: duration));
}

Future<void> _handlePopScope(bool didPop, Object? data, [BuildContext? contextParam]) async {
Future<void> _handlePopScope(BuildContext context, bool didPop) async {
if (didPop) return;

final context = contextParam ?? data as BuildContext;
if (!context.mounted) return;

if (!(_formKey.currentState?.isDirty ?? false) || _formKey.currentState == null) {
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/intl/messages_en.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class MessageLookup extends MessageLookupByLibrary {
"authorities": MessageLookupByLibrary.simpleMessage("Authorities"),
"back": MessageLookupByLibrary.simpleMessage("Back"),
"change_password": MessageLookupByLibrary.simpleMessage("Change Password"),
"change_password_description": MessageLookupByLibrary.simpleMessage(
"Ensure your account is using a long, random password to stay secure.",
),
"chart_kpi_placeholder": MessageLookupByLibrary.simpleMessage("Chart / KPI Placeholder"),
"community_contribute": MessageLookupByLibrary.simpleMessage("Contribute"),
"community_discussions": MessageLookupByLibrary.simpleMessage("Discussions"),
Expand Down
3 changes: 3 additions & 0 deletions lib/generated/intl/messages_tr.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class MessageLookup extends MessageLookupByLibrary {
"authorities": MessageLookupByLibrary.simpleMessage("Roller"),
"back": MessageLookupByLibrary.simpleMessage("Geri"),
"change_password": MessageLookupByLibrary.simpleMessage("Şifre Değiştir"),
"change_password_description": MessageLookupByLibrary.simpleMessage(
"Hesabınızın güvende kalması için uzun ve rastgele bir şifre kullandığınızdan emin olun.",
),
"chart_kpi_placeholder": MessageLookupByLibrary.simpleMessage("Grafik / KPI Alanı"),
"community_contribute": MessageLookupByLibrary.simpleMessage("Katkıda Bulun"),
"community_discussions": MessageLookupByLibrary.simpleMessage("Tartışmalar"),
Expand Down
10 changes: 10 additions & 0 deletions lib/generated/l10n.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/l10n/intl_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"settings": "Settings",
"account": "Account",
"change_password": "Change Password",
"change_password_description": "Ensure your account is using a long, random password to stay secure.",
"language_select": "Select Language",
"logout": "Logout",
"logout_sure": "Are you sure you want to logout?",
Expand Down
1 change: 1 addition & 0 deletions lib/l10n/intl_tr.arb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"settings": "Ayarlar",
"account": "Hesabım",
"change_password": "Şifre Değiştir",
"change_password_description": "Hesabınızın güvende kalması için uzun ve rastgele bir şifre kullandığınızdan emin olun.",
"language_select": "Dil Seçimi",
"logout": "Çıkış Yap",
"logout_sure": "Çıkış yapmak istediğinize emin misiniz?",
Expand Down
Loading