Compare commits

...

3 Commits

Author SHA1 Message Date
dacf5461f3 add registration password page 2024-02-06 14:40:10 +07:00
5d4bc47adf styling components 2024-02-06 14:39:16 +07:00
80e4657240 add string utils 2024-02-06 14:38:55 +07:00
10 changed files with 323 additions and 117 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

View File

@ -23,4 +23,5 @@ class PathAssets {
static const String imgKtpCropped = 'assets/images/img-ktp-cropped.png';
static const String imgKtpClear = 'assets/images/img-ktp-clear.png';
static const String imgKtpBlur = 'assets/images/img-ktp-blur.png';
static const String imgSuccessSignup = 'assets/images/img-success-signup.png';
}

View File

@ -55,8 +55,9 @@ class ButtonView extends StatelessWidget {
final widthPrefix =
this.widthPrefix ?? (heightWrapContent ? width! / 4.7 : _widthBtn / 16);
return Container(
margin: EdgeInsets.symmetric(vertical: marginVertical ?? 32.0),
return Center(
child: Container(
margin: EdgeInsets.symmetric(vertical: marginVertical ?? 24.0),
width: width ?? _widthBtn,
height: heightWrapContent ? null : height ?? _heightBtn,
child: ElevatedButton(
@ -129,6 +130,7 @@ class ButtonView extends StatelessWidget {
],
),
),
),
);
}
}

View File

@ -3,10 +3,14 @@ import 'package:flutter/material.dart';
class TextCaption extends StatelessWidget {
final String title, subtitle;
final TextAlign? textAlignSubtitle;
final CrossAxisAlignment? crossAxisAlignment;
const TextCaption({
Key? key,
required this.title,
this.subtitle = '',
this.textAlignSubtitle,
this.crossAxisAlignment,
}) : super(key: key);
@override
@ -14,7 +18,7 @@ class TextCaption extends StatelessWidget {
return Padding(
padding: const EdgeInsets.only(bottom: 32.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
crossAxisAlignment: crossAxisAlignment ?? CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
@ -30,6 +34,7 @@ class TextCaption extends StatelessWidget {
padding: const EdgeInsets.only(top: 8.0),
child: Text(
subtitle,
textAlign: textAlignSubtitle ?? TextAlign.start,
style: const TextStyle(
fontSize: 16,
fontWeight: FontWeight.w500,

View File

@ -94,12 +94,12 @@ class TextFormView extends StatelessWidget {
name,
style: const TextStyle(
fontSize: 16,
color: ColorPalette.greyLight,
// color: ColorPalette.greyLight,
),
),
suffixLable ??
const Text(
" * ",
"",
style: TextStyle(
fontSize: 16,
color: Colors.red,

View File

@ -0,0 +1,16 @@
class StringUtils {
static bool emailValidation(String email) {
return RegExp(
r'^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$')
.hasMatch(email);
}
static bool phoneValidation(String phone) {
return RegExp(r'^(\+62|62|0)8[1-9][0-9]{6,10}$').hasMatch(phone);
}
static bool passwordValidation(String password) {
return RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*?[\W_])(?=.{8,})')
.hasMatch(password);
}
}

View File

@ -0,0 +1,151 @@
import 'package:cims_apps/application/assets/path_assets.dart';
import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/component/image/image_view.dart';
import 'package:cims_apps/application/component/text_caption/text_caption.dart';
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
import 'package:cims_apps/application/theme/color_palette.dart';
import 'package:cims_apps/core/route/route.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/auth/registration/view/submission_data/submission_parent.dart';
import 'package:cims_apps/features/auth/registration/viewmodel/registration_viewmodel.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class RegistrationPasswordView extends StatelessWidget {
const RegistrationPasswordView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => RegistrationViewModel(),
builder: (context, child) {
return Scaffold(
appBar: AppBar(
title: const Text('Sign Up'),
),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Consumer<RegistrationViewModel>(
builder: (context, provider, child) {
return Form(
key: provider.formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const TextCaption(
title: 'Create your password',
subtitle:
'The password you create serves as your login',
),
TextFormView(
name: 'Password',
hintText: 'Input password',
ctrl: provider.passwordCtrl,
obscureText: !provider.showPassword,
validator: (value) {
if (value!.isEmpty) {
return 'Password must filled';
} else {
return null;
}
},
suffixIcon: GestureDetector(
onTap: () {
provider.toggleVisibility();
},
child: Icon(
provider.showPassword
? Icons.visibility_off_outlined
: Icons.visibility_off_outlined,
color: ColorPalette.greyDarker,
),
),
),
const SizedBox(
height: 32.0,
),
TextFormView(
name: 'Confirm Password',
hintText: 'Input password',
ctrl: provider.confirmPasswordCtrl,
obscureText: !provider.showPasswordConfirm,
validator: (value) {
if (value!.isEmpty) {
return 'Password must filled';
} else if (value != provider.passwordCtrl.text) {
return 'Password must be same';
} else {
return null;
}
},
suffixIcon: GestureDetector(
onTap: () {
provider.toggleVisibilityConfirm();
},
child: Icon(
provider.showPasswordConfirm
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
color: ColorPalette.greyDarker,
),
),
),
ButtonView(
name: 'Confirm',
onPressed: () {
if (provider.formKey.currentState!.validate()) {
routePush(context, page: const DialogSuccess());
}
},
)
],
),
);
}),
),
);
});
}
}
class DialogSuccess extends StatelessWidget {
const DialogSuccess({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
padding: const EdgeInsets.all(24.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ImageView(
image: PathAssets.imgSuccessSignup,
width: SizeConfig.width * .8,
),
const TextCaption(
title: 'Success',
subtitle:
'Congratulations, your account creation was successful!',
crossAxisAlignment: CrossAxisAlignment.center,
textAlignSubtitle: TextAlign.center,
),
SizedBox(
height: SizeConfig.height * .2,
),
ButtonView(
name: 'Next',
marginVertical: 8.0,
onPressed: () {
routePush(context,
page: const SubmissionParent(),
routeType: RouteType.pushReplace);
},
)
],
),
),
);
}
}

View File

@ -2,7 +2,7 @@ import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/component/text_caption/text_caption.dart';
import 'package:cims_apps/application/component/text_form/text_form_view.dart';
import 'package:cims_apps/core/route/route.dart';
import 'package:cims_apps/features/auth/registration/view/initial_registration_step.dart';
import 'package:cims_apps/features/auth/registration/view/registration_password_view.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
@ -29,7 +29,7 @@ class RegistrationView extends StatelessWidget {
ButtonView(
name: 'Next',
onPressed: () {
routePush(context, page: const InitialRegistrationStep());
routePush(context, page: const RegistrationPasswordView());
},
),
Align(

View File

@ -1,10 +1,12 @@
import 'package:cims_apps/application/component/button/button_view.dart';
import 'package:cims_apps/application/theme/color_palette.dart';
import 'package:cims_apps/core/route/route.dart';
import 'package:cims_apps/core/utils/size_config.dart';
import 'package:cims_apps/features/auth/registration/view/submission_data/initial_take_photo.dart';
import 'package:cims_apps/features/auth/registration/view/submission_data/submit_email.dart';
import 'package:cims_apps/features/auth/registration/view/submission_data/submit_personal_data.dart';
import 'package:cims_apps/features/auth/registration/viewmodel/submission_data_viewmodel.dart';
import 'package:cims_apps/features/bottom_navigation_view.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -71,7 +73,14 @@ class _SubmissionParentState extends State<SubmissionParent> {
return ChangeNotifierProvider(
create: (context) => SubmissionDataViewModel(),
builder: (context, child) {
return Scaffold(
return WillPopScope(
onWillPop: () async {
await routePush(context,
page: const BottomNavigationView(),
routeType: RouteType.pushReplace);
return false;
},
child: Scaffold(
appBar: AppBar(
title: const Text('Registration'),
),
@ -91,14 +100,16 @@ class _SubmissionParentState extends State<SubmissionParent> {
children: List.generate(
provider.stepAmount,
(index) => _stepItem(
isCurrentStep: provider.currentStep == index + 1,
isCurrentStep:
provider.currentStep == index + 1,
),
),
),
),
Expanded(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
padding:
const EdgeInsets.symmetric(horizontal: 16.0),
child: _content(provider.currentStep),
),
),
@ -119,6 +130,7 @@ class _SubmissionParentState extends State<SubmissionParent> {
}),
],
),
),
);
});
}

View File

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class RegistrationViewModel extends ChangeNotifier {
TextEditingController passwordCtrl = TextEditingController();
TextEditingController confirmPasswordCtrl = TextEditingController();
var formKey = GlobalKey<FormState>();
bool showPassword = false;
bool showPasswordConfirm = false;
void toggleVisibility() {
showPassword = !showPassword;
notifyListeners();
}
void toggleVisibilityConfirm() {
showPasswordConfirm = !showPasswordConfirm;
notifyListeners();
}
}