Feat: add page passenger screen
This commit is contained in:
parent
5f4153fe62
commit
430cce5f10
|
@ -73,6 +73,12 @@
|
|||
"packageUri": "lib/",
|
||||
"languageVersion": "3.1"
|
||||
},
|
||||
{
|
||||
"name": "dropdown_button2",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/dropdown_button2-2.3.9",
|
||||
"packageUri": "lib/",
|
||||
"languageVersion": "2.17"
|
||||
},
|
||||
{
|
||||
"name": "fake_async",
|
||||
"rootUri": "file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.1",
|
||||
|
@ -440,7 +446,7 @@
|
|||
"languageVersion": "3.4"
|
||||
}
|
||||
],
|
||||
"generated": "2025-03-11T15:01:28.490605Z",
|
||||
"generated": "2025-03-12T12:18:16.494991Z",
|
||||
"generator": "pub",
|
||||
"generatorVersion": "3.5.0",
|
||||
"flutterRoot": "file:///D:/Flutter/flutter_sdk/flutter_3.24.0",
|
||||
|
|
|
@ -46,6 +46,10 @@ cupertino_icons
|
|||
3.1
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/cupertino_icons-1.0.8/lib/
|
||||
dropdown_button2
|
||||
2.17
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/dropdown_button2-2.3.9/
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/dropdown_button2-2.3.9/lib/
|
||||
fake_async
|
||||
2.12
|
||||
file:///C:/Users/ASUS/AppData/Local/Pub/Cache/hosted/pub.dev/fake_async-1.3.1/
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,4 @@
|
|||
#Tue Mar 11 22:03:16 WIB 2025
|
||||
#Wed Mar 12 19:14:57 WIB 2025
|
||||
base.0=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeExtDexDebug\\classes.dex
|
||||
base.1=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeLibDexDebug\\0\\classes.dex
|
||||
base.2=D\:\\Flutter\\Flutter Project\\e_porter\\build\\app\\intermediates\\dex\\debug\\mergeProjectDexDebug\\0\\classes.dex
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:e_porter/_core/constants/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||
|
||||
import '../../constants/typography.dart';
|
||||
|
||||
|
@ -20,27 +21,29 @@ class ButtonFill extends StatelessWidget {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: onTap,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isLoading ? GrayColors.gray500 : PrimaryColors.primary800,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(35.r),
|
||||
return ZoomTapAnimation(
|
||||
child: SizedBox(
|
||||
width: double.infinity,
|
||||
child: ElevatedButton(
|
||||
onPressed: onTap,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
isLoading ? GrayColors.gray500 : PrimaryColors.primary800,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(35.r),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 14.h),
|
||||
child: isLoading
|
||||
? _rowLoading()
|
||||
: TypographyStyles.h6(
|
||||
text,
|
||||
color: textColor,
|
||||
letterSpacing: 1,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 14.h),
|
||||
child: isLoading
|
||||
? _rowLoading()
|
||||
: TypographyStyles.h6(
|
||||
text,
|
||||
color: textColor,
|
||||
letterSpacing: 1,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:e_porter/_core/constants/colors.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
class DropdownComponent extends StatefulWidget {
|
||||
final String? value;
|
||||
final Function(String?) onChanged;
|
||||
final String hintText;
|
||||
|
||||
const DropdownComponent({
|
||||
Key? key,
|
||||
this.value,
|
||||
required this.onChanged,
|
||||
required this.hintText,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<DropdownComponent> createState() => _DropdownComponentState();
|
||||
}
|
||||
|
||||
class _DropdownComponentState extends State<DropdownComponent> {
|
||||
final List<String> items = ["KTP", "Paspor"];
|
||||
String? selectedValue;
|
||||
|
||||
bool _isMenuOpen = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
selectedValue = widget.value;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
width: MediaQuery.of(context).size.height * 0.14,
|
||||
child: DropdownButtonHideUnderline(
|
||||
child: DropdownButton2<String>(
|
||||
isExpanded: true,
|
||||
value: selectedValue,
|
||||
items: items.map((String item) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: item,
|
||||
child: Text(
|
||||
item,
|
||||
style: TextStyle(
|
||||
fontFamily: 'DMsans',
|
||||
fontSize: 16.sp,
|
||||
color: GrayColors.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
hint: Text(
|
||||
widget.hintText,
|
||||
style: TextStyle(
|
||||
fontFamily: 'DMsans',
|
||||
fontSize: 16.sp,
|
||||
color: GrayColors.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
onMenuStateChange: (isOpen) {
|
||||
setState(() {
|
||||
_isMenuOpen = isOpen;
|
||||
});
|
||||
},
|
||||
onChanged: (String? newValue) {
|
||||
setState(() {
|
||||
selectedValue = newValue;
|
||||
});
|
||||
widget.onChanged(newValue);
|
||||
},
|
||||
buttonStyleData: ButtonStyleData(
|
||||
padding: EdgeInsets.only(left: 10.w, right: 16.w, top: 4.h, bottom: 4.h),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
border: Border.all(width: 1.w, color: _isMenuOpen ? PrimaryColors.primary800 : GrayColors.gray200),
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
dropdownStyleData: DropdownStyleData(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
color: Colors.white,
|
||||
),
|
||||
elevation: 1,
|
||||
),
|
||||
menuItemStyleData: MenuItemStyleData(
|
||||
padding: EdgeInsets.only(left: 16.w, top: 8.h, bottom: 8.h),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,7 @@ class SearchBarComponent extends StatelessWidget {
|
|||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(10.r)
|
||||
),
|
||||
child: TextField(
|
||||
onChanged: onChanged,
|
|
@ -0,0 +1,44 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
|
||||
import '../../../constants/colors.dart';
|
||||
|
||||
class TextFieldComponent extends StatelessWidget {
|
||||
final TextEditingController? controller;
|
||||
final String hintText;
|
||||
|
||||
const TextFieldComponent({this.controller, required this.hintText});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Container(
|
||||
decoration: BoxDecoration(color: Colors.white, borderRadius: BorderRadius.circular(10.r)),
|
||||
child: TextField(
|
||||
controller: controller,
|
||||
decoration: InputDecoration(
|
||||
prefix: Padding(padding: EdgeInsets.symmetric(horizontal: 10.w)),
|
||||
hintText: hintText,
|
||||
hintStyle: TextStyle(
|
||||
fontFamily: 'DMsans',
|
||||
fontSize: 16.sp,
|
||||
color: GrayColors.gray600,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderSide: BorderSide(width: 1, color: GrayColors.gray200),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderSide: BorderSide(width: 1, color: GrayColors.gray200),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10.r),
|
||||
borderSide: BorderSide(width: 1.5.w, color: PrimaryColors.primary800),
|
||||
),
|
||||
contentPadding: EdgeInsets.symmetric(vertical: 16.h),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -11,6 +11,8 @@ class UserEntity {
|
|||
}
|
||||
|
||||
class UserData {
|
||||
final String? tipeId;
|
||||
final String? noId;
|
||||
final String? name;
|
||||
final String? email;
|
||||
final String? phone;
|
||||
|
@ -22,6 +24,8 @@ class UserData {
|
|||
final String? role;
|
||||
|
||||
UserData({
|
||||
required this.tipeId,
|
||||
required this.noId,
|
||||
required this.name,
|
||||
required this.email,
|
||||
required this.phone,
|
||||
|
@ -46,6 +50,8 @@ class UserData {
|
|||
}
|
||||
|
||||
return UserData(
|
||||
tipeId: map['tipeId'] ?? '',
|
||||
noId: map['noId'] ?? '',
|
||||
name: map['name'] as String?,
|
||||
email: map['email'] as String?,
|
||||
phone: map['phone'] as String?,
|
||||
|
@ -60,6 +66,8 @@ class UserData {
|
|||
|
||||
Map<String, dynamic> toMap() {
|
||||
return {
|
||||
'tipeId': tipeId,
|
||||
'noId': noId,
|
||||
'name': name,
|
||||
'email': email,
|
||||
'phone': phone,
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:e_porter/_core/service/logger_service.dart';
|
||||
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
||||
import 'package:firebase_core/firebase_core.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -8,7 +9,7 @@ void main() async {
|
|||
WidgetsFlutterBinding.ensureInitialized();
|
||||
await Firebase.initializeApp();
|
||||
|
||||
print("Firebase Initialized Successfully!");
|
||||
logger.d("Firebase Initialized Successfully!");
|
||||
runApp(MyApp(initialRoute: Routes.SPLASH));
|
||||
}
|
||||
|
||||
|
|
|
@ -59,22 +59,17 @@ class CardFlightInformation extends StatelessWidget {
|
|||
SizedBox(height: 4.h),
|
||||
Row(
|
||||
children: [
|
||||
TypographyStyles.body(departureCity, color: GrayColors.gray800, letterSpacing: 0.2),
|
||||
TypographyStyles.body(departureCity, color: GrayColors.gray800),
|
||||
SizedBox(width: 10.w),
|
||||
CustomeIcons.PlaneRightFilled(color: PrimaryColors.primary800),
|
||||
SizedBox(width: 10.w),
|
||||
TypographyStyles.body(arrivalCity, color: GrayColors.gray800, letterSpacing: 0.2)
|
||||
TypographyStyles.body(arrivalCity, color: GrayColors.gray800)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
Row(
|
||||
children: [
|
||||
TypographyStyles.small(
|
||||
plane,
|
||||
color: GrayColors.gray600,
|
||||
letterSpacing: 0.2,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
TypographyStyles.small(plane, color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
_buildText(context, text: seatClass),
|
||||
servicePorter != null ? _buildText(context, text: servicePorter!) : SizedBox.shrink(),
|
||||
],
|
||||
|
|
|
@ -17,6 +17,8 @@ import 'package:get/get.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||
|
||||
import '../../../../_core/service/logger_service.dart';
|
||||
|
||||
class BookingTickets extends StatefulWidget {
|
||||
const BookingTickets({super.key});
|
||||
|
||||
|
@ -117,7 +119,7 @@ class _BookingTicketsState extends State<BookingTickets> {
|
|||
setState(() {
|
||||
selectedDate = picked;
|
||||
selectedDateText = DateFormat('EEE, d MMM yyyy', 'en_US').format(selectedDate);
|
||||
print(selectedDate);
|
||||
logger.d(selectedDate);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
@ -202,25 +204,23 @@ class _BookingTicketsState extends State<BookingTickets> {
|
|||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
SizedBox(height: 20.h),
|
||||
ZoomTapAnimation(
|
||||
child: ButtonFill(
|
||||
text: 'Cari Tiket',
|
||||
textColor: Colors.white,
|
||||
onTap: () {
|
||||
if (selectedAirportFrom != null && selectedAirportTo != null) {
|
||||
final searchParams = {
|
||||
"from": '${selectedAirportFrom!.city}',
|
||||
"to": '${selectedAirportTo!.city}',
|
||||
"leavingDate": selectedDate,
|
||||
"flightClass": selectedClass.value,
|
||||
"passengerCount": selectedPassengerCount,
|
||||
};
|
||||
Get.toNamed(Routes.SEARCHTICKETS, arguments: searchParams);
|
||||
} else {
|
||||
Get.snackbar("Error", "Silakan pilih bandara keberangkatan dan tujuan");
|
||||
}
|
||||
},
|
||||
),
|
||||
ButtonFill(
|
||||
text: 'Cari Tiket',
|
||||
textColor: Colors.white,
|
||||
onTap: () {
|
||||
if (selectedAirportFrom != null && selectedAirportTo != null) {
|
||||
final searchParams = {
|
||||
"from": '${selectedAirportFrom!.city}',
|
||||
"to": '${selectedAirportTo!.city}',
|
||||
"leavingDate": selectedDate,
|
||||
"flightClass": selectedClass.value,
|
||||
"passengerCount": selectedPassengerCount,
|
||||
};
|
||||
Get.toNamed(Routes.SEARCHTICKETS, arguments: searchParams);
|
||||
} else {
|
||||
Get.snackbar("Error", "Silakan pilih bandara keberangkatan dan tujuan");
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:e_porter/_core/component/appbar/appbar_component.dart';
|
||||
import 'package:e_porter/_core/component/search_bar/search_bar_component.dart';
|
||||
import 'package:e_porter/_core/component/text_field/search_bar/search_bar_component.dart';
|
||||
import 'package:e_porter/_core/constants/colors.dart';
|
||||
import 'package:e_porter/_core/constants/typography.dart';
|
||||
import 'package:e_porter/presentation/controllers/search_flight_controller.dart';
|
||||
|
|
|
@ -14,8 +14,10 @@ import 'package:e_porter/presentation/screens/home/component/title_show_modal.da
|
|||
import 'package:e_porter/presentation/screens/routes/app_rountes.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
||||
|
||||
class TicketBookingStep1Screen extends StatefulWidget {
|
||||
|
@ -34,6 +36,7 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
late Future<FlightModel> _flightFuture;
|
||||
late final TicketController ticketController;
|
||||
final currencyFormatter = NumberFormat.decimalPattern('id_ID');
|
||||
dynamic _loggedUser;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
|
@ -107,14 +110,12 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
),
|
||||
bottomNavigationBar: CustomeShadowCotainner(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||
child: ZoomTapAnimation(
|
||||
child: ButtonFill(
|
||||
text: 'Lanjutkan',
|
||||
textColor: Colors.white,
|
||||
onTap: () {
|
||||
Get.toNamed(Routes.TICKETBOOKINGSTEP2);
|
||||
},
|
||||
),
|
||||
child: ButtonFill(
|
||||
text: 'Lanjutkan',
|
||||
textColor: Colors.white,
|
||||
onTap: () {
|
||||
Get.toNamed(Routes.TICKETBOOKINGSTEP2);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
|
@ -124,11 +125,12 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
return FutureBuilder(
|
||||
future: PreferencesService.getUserData(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return CustomeShadowCotainner(child: Center(child: CircularProgressIndicator()));
|
||||
if (snapshot.connectionState == ConnectionState.none) {
|
||||
return SizedBox.shrink();
|
||||
} else if (snapshot.hasData && snapshot.data != null) {
|
||||
final user = snapshot.data!;
|
||||
logger.d('Data user: ${user.email}');
|
||||
_loggedUser = user;
|
||||
logger.d('Data user: ${user.noId}');
|
||||
return CustomeShadowCotainner(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -159,7 +161,10 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
SizedBox(width: 20.w),
|
||||
SwitchButton(
|
||||
value: isToggled,
|
||||
onChanged: (newValue) {
|
||||
onChanged: (newValue) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool('isPassengerAdd', newValue);
|
||||
|
||||
setState(
|
||||
() {
|
||||
isToggled = newValue;
|
||||
|
@ -191,53 +196,116 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
children: List.generate(
|
||||
passenger,
|
||||
(index) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
'Penumpang 1 (Dewasa)',
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
child: CustomeIcons.EditOutline(),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
isScrollControlled: true,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.r),
|
||||
topRight: Radius.circular(10.r),
|
||||
),
|
||||
),
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Wrap(
|
||||
children: [
|
||||
TitleShowModal(
|
||||
text: 'Informasi Penumpang',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildAddPassenger(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
if (isToggled && index == 0 && _loggedUser != null) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
'${_loggedUser.name}',
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
SizedBox(height: 4.h),
|
||||
TypographyStyles.caption(
|
||||
"${_loggedUser.tipeId} - ${_loggedUser.noId}",
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w400,
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
child: CustomeIcons.EditOutline(),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
isScrollControlled: true,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.r),
|
||||
topRight: Radius.circular(10.r),
|
||||
),
|
||||
),
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Wrap(
|
||||
children: [
|
||||
TitleShowModal(
|
||||
text: 'Informasi Penumpang',
|
||||
onTap: () {},
|
||||
),
|
||||
_buildAddPassenger(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 16.h),
|
||||
child: CustomeShadowCotainner(
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
'Penumpang ${index + 1} (Dewasa)',
|
||||
color: GrayColors.gray800,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
ZoomTapAnimation(
|
||||
child: GestureDetector(
|
||||
child: CustomeIcons.EditOutline(),
|
||||
onTap: () {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: Colors.white,
|
||||
isScrollControlled: true,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(10.r),
|
||||
topRight: Radius.circular(10.r),
|
||||
),
|
||||
),
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
||||
child: Wrap(
|
||||
children: [
|
||||
TitleShowModal(
|
||||
text: 'Informasi Penumpang',
|
||||
onTap: () {
|
||||
Get.toNamed(Routes.ADDPASSENGER);
|
||||
},
|
||||
),
|
||||
_buildAddPassenger(),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
));
|
||||
}
|
||||
|
@ -245,6 +313,27 @@ class _TicketBookingStep1ScreenState extends State<TicketBookingStep1Screen> {
|
|||
Widget _buildAddPassenger() {
|
||||
return Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 16.h),
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 16.h),
|
||||
decoration: BoxDecoration(
|
||||
color: GrayColors.gray50,
|
||||
border: Border.all(width: 1.w, color: GrayColors.gray200),
|
||||
borderRadius: BorderRadius.circular(10.r)),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body("Muhammad Al Kahfi", color: GrayColors.gray800),
|
||||
SizedBox(height: 4.h),
|
||||
TypographyStyles.caption("KTP - 3571", color: GrayColors.gray800, fontWeight: FontWeight.w400)
|
||||
],
|
||||
),
|
||||
SvgPicture.asset('assets/icons/ic_more _than.svg')
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ import 'package:zoom_tap_animation/zoom_tap_animation.dart';
|
|||
import '../../../_core/constants/typography.dart';
|
||||
import '../../controllers/navigation_controller.dart';
|
||||
import '../boarding_pass/pages/boarding_pass_screen.dart';
|
||||
import '../profile/profile_screen.dart';
|
||||
import '../profile/pages/profile_screen.dart';
|
||||
|
||||
|
||||
class MainNavigation extends StatefulWidget {
|
||||
final int initialTabIndex;
|
||||
|
|
|
@ -0,0 +1,131 @@
|
|||
import 'package:e_porter/_core/component/appbar/appbar_component.dart';
|
||||
import 'package:e_porter/_core/component/button/button_fill.dart';
|
||||
import 'package:e_porter/_core/component/card/custome_shadow_cotainner.dart';
|
||||
import 'package:e_porter/_core/component/text_field/dropdown/dropdown_component.dart';
|
||||
import 'package:e_porter/_core/component/text_field/text_input/text_field_component.dart';
|
||||
import 'package:e_porter/_core/constants/colors.dart';
|
||||
import 'package:e_porter/_core/constants/typography.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class AddPassengerScreen extends StatefulWidget {
|
||||
const AddPassengerScreen({super.key});
|
||||
|
||||
@override
|
||||
State<AddPassengerScreen> createState() => _AddPassengerScreenState();
|
||||
}
|
||||
|
||||
class _AddPassengerScreenState extends State<AddPassengerScreen> {
|
||||
final ValueNotifier<String> selectedGender = ValueNotifier<String>('');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: GrayColors.gray50,
|
||||
appBar: DefaultAppbarComponent(
|
||||
backgroundColors: PrimaryColors.primary800,
|
||||
title: "Tambah Penumpang",
|
||||
textColor: Colors.white,
|
||||
onTab: () {
|
||||
Get.back();
|
||||
},
|
||||
),
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body(
|
||||
"Silahkan isi informasi data diri calon penumpang baru",
|
||||
color: GrayColors.gray600,
|
||||
fontWeight: FontWeight.w400,
|
||||
maxlines: 2,
|
||||
),
|
||||
SizedBox(height: 32.h),
|
||||
TypographyStyles.body('Nama Lengkap', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(height: 16.w),
|
||||
TextFieldComponent(hintText: 'Masukkan nama lengkap'),
|
||||
SizedBox(height: 20.h),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body('Tipe ID', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(height: 16.h),
|
||||
DropdownComponent(
|
||||
hintText: "Pilih jenis dokument",
|
||||
value: "KTP",
|
||||
onChanged: (value) {},
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(width: 16.w),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TypographyStyles.body('No ID', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
SizedBox(height: 16.h),
|
||||
TextFieldComponent(hintText: 'Masukkan ID')
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20.w),
|
||||
TypographyStyles.body('Jenis Kelamin', color: GrayColors.gray600, fontWeight: FontWeight.w400),
|
||||
Row(
|
||||
children: [
|
||||
_buildRadioButton(context, label: 'Laki-laki', value: 'Laki-laki'),
|
||||
SizedBox(width: 40.h),
|
||||
_buildRadioButton(context, label: 'Perempuan', value: 'Perempuan')
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
bottomNavigationBar: CustomeShadowCotainner(
|
||||
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 20.h),
|
||||
borderRadius: BorderRadius.circular(0.r),
|
||||
child: ButtonFill(
|
||||
text: 'Simpan',
|
||||
textColor: Colors.white,
|
||||
onTap: () {},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRadioButton(
|
||||
BuildContext context, {
|
||||
required String label,
|
||||
required String value,
|
||||
}) {
|
||||
return ValueListenableBuilder<String>(
|
||||
valueListenable: selectedGender,
|
||||
builder: (context, selected, child) {
|
||||
return Row(
|
||||
children: [
|
||||
Radio<String>(
|
||||
value: value,
|
||||
groupValue: selected,
|
||||
activeColor: PrimaryColors.primary800,
|
||||
onChanged: (val) {
|
||||
selectedGender.value = val!;
|
||||
},
|
||||
),
|
||||
SizedBox(width: 10.w),
|
||||
TypographyStyles.body(label, color: GrayColors.gray800, fontWeight: FontWeight.w500)
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../_core/constants/colors.dart';
|
||||
import '../../../_core/constants/typography.dart';
|
||||
import '../../../../_core/constants/colors.dart';
|
||||
import '../../../../_core/constants/typography.dart';
|
||||
|
||||
|
||||
|
||||
class ProfileScreen extends StatefulWidget {
|
||||
const ProfileScreen({super.key});
|
|
@ -19,7 +19,8 @@ import 'package:e_porter/presentation/screens/home/pages/ticket_booking_step3_sc
|
|||
import 'package:e_porter/presentation/screens/home/pages/ticket_booking_step4_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/navigation/main_navigation.dart';
|
||||
import 'package:e_porter/presentation/screens/onboarding/onboarding_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/profile/profile_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/profile/pages/profile_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/profile/pages/add_passenger_screen.dart';
|
||||
import 'package:e_porter/presentation/screens/splash/splash_screen.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
|
@ -82,7 +83,7 @@ class AppRoutes {
|
|||
GetPage(
|
||||
name: Routes.SEARCHTICKETS,
|
||||
page: () => SearchTicketsScreen(),
|
||||
binding: TicketBinding()
|
||||
binding: TicketBinding(),
|
||||
),
|
||||
GetPage(
|
||||
name: Routes.TICKETBOOKINGSTEP1,
|
||||
|
@ -112,6 +113,10 @@ class AppRoutes {
|
|||
name: Routes.TRANSACTIONHISTORY,
|
||||
page: () => transactionHistory(),
|
||||
),
|
||||
GetPage(
|
||||
name: Routes.ADDPASSENGER,
|
||||
page: () => AddPassengerScreen(),
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -136,4 +141,6 @@ class Routes {
|
|||
static const CHOOSECHAIR = '/choose_chair';
|
||||
static const PAYMENT = '/payment';
|
||||
static const TRANSACTIONHISTORY = '/transaction_history';
|
||||
|
||||
static const ADDPASSENGER = '/add_passenger';
|
||||
}
|
||||
|
|
|
@ -97,6 +97,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.0.8"
|
||||
dropdown_button2:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: dropdown_button2
|
||||
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.3.9"
|
||||
fake_async:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
|
|
@ -49,6 +49,7 @@ dependencies:
|
|||
firebase_auth: ^5.5.1
|
||||
shared_preferences: ^2.5.2
|
||||
logger: ^2.5.0
|
||||
dropdown_button2: ^2.3.9
|
||||
# pin_code_fields: ^8.0.1
|
||||
# dio: ^5.8.0+1
|
||||
|
||||
|
|
Loading…
Reference in New Issue