added kode otp page, input informasi diri page, and user index tracking page, repair the back button on UserIndexTrackingView

This commit is contained in:
kicap
2023-07-17 04:39:00 +08:00
parent 4c5ec4364d
commit b20b414a21
22 changed files with 1051 additions and 33 deletions

View File

@ -1,3 +1,8 @@
import 'package:reza_app/ui/views/user_ui/akun_user/akun_user_view.dart';
import 'package:reza_app/ui/views/user_ui/makanan_list/makanan_list_view.dart';
import 'package:reza_app/ui/views/user_ui/pesanan_list/pesanan_list_view.dart';
import 'package:reza_app/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart';
import 'package:reza_app/ui/views/user_ui/user_index_tracking/user_index_tracking_view.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stacked/stacked_annotations.dart';
@ -16,6 +21,16 @@ import '../ui/views/splash_screen/splash_screen_view.dart';
MaterialRoute(page: MasukanNoHpView),
MaterialRoute(page: VerifikasiNoHpView),
MaterialRoute(page: InputInformasiDiriView),
MaterialRoute(
page: UserIndexTrackingView,
fullscreenDialog: true,
children: [
MaterialRoute(page: ReservasiMejaView, initial: true),
MaterialRoute(page: MakananListView),
MaterialRoute(page: PesananListView),
MaterialRoute(page: AkunUserView),
],
),
],
// dialogs: [
// StackedDialog(classType: AddSiswaDialogView),

View File

@ -5,7 +5,7 @@
// **************************************************************************
// ignore_for_file: no_leading_underscores_for_library_prefixes
import 'package:flutter/material.dart' as _i7;
import 'package:flutter/material.dart' as _i8;
import 'package:flutter/material.dart';
import 'package:reza_app/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart'
as _i6;
@ -15,8 +15,18 @@ import 'package:reza_app/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_
as _i5;
import 'package:reza_app/ui/views/login_user/login_user_view.dart' as _i3;
import 'package:reza_app/ui/views/splash_screen/splash_screen_view.dart' as _i2;
import 'package:reza_app/ui/views/user_ui/akun_user/akun_user_view.dart'
as _i12;
import 'package:reza_app/ui/views/user_ui/makanan_list/makanan_list_view.dart'
as _i10;
import 'package:reza_app/ui/views/user_ui/pesanan_list/pesanan_list_view.dart'
as _i11;
import 'package:reza_app/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart'
as _i9;
import 'package:reza_app/ui/views/user_ui/user_index_tracking/user_index_tracking_view.dart'
as _i7;
import 'package:stacked/stacked.dart' as _i1;
import 'package:stacked_services/stacked_services.dart' as _i8;
import 'package:stacked_services/stacked_services.dart' as _i13;
class Routes {
static const splashScreenView = '/';
@ -29,12 +39,15 @@ class Routes {
static const inputInformasiDiriView = '/input-informasi-diri-view';
static const userIndexTrackingView = '/user-index-tracking-view';
static const all = <String>{
splashScreenView,
loginUserView,
masukanNoHpView,
verifikasiNoHpView,
inputInformasiDiriView,
userIndexTrackingView,
};
}
@ -60,36 +73,146 @@ class StackedRouter extends _i1.RouterBase {
Routes.inputInformasiDiriView,
page: _i6.InputInformasiDiriView,
),
_i1.RouteDef(
Routes.userIndexTrackingView,
page: _i7.UserIndexTrackingView,
),
];
final _pagesMap = <Type, _i1.StackedRouteFactory>{
_i2.SplashScreenView: (data) {
return _i7.MaterialPageRoute<dynamic>(
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i2.SplashScreenView(),
settings: data,
);
},
_i3.LoginUserView: (data) {
return _i7.MaterialPageRoute<dynamic>(
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i3.LoginUserView(),
settings: data,
);
},
_i4.MasukanNoHpView: (data) {
return _i7.MaterialPageRoute<dynamic>(
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i4.MasukanNoHpView(),
settings: data,
);
},
_i5.VerifikasiNoHpView: (data) {
return _i7.MaterialPageRoute<dynamic>(
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i5.VerifikasiNoHpView(),
settings: data,
);
},
_i6.InputInformasiDiriView: (data) {
return _i7.MaterialPageRoute<dynamic>(
builder: (context) => const _i6.InputInformasiDiriView(),
final args = data.getArgs<InputInformasiDiriViewArguments>(nullOk: false);
return _i8.MaterialPageRoute<dynamic>(
builder: (context) =>
_i6.InputInformasiDiriView(key: args.key, noHp: args.noHp),
settings: data,
);
},
_i7.UserIndexTrackingView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i7.UserIndexTrackingView(),
settings: data,
fullscreenDialog: true,
);
},
};
@override
List<_i1.RouteDef> get routes => _routes;
@override
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
class InputInformasiDiriViewArguments {
const InputInformasiDiriViewArguments({
this.key,
required this.noHp,
});
final _i8.Key? key;
final String noHp;
@override
String toString() {
return '{"key": "$key", "noHp": "$noHp"}';
}
@override
bool operator ==(covariant InputInformasiDiriViewArguments other) {
if (identical(this, other)) return true;
return other.key == key && other.noHp == noHp;
}
@override
int get hashCode {
return key.hashCode ^ noHp.hashCode;
}
}
class UserIndexTrackingViewRoutes {
static const reservasiMejaView = '';
static const makananListView = 'makanan-list-view';
static const pesananListView = 'pesanan-list-view';
static const akunUserView = 'akun-user-view';
static const all = <String>{
reservasiMejaView,
makananListView,
pesananListView,
akunUserView,
};
}
class UserIndexTrackingViewRouter extends _i1.RouterBase {
final _routes = <_i1.RouteDef>[
_i1.RouteDef(
UserIndexTrackingViewRoutes.reservasiMejaView,
page: _i9.ReservasiMejaView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.makananListView,
page: _i10.MakananListView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.pesananListView,
page: _i11.PesananListView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.akunUserView,
page: _i12.AkunUserView,
),
];
final _pagesMap = <Type, _i1.StackedRouteFactory>{
_i9.ReservasiMejaView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i9.ReservasiMejaView(),
settings: data,
);
},
_i10.MakananListView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i10.MakananListView(),
settings: data,
);
},
_i11.PesananListView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i11.PesananListView(),
settings: data,
);
},
_i12.AkunUserView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.AkunUserView(),
settings: data,
);
},
@ -101,7 +224,7 @@ class StackedRouter extends _i1.RouterBase {
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
extension NavigatorStateExtension on _i8.NavigationService {
extension NavigatorStateExtension on _i13.NavigationService {
Future<dynamic> navigateToSplashScreenView([
int? routerId,
bool preventDuplicates = true,
@ -158,14 +281,88 @@ extension NavigatorStateExtension on _i8.NavigationService {
transition: transition);
}
Future<dynamic> navigateToInputInformasiDiriView([
Future<dynamic> navigateToInputInformasiDiriView({
_i8.Key? key,
required String noHp,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return navigateTo<dynamic>(Routes.inputInformasiDiriView,
arguments: InputInformasiDiriViewArguments(key: key, noHp: noHp),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToUserIndexTrackingView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.inputInformasiDiriView,
return navigateTo<dynamic>(Routes.userIndexTrackingView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
navigateToNestedReservasiMejaViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(UserIndexTrackingViewRoutes.reservasiMejaView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedMakananListViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(UserIndexTrackingViewRoutes.makananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedPesananListViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(UserIndexTrackingViewRoutes.pesananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> navigateToNestedAkunUserViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(UserIndexTrackingViewRoutes.akunUserView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
@ -228,14 +425,90 @@ extension NavigatorStateExtension on _i8.NavigationService {
transition: transition);
}
Future<dynamic> replaceWithInputInformasiDiriView([
Future<dynamic> replaceWithInputInformasiDiriView({
_i8.Key? key,
required String noHp,
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
}) async {
return replaceWith<dynamic>(Routes.inputInformasiDiriView,
arguments: InputInformasiDiriViewArguments(key: key, noHp: noHp),
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithUserIndexTrackingView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.inputInformasiDiriView,
return replaceWith<dynamic>(Routes.userIndexTrackingView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedReservasiMejaViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(UserIndexTrackingViewRoutes.reservasiMejaView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedMakananListViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(UserIndexTrackingViewRoutes.makananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedPesananListViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(UserIndexTrackingViewRoutes.pesananListView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic> replaceWithNestedAkunUserViewInUserIndexTrackingViewRouter([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(UserIndexTrackingViewRoutes.akunUserView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,

View File

@ -1,16 +1,53 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import '../../services/http_services.dart';
import '../../services/my_easyloading.dart';
import '../app.locator.dart';
import '../themes/app_colors.dart';
class CustomBaseViewModel extends BaseViewModel {
final dialogService = locator<DialogService>();
final navigationService = locator<NavigationService>();
final bottomSheetService = locator<BottomSheetService>();
final snackbarService = locator<SnackbarService>();
final easyLoading = locator<MyEasyLoading>();
final httpService = locator<MyHttpServices>();
bool backPressed = true;
void back() {
navigationService.back();
}
quitApp(BuildContext context) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Keluar'),
content: const Text('Apakah Anda yakin ingin keluar?'),
actions: [
TextButton(
onPressed: () => Navigator.of(context).pop(false),
child: const Text('Batal'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text(
'Keluar',
style: TextStyle(color: dangerColor),
),
),
],
);
},
).then((value) {
if (value == true) {
SystemNavigator.pop();
}
});
}
}

View File

@ -1,10 +1,19 @@
import 'package:flutter/material.dart';
import 'package:reza_app/app/app.router.dart';
import 'package:reza_app/ui/widgets/my_button.dart';
import 'package:reza_app/ui/widgets/my_textformfield.dart';
import 'package:stacked/stacked.dart';
import 'package:validatorless/validatorless.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../../app/themes/app_text.dart';
import './input_informasi_diri_view_model.dart';
class InputInformasiDiriView extends StatelessWidget {
const InputInformasiDiriView({super.key});
final String noHp;
const InputInformasiDiriView({Key? key, required this.noHp})
: super(key: key);
@override
Widget build(BuildContext context) {
@ -18,10 +27,155 @@ class InputInformasiDiriView extends StatelessWidget {
InputInformasiDiriViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'InputInformasiDiriView',
return Scaffold(
appBar: AppBar(
title: const Text('INPUT INFORMASI DIRI',
style: TextStyle(
color: lightColor,
)),
backgroundColor: mainColor,
iconTheme: const IconThemeData(
color:
Colors.white), // Set the color of the back button to white
),
body: WillPopScope(
onWillPop: () async {
if (model.backPressed) {
model.navigationService.navigateToMasukanNoHpView();
}
return false;
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: SingleChildScrollView(
child: Form(
key: model.formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(height: 25),
Center(
child: Image.asset(
'assets/logo.png',
width: 100,
height: 100,
alignment: Alignment.center,
),
),
const SizedBox(height: 15),
const Align(
alignment: Alignment.centerLeft,
child: Text(
' No . HP',
),
),
const SizedBox(height: 5),
MyTextFormField(
initialValue: noHp,
readOnly: true,
),
const SizedBox(height: 15),
const Align(
alignment: Alignment.centerLeft,
child: Text(
' Nama Lengkap',
),
),
const SizedBox(height: 5),
MyTextFormField(
hintText: 'Masukan Nama Lengkap',
controller: model.namaLengkapController,
validator: Validatorless.required(
'Nama Lengkap tidak boleh kosong',
),
),
const SizedBox(height: 15),
const Align(
alignment: Alignment.centerLeft,
child: Text(
' Tanggal Lahir',
),
),
const SizedBox(height: 5),
MyTextFormField(
hintText: 'Pilih Tanggal Lahir',
readOnly: true,
controller: model.tanggalLahirController,
validator: Validatorless.required(
'Tanggal Lahir tidak boleh kosong',
),
onTap: () => model.selectDate(context),
),
const SizedBox(height: 15),
const Align(
alignment: Alignment.centerLeft,
child: Text(
' Jenis Kelamin',
),
),
Container(
width: double.infinity,
height: 60,
padding: const EdgeInsets.symmetric(horizontal: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(25),
border: Border.all(
color: mainColor,
),
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: model.jenisKelamin,
onChanged: (String? newValue) {
// model.setSelectedJenisKelamin(newValue!);
model.log.i(newValue);
model.jenisKelamin = newValue!;
model.notifyListeners();
},
items: model.jenisKelaminList.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(
value,
style: regularTextStyle.copyWith(
fontSize: 16,
),
),
);
}).toList(),
),
),
),
const SizedBox(height: 15),
const Align(
alignment: Alignment.centerLeft,
child: Text(
' Alamat',
),
),
const SizedBox(height: 5),
MyTextFormField(
hintText: 'Masukan Alamat',
maxLines: 3,
controller: model.alamatController,
validator: Validatorless.required(
'Alamat tidak boleh kosong',
),
),
const SizedBox(height: 15),
MyButton(
text: 'Daftar',
onPressed: () {
if (model.formKey.currentState!.validate()) {
model.goToLogin();
}
},
),
const SizedBox(height: 25),
],
),
),
),
),
),
);

View File

@ -1,5 +1,46 @@
import 'package:reza_app/app/core/custom_base_view_model.dart';
import 'package:flutter/material.dart';
import '../../../../app/app.router.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/core/custom_base_view_model.dart';
class InputInformasiDiriViewModel extends CustomBaseViewModel {
final log = getLogger('InputInformasiDiriViewModel');
Future<void> init() async {}
List<String> jenisKelaminList = ['Laki-laki', 'Perempuan'];
String jenisKelamin = 'Laki-laki';
TextEditingController namaLengkapController = TextEditingController();
TextEditingController tanggalLahirController = TextEditingController();
TextEditingController alamatController = TextEditingController();
GlobalKey<FormState> formKey = GlobalKey<FormState>();
selectDate(BuildContext context) async {
// get today's date
var datePicked = await showDatePicker(
context: context,
initialDate: DateTime(2013),
firstDate: DateTime(1950),
// last date is today's date
lastDate: DateTime(2013),
);
if (datePicked != null) {
String date = datePicked.toString().split(' ')[0];
tanggalLahirController.text = date;
}
}
goToLogin() async {
backPressed = false;
easyLoading.customLoading("Mendaftarkan Akun Anda");
await Future.delayed(const Duration(seconds: 2));
easyLoading.customLoading("Ke Halaman Login");
await Future.delayed(const Duration(seconds: 2));
easyLoading.dismissLoading();
backPressed = true;
notifyListeners();
await navigationService.navigateToLoginUserView();
}
}

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import '../../../../app/app.router.dart';
import 'package:stacked/stacked.dart';
import 'package:validatorless/validatorless.dart';
@ -35,7 +36,10 @@ class MasukanNoHpView extends StatelessWidget {
),
body: WillPopScope(
onWillPop: () async {
return model.backPressed;
if (model.backPressed) {
model.navigationService.navigateToLoginUserView();
}
return false;
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
@ -78,6 +82,7 @@ class MasukanNoHpView extends StatelessWidget {
if (!model.formKey.currentState!.validate()) {
return;
}
FocusScope.of(context).unfocus();
model.log.i('Selanjutnya button pressed');
model.selanjutnya();
},

View File

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:otp_text_field/otp_text_field.dart';
import 'package:otp_text_field/style.dart';
import 'package:stacked/stacked.dart';
import '../../../../app/themes/app_colors.dart';
import './verifikasi_no_hp_view_model.dart';
class VerifikasiNoHpView extends StatelessWidget {
@ -18,10 +21,128 @@ class VerifikasiNoHpView extends StatelessWidget {
VerifikasiNoHpViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'VerifikasiNoHpView',
return Scaffold(
appBar: AppBar(
title: const Text(
'Verifikasi No. HP',
style: TextStyle(
color: lightColor,
),
),
backgroundColor: mainColor,
iconTheme: const IconThemeData(
color:
Colors.white), // Set the color of the back button to white
),
body: WillPopScope(
onWillPop: () async {
if (model.backPressed) {
model.back();
}
return false;
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/logo.png',
width: 75,
height: 75,
),
const SizedBox(height: 15),
const Text(
'Masukkan Kode OTP yang telah \ndikirimkan ke nomor HP anda',
textAlign: TextAlign.center,
),
const SizedBox(height: 5),
OTPTextField(
length: 6,
width: MediaQuery.of(context).size.width,
fieldWidth: 50,
style: const TextStyle(fontSize: 17),
textFieldAlignment: MainAxisAlignment.spaceAround,
fieldStyle: FieldStyle.box,
onCompleted: (pin) {
model.log.i('Completed: $pin');
model.noOTP = int.parse(pin);
model.notifyListeners();
},
onChanged: (value) {
model.log.i('onChanged: $value');
model.noOTP = int.parse(value);
model.notifyListeners();
},
),
const SizedBox(height: 5),
RichText(
textAlign: TextAlign.center,
text: TextSpan(
text: 'Kode OTP kadaluarsa dalam ',
style: const TextStyle(color: Colors.black),
children: [
const TextSpan(
text: '00:30\n',
style: TextStyle(color: mainColor),
),
WidgetSpan(
child: GestureDetector(
onTap: () {
// Handle tap
},
child: const Center(
child: Text(
'Kirim ulang kode OTP',
style: TextStyle(
color: mainColor,
fontSize: 14,
height: 1.5,
decoration: TextDecoration.underline,
),
),
),
),
),
],
),
),
const SizedBox(height: 5),
SizedBox(
width: MediaQuery.of(context).size.width * 0.5,
child: ElevatedButton(
onPressed: () {
if (model.noOTP == null) {
model.snackbarService.showSnackbar(
message: 'Kode OTP tidak boleh kosong');
return;
}
// check the length of noOTP
if (model.noOTP.toString().length < 6) {
model.snackbarService.showSnackbar(
message: 'Kode OTP tidak boleh kurang dari 6');
return;
}
// hide the keyboard
FocusScope.of(context).unfocus();
model.log.i('noOTP: ${model.noOTP}');
model.goToInputInformasiDiri();
},
style: ElevatedButton.styleFrom(
backgroundColor: mainColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: const Text('Verifikasi'),
),
),
],
),
),
),
),
);

View File

@ -1,5 +1,22 @@
import 'package:reza_app/app/core/custom_base_view_model.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/app.router.dart';
import '../../../../app/core/custom_base_view_model.dart';
class VerifikasiNoHpViewModel extends CustomBaseViewModel {
final log = getLogger('VerifikasiNoHpViewModel');
int? noOTP;
Future<void> init() async {}
goToInputInformasiDiri() async {
backPressed = false;
easyLoading.customLoading("Ke Halaman Input Informasi Diri");
await Future.delayed(const Duration(seconds: 3));
easyLoading.dismissLoading();
backPressed = true;
notifyListeners();
await navigationService.navigateToInputInformasiDiriView(
noHp: "082293246583",
);
}
}

View File

@ -23,7 +23,11 @@ class LoginUserView extends StatelessWidget {
return Scaffold(
body: WillPopScope(
onWillPop: () async {
return model.backPressed;
if (model.backPressed) {
// model.back();
model.quitApp(context);
}
return false;
},
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
@ -75,12 +79,14 @@ class LoginUserView extends StatelessWidget {
MyButton(
text: 'Login',
onPressed: () {
FocusScope.of(context).unfocus();
model.log.i('Login button pressed');
model.login();
},
),
TextButton(
onPressed: () {
FocusScope.of(context).unfocus();
model.daftar();
},
child: const Text(

View File

@ -1,14 +1,11 @@
import 'package:flutter/material.dart';
import '../../../app/app.router.dart';
import '../../../app/app.locator.dart';
import '../../../app/app.logger.dart';
import '../../../app/core/custom_base_view_model.dart';
import '../../../services/my_easyloading.dart';
class LoginUserViewModel extends CustomBaseViewModel {
final log = getLogger('LoginUserViewModel');
final easyloading = locator<MyEasyLoading>();
TextEditingController noHpController = TextEditingController();
TextEditingController passwordController = TextEditingController();
@ -21,13 +18,13 @@ class LoginUserViewModel extends CustomBaseViewModel {
login() async {
setBusy(true);
backPressed = false;
easyloading.showLoading();
await Future.delayed(const Duration(seconds: 5));
easyloading.dismissLoading();
easyLoading.showLoading();
await Future.delayed(const Duration(seconds: 2));
easyLoading.dismissLoading();
setBusy(false);
backPressed = true;
notifyListeners();
// await navigationService.navigateToHomeView();
await navigationService.navigateToUserIndexTrackingView();
}
daftar() async {

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './akun_user_view_model.dart';
class AkunUserView extends StatelessWidget {
const AkunUserView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<AkunUserViewModel>.reactive(
viewModelBuilder: () => AkunUserViewModel(),
onViewModelReady: (AkunUserViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
AkunUserViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'AkunUserView',
),
),
);
},
);
}
}

View File

@ -0,0 +1,5 @@
import 'package:reza_app/app/core/custom_base_view_model.dart';
class AkunUserViewModel extends CustomBaseViewModel {
Future<void> init() async {}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './makanan_list_view_model.dart';
class MakananListView extends StatelessWidget {
const MakananListView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<MakananListViewModel>.reactive(
viewModelBuilder: () => MakananListViewModel(),
onViewModelReady: (MakananListViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
MakananListViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'MakananListView',
),
),
);
},
);
}
}

View File

@ -0,0 +1,5 @@
import 'package:reza_app/app/core/custom_base_view_model.dart';
class MakananListViewModel extends CustomBaseViewModel {
Future<void> init() async {}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './pesanan_list_view_model.dart';
class PesananListView extends StatelessWidget {
const PesananListView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<PesananListViewModel>.reactive(
viewModelBuilder: () => PesananListViewModel(),
onViewModelReady: (PesananListViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
PesananListViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'PesananListView',
),
),
);
},
);
}
}

View File

@ -0,0 +1,5 @@
import 'package:reza_app/app/core/custom_base_view_model.dart';
class PesananListViewModel extends CustomBaseViewModel {
Future<void> init() async {}
}

View File

@ -0,0 +1,31 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import './reservasi_meja_view_model.dart';
class ReservasiMejaView extends StatelessWidget {
const ReservasiMejaView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<ReservasiMejaViewModel>.reactive(
viewModelBuilder: () => ReservasiMejaViewModel(),
onViewModelReady: (ReservasiMejaViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
ReservasiMejaViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'ReservasiMejaView',
),
),
);
},
);
}
}

View File

@ -0,0 +1,5 @@
import 'package:reza_app/app/core/custom_base_view_model.dart';
class ReservasiMejaViewModel extends CustomBaseViewModel {
Future<void> init() async {}
}

View File

@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stylish_bottom_bar/model/bar_items.dart';
import 'package:stylish_bottom_bar/stylish_bottom_bar.dart';
import '../../../../app/app.router.dart';
import '../../../../app/themes/app_colors.dart';
import '../../../../app/themes/app_text.dart';
import 'user_index_tracking_view_model.dart';
class UserIndexTrackingView extends StatelessWidget {
const UserIndexTrackingView({super.key});
@override
Widget build(BuildContext context) {
return ViewModelBuilder<UserIndexTrackingViewModel>.reactive(
viewModelBuilder: () => UserIndexTrackingViewModel(),
onViewModelReady: (UserIndexTrackingViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
UserIndexTrackingViewModel model,
Widget? child,
) {
return Scaffold(
appBar: AppBar(
title: Text(
model.header,
style: const TextStyle(
color: Colors.white,
fontSize: 20,
),
),
backgroundColor: mainColor,
elevation: 0,
automaticallyImplyLeading: false,
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
child: ExtendedNavigator(
navigatorKey: StackedService.nestedNavigationKey(3),
router: UserIndexTrackingViewRouter(),
observers: [
StackedService.routeObserver,
],
),
),
bottomNavigationBar: StylishBottomBar(
items: [
for (var item in model.bottomNavBarList)
BottomBarItem(
icon: Icon(item['icon'],
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? sixthGrey
: backgroundColor),
title: Text(
item['name'],
style: regularTextStyle.copyWith(
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? sixthGrey
: Colors.grey,
),
),
backgroundColor:
model.currentIndex == model.bottomNavBarList.indexOf(item)
? Colors.white
: Colors.grey,
),
],
currentIndex: model.currentIndex,
hasNotch: true,
backgroundColor: mainColor,
onTap: (value) {
model.handleNavigation(value);
},
option: BubbleBarOptions(
barStyle: BubbleBarStyle.horizotnal,
bubbleFillStyle: BubbleFillStyle.fill,
opacity: 0.3),
),
);
},
);
}
}

View File

@ -0,0 +1,110 @@
import 'package:back_button_interceptor/back_button_interceptor.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import '../../../../app/app.locator.dart';
import '../../../../app/app.logger.dart';
import '../../../../app/app.router.dart';
import '../../../../app/themes/app_colors.dart';
class UserIndexTrackingViewModel extends IndexTrackingViewModel {
final log = getLogger('UserIndexTrackingViewModel');
final navigationService = locator<NavigationService>();
bool backPressed = true;
Future<void> init() async {
BackButtonInterceptor.add(myInterceptor);
}
bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
// print("BACK BUTTON!"); // Do some stuff.
if (backPressed) {
quitApp(null);
}
return true;
}
final _bottomNavBarList = [
{
'name': 'Meja',
'icon': Icons.table_restaurant_outlined,
'header': 'RESERVASI MEJA',
},
{
'name': 'Makanan',
'icon': Icons.food_bank_outlined,
'header': 'LIST MAKANAN',
},
{
'name': 'Pesanan',
'icon': Icons.shopping_cart_outlined,
'header': 'LIST PESANAN',
},
{
'name': 'Akun',
'icon': Icons.person_outline,
'header': 'AKUN',
},
];
String header = 'RESERVASI MEJA';
List<Map<String, dynamic>> get bottomNavBarList => _bottomNavBarList;
final List<String> _views = [
UserIndexTrackingViewRoutes.reservasiMejaView,
UserIndexTrackingViewRoutes.makananListView,
UserIndexTrackingViewRoutes.pesananListView,
UserIndexTrackingViewRoutes.akunUserView,
];
void handleNavigation(int index) {
// log.d("handleNavigation: $index");
// log.d("currentIndex: $currentIndex");
if (currentIndex == index) return;
setIndex(index);
header = _bottomNavBarList[index]['header'] as String;
navigationService.navigateTo(
_views[index],
id: 3,
);
}
quitApp(BuildContext? context) {
backPressed = false;
showDialog(
context: context ?? StackedService.navigatorKey!.currentContext!,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Keluar'),
content: const Text('Apakah Anda yakin ingin keluar?'),
actions: [
TextButton(
onPressed: () {
backPressed = true;
Navigator.of(context).pop(false);
},
child: const Text('Batal'),
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
child: const Text(
'Keluar',
style: TextStyle(color: dangerColor),
),
),
],
);
},
).then((value) {
if (value == true) {
SystemNavigator.pop();
}
});
notifyListeners();
}
}

View File

@ -33,6 +33,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.11.0"
back_button_interceptor:
dependency: "direct main"
description:
name: back_button_interceptor
sha256: e47660f2178a4392eb72001f9594d3fdcb5efde93e59d2819d61fda499e781c8
url: "https://pub.dev"
source: hosted
version: "6.0.2"
boolean_selector:
dependency: transitive
description:

View File

@ -51,6 +51,7 @@ dependencies:
validatorless: ^1.2.3
intl:
otp_text_field: ^1.1.3
back_button_interceptor: ^6.0.2
dev_dependencies:
flutter_test: