Download PDF #2

This commit is contained in:
2025-09-08 17:57:11 +05:30
parent b513664a47
commit 0a6dde9ead
5 changed files with 234 additions and 10 deletions

View File

@@ -63,8 +63,9 @@ Dio _createDioClient() {
final dio = Dio( final dio = Dio(
BaseOptions( BaseOptions(
baseUrl: baseUrl:
'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080', // 'http://lb-test-mobile-banking-app-192209417.ap-south-1.elb.amazonaws.com:8080',
//'http://localhost:8081', //'http://localhost:8081',
'http://localhost:8082',
connectTimeout: const Duration(seconds: 5), connectTimeout: const Duration(seconds: 5),
receiveTimeout: const Duration(seconds: 10), receiveTimeout: const Duration(seconds: 10),
headers: { headers: {

View File

@@ -209,26 +209,21 @@ class _PaymentAnimationScreenState extends State<PaymentAnimationScreen> {
onPressed: _shareScreenshot, onPressed: _shareScreenshot,
icon: Icon( icon: Icon(
Icons.share_rounded, Icons.share_rounded,
color: Theme.of(context).primaryColor, color: Theme.of(context).colorScheme.primary,
), ),
label: Text( label: Text(
AppLocalizations.of(context).share, AppLocalizations.of(context).share,
style: TextStyle(color: Theme.of(context).primaryColor), style: TextStyle(color: Theme.of(context).colorScheme.primary),
), ),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor:
Theme.of(context).scaffoldBackgroundColor,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 32, vertical: 12), horizontal: 45, vertical: 12),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
side: BorderSide(
color: Theme.of(context).primaryColor, width: 1),
borderRadius: BorderRadius.circular(30), borderRadius: BorderRadius.circular(30),
), ),
textStyle: const TextStyle( textStyle: const TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.black,
), ),
), ),
), ),

View File

@@ -0,0 +1,84 @@
import 'package:flutter/material.dart';
class ChangePasswordOTPScreen extends StatefulWidget {
final String currentPassword;
final String newPassword;
final String confirmPassword;
// ignore: use_key_in_widget_constructors
const ChangePasswordOTPScreen({
required this.currentPassword,
required this.newPassword,
required this.confirmPassword,
});
@override
State<ChangePasswordOTPScreen> createState() => _ChangePasswordOTPScreenState();
}
class _ChangePasswordOTPScreenState extends State<ChangePasswordOTPScreen> {
bool _isLoading = true;
final TextEditingController otpController = TextEditingController();
@override
void initState() {
super.initState();
// Simulate OTP sending delay
Future.delayed(const Duration(seconds: 2), () {
setState(() {
_isLoading = false;
});
});
}
void _validateOTP() {
// TODO: Add validation logic later
print("Validating OTP...");
print('Current Password: ${widget.currentPassword}');
print('New Password: ${widget.newPassword}');
print('Confirm Password: ${widget.confirmPassword}');
print('Entered OTP: ${otpController.text}');
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('OTP Verification')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: _isLoading
? const Center(child: CircularProgressIndicator())
: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
'An OTP has been sent to your registered mobile number.',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16),
),
const SizedBox(height: 24),
TextFormField(
controller: otpController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Enter OTP',
border: OutlineInputBorder(),
),
),
const SizedBox(height: 24),
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: _validateOTP,
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Text('Validate OTP'),
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,140 @@
// ignore_for_file: use_key_in_widget_constructors
import 'package:flutter/material.dart';
import '../../../l10n/app_localizations.dart';
import 'change_password_otp_screen.dart';
class ChangePasswordScreen extends StatefulWidget {
const ChangePasswordScreen();
@override
State<ChangePasswordScreen> createState() => _ChangePasswordScreenState();
}
class _ChangePasswordScreenState extends State<ChangePasswordScreen> {
final _formKey = GlobalKey<FormState>();
final currentPasswordController = TextEditingController();
final newPasswordController = TextEditingController();
final confirmPasswordController = TextEditingController();
bool _showCurrentPassword = false;
bool _showNewPassword = false;
bool _showConfirmPassword = false;
final passwordRegex =
RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\W_]).{8,}$');
String? validateCurrentPassword(String? value) {
if (value == null || value.isEmpty) {
return 'Current password is required';
}
return null;
}
String? validateNewPassword(String? value) {
if (value == null || value.isEmpty) {
return 'New password is required';
}
if (!passwordRegex.hasMatch(value)) {
return 'At least 8 chars, upper & lower case, digit, special char';
}
if (value == currentPasswordController.text) {
return 'New password must differ from current';
}
return null;
}
String? validateConfirmPassword(String? value) {
if (value == null || value.isEmpty) {
return 'Confirm new password is required';
}
if (value != newPasswordController.text) {
return 'Passwords do not match';
}
return null;
}
void _proceed() {
if (_formKey.currentState!.validate()) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ChangePasswordOTPScreen(
currentPassword: currentPasswordController.text,
newPassword: newPasswordController.text,
confirmPassword: confirmPasswordController.text,
),
),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(AppLocalizations.of(context).changePassword)),
body: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: currentPasswordController,
obscureText: !_showCurrentPassword,
decoration: InputDecoration(
labelText: 'Current Password',
suffixIcon: IconButton(
icon: Icon(_showCurrentPassword
? Icons.visibility
: Icons.visibility_off),
onPressed: () =>
setState(() => _showCurrentPassword = !_showCurrentPassword),
),
),
validator: validateCurrentPassword,
),
const SizedBox(height: 16),
TextFormField(
controller: newPasswordController,
obscureText: !_showNewPassword,
decoration: InputDecoration(
labelText: 'New Password',
suffixIcon: IconButton(
icon: Icon(_showNewPassword
? Icons.visibility
: Icons.visibility_off),
onPressed: () =>
setState(() => _showNewPassword = !_showNewPassword),
),
),
validator: validateNewPassword,
),
const SizedBox(height: 16),
TextFormField(
controller: confirmPasswordController,
obscureText: !_showConfirmPassword,
decoration: InputDecoration(
labelText: 'Confirm New Password',
suffixIcon: IconButton(
icon: Icon(_showConfirmPassword
? Icons.visibility
: Icons.visibility_off),
onPressed: () =>
setState(() => _showConfirmPassword = !_showConfirmPassword),
),
),
validator: validateConfirmPassword,
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: _proceed,
child: Text(AppLocalizations.of(context).proceed),
),
],
),
),
),
);
}
}

View File

@@ -1,5 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:kmobile/data/repositories/auth_repository.dart'; import 'package:kmobile/data/repositories/auth_repository.dart';
import 'package:kmobile/features/profile/change_password/change_password_screen.dart';
import 'package:kmobile/features/profile/logout_dialog.dart'; import 'package:kmobile/features/profile/logout_dialog.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import '../../di/injection.dart'; import '../../di/injection.dart';
@@ -44,7 +45,10 @@ class ProfileScreen extends StatelessWidget {
leading: const Icon(Icons.password), leading: const Icon(Icons.password),
title: Text(loc.changePassword), title: Text(loc.changePassword),
onTap: () { onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const ChangePasswordScreen()),
);
}, },
), ),
ListTile( ListTile(