tambah detail makanan page dengan flutter hook

This commit is contained in:
kicap
2023-07-21 17:05:00 +08:00
parent b20b414a21
commit 4350e3503e
10 changed files with 649 additions and 66 deletions

View File

@ -1,4 +1,5 @@
import 'package:reza_app/ui/views/user_ui/akun_user/akun_user_view.dart';
import 'package:reza_app/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_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';
@ -31,6 +32,7 @@ import '../ui/views/splash_screen/splash_screen_view.dart';
MaterialRoute(page: AkunUserView),
],
),
MaterialRoute(page: DetailMakananView),
],
// 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 _i8;
import 'package:flutter/material.dart' as _i9;
import 'package:flutter/material.dart';
import 'package:reza_app/ui/views/daftar_user_ui/input_informasi_diri/input_informasi_diri_view.dart'
as _i6;
@ -16,17 +16,19 @@ import 'package:reza_app/ui/views/daftar_user_ui/verifikasi_no_hp/verifikasi_no_
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;
as _i13;
import 'package:reza_app/ui/views/user_ui/makanan_list/detail_makanan/detail_makanan_view.dart'
as _i8;
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/pesanan_list/pesanan_list_view.dart'
as _i12;
import 'package:reza_app/ui/views/user_ui/reservasi_meja/reservasi_meja_view.dart'
as _i9;
as _i10;
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 _i13;
import 'package:stacked_services/stacked_services.dart' as _i14;
class Routes {
static const splashScreenView = '/';
@ -41,6 +43,8 @@ class Routes {
static const userIndexTrackingView = '/user-index-tracking-view';
static const detailMakananView = '/detail-makanan-view';
static const all = <String>{
splashScreenView,
loginUserView,
@ -48,6 +52,7 @@ class Routes {
verifikasiNoHpView,
inputInformasiDiriView,
userIndexTrackingView,
detailMakananView,
};
}
@ -77,48 +82,58 @@ class StackedRouter extends _i1.RouterBase {
Routes.userIndexTrackingView,
page: _i7.UserIndexTrackingView,
),
_i1.RouteDef(
Routes.detailMakananView,
page: _i8.DetailMakananView,
),
];
final _pagesMap = <Type, _i1.StackedRouteFactory>{
_i2.SplashScreenView: (data) {
return _i8.MaterialPageRoute<dynamic>(
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i2.SplashScreenView(),
settings: data,
);
},
_i3.LoginUserView: (data) {
return _i8.MaterialPageRoute<dynamic>(
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i3.LoginUserView(),
settings: data,
);
},
_i4.MasukanNoHpView: (data) {
return _i8.MaterialPageRoute<dynamic>(
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i4.MasukanNoHpView(),
settings: data,
);
},
_i5.VerifikasiNoHpView: (data) {
return _i8.MaterialPageRoute<dynamic>(
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i5.VerifikasiNoHpView(),
settings: data,
);
},
_i6.InputInformasiDiriView: (data) {
final args = data.getArgs<InputInformasiDiriViewArguments>(nullOk: false);
return _i8.MaterialPageRoute<dynamic>(
return _i9.MaterialPageRoute<dynamic>(
builder: (context) =>
_i6.InputInformasiDiriView(key: args.key, noHp: args.noHp),
settings: data,
);
},
_i7.UserIndexTrackingView: (data) {
return _i8.MaterialPageRoute<dynamic>(
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i7.UserIndexTrackingView(),
settings: data,
fullscreenDialog: true,
);
},
_i8.DetailMakananView: (data) {
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i8.DetailMakananView(),
settings: data,
);
},
};
@override
@ -133,7 +148,7 @@ class InputInformasiDiriViewArguments {
required this.noHp,
});
final _i8.Key? key;
final _i9.Key? key;
final String noHp;
@ -175,44 +190,44 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
final _routes = <_i1.RouteDef>[
_i1.RouteDef(
UserIndexTrackingViewRoutes.reservasiMejaView,
page: _i9.ReservasiMejaView,
page: _i10.ReservasiMejaView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.makananListView,
page: _i10.MakananListView,
page: _i11.MakananListView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.pesananListView,
page: _i11.PesananListView,
page: _i12.PesananListView,
),
_i1.RouteDef(
UserIndexTrackingViewRoutes.akunUserView,
page: _i12.AkunUserView,
page: _i13.AkunUserView,
),
];
final _pagesMap = <Type, _i1.StackedRouteFactory>{
_i9.ReservasiMejaView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i9.ReservasiMejaView(),
_i10.ReservasiMejaView: (data) {
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i10.ReservasiMejaView(),
settings: data,
);
},
_i10.MakananListView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i10.MakananListView(),
_i11.MakananListView: (data) {
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i11.MakananListView(),
settings: data,
);
},
_i11.PesananListView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i11.PesananListView(),
_i12.PesananListView: (data) {
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.PesananListView(),
settings: data,
);
},
_i12.AkunUserView: (data) {
return _i8.MaterialPageRoute<dynamic>(
builder: (context) => const _i12.AkunUserView(),
_i13.AkunUserView: (data) {
return _i9.MaterialPageRoute<dynamic>(
builder: (context) => const _i13.AkunUserView(),
settings: data,
);
},
@ -224,7 +239,7 @@ class UserIndexTrackingViewRouter extends _i1.RouterBase {
Map<Type, _i1.StackedRouteFactory> get pagesMap => _pagesMap;
}
extension NavigatorStateExtension on _i13.NavigationService {
extension NavigatorStateExtension on _i14.NavigationService {
Future<dynamic> navigateToSplashScreenView([
int? routerId,
bool preventDuplicates = true,
@ -282,7 +297,7 @@ extension NavigatorStateExtension on _i13.NavigationService {
}
Future<dynamic> navigateToInputInformasiDiriView({
_i8.Key? key,
_i9.Key? key,
required String noHp,
int? routerId,
bool preventDuplicates = true,
@ -312,6 +327,20 @@ extension NavigatorStateExtension on _i13.NavigationService {
transition: transition);
}
Future<dynamic> navigateToDetailMakananView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return navigateTo<dynamic>(Routes.detailMakananView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
navigateToNestedReservasiMejaViewInUserIndexTrackingViewRouter([
int? routerId,
@ -426,7 +455,7 @@ extension NavigatorStateExtension on _i13.NavigationService {
}
Future<dynamic> replaceWithInputInformasiDiriView({
_i8.Key? key,
_i9.Key? key,
required String noHp,
int? routerId,
bool preventDuplicates = true,
@ -456,6 +485,20 @@ extension NavigatorStateExtension on _i13.NavigationService {
transition: transition);
}
Future<dynamic> replaceWithDetailMakananView([
int? routerId,
bool preventDuplicates = true,
Map<String, String>? parameters,
Widget Function(BuildContext, Animation<double>, Animation<double>, Widget)?
transition,
]) async {
return replaceWith<dynamic>(Routes.detailMakananView,
id: routerId,
preventDuplicates: preventDuplicates,
parameters: parameters,
transition: transition);
}
Future<dynamic>
replaceWithNestedReservasiMejaViewInUserIndexTrackingViewRouter([
int? routerId,

View File

@ -0,0 +1,327 @@
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:stacked/stacked.dart';
import '../../../../../app/themes/app_colors.dart';
import '../../../../../app/themes/app_text.dart';
import '../../../../widgets/my_white_container.dart';
import './detail_makanan_view_model.dart';
class DetailMakananView extends HookWidget {
const DetailMakananView({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final scrollController = useScrollController();
final opacity = useState(0.0);
final theHeight = useState(MediaQuery.of(useContext()).size.height * 0.35);
checkScrollValue(scrollController, opacity, theHeight);
return ViewModelBuilder<DetailMakananViewModel>.reactive(
viewModelBuilder: () => DetailMakananViewModel(),
onViewModelReady: (DetailMakananViewModel model) async {
await model.init();
},
builder: (
BuildContext context,
DetailMakananViewModel model,
Widget? child,
) {
return Scaffold(
backgroundColor: backgroundColor,
body: SizedBox(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Stack(
children: [
ListView.builder(
controller: scrollController,
itemCount: 1,
itemBuilder: (context, index) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
const TopMenuWidget(),
const SecondWidget(),
const SizedBox(
height: 10,
),
MyWhiteContainer(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 10,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
RichText(
text: TextSpan(
children: [
TextSpan(
text: 'Ongkos Kirim',
style: boldTextStyle.copyWith(
fontSize: 14,
),
),
TextSpan(
text: ' Rp. 10.000',
style: boldTextStyle.copyWith(
fontSize: 14,
color: dangerColor,
),
),
],
),
),
const SizedBox(
height: 10,
),
Text(
"Bisa Dibayar COD sekitar Parepare",
style: regularTextStyle.copyWith(
fontSize: 13,
color: fontGrey,
),
),
],
),
),
),
],
);
},
),
TopBarWidget(opacity: opacity),
],
),
),
);
},
);
}
void checkScrollValue(
ScrollController scrollController,
ValueNotifier<double> opacity,
ValueNotifier<double> theHeight,
) {
scrollController.addListener(() {
opacity.value = scrollController.offset / theHeight.value;
if (opacity.value > 1) {
opacity.value = 1;
} else if (opacity.value < 0) {
opacity.value = 0;
}
});
}
}
class TopBarWidget extends ViewModelWidget<DetailMakananViewModel> {
const TopBarWidget({
super.key,
required this.opacity,
});
final ValueNotifier<double> opacity;
@override
Widget build(BuildContext context, DetailMakananViewModel viewModel) {
return Positioned(
top: 0,
child: Container(
padding: const EdgeInsets.all(10),
width: MediaQuery.of(context).size.width,
color: Colors.white.withOpacity(opacity.value),
child: Column(
children: [
SizedBox(
height: MediaQuery.of(context).padding.top,
),
Row(
// create 3 circle widget, with background color is black and opacity is 0.5, ist icon is back, second icon is cart and third icon is 3 dots
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
onPressed: () {
viewModel.back();
},
icon: const Icon(
Icons.arrow_back,
color: Colors.white,
),
),
),
const Expanded(
child: SizedBox(
width: 20,
),
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
onPressed: () {},
icon: const Icon(
Icons.shopping_cart_outlined,
color: Colors.white,
),
),
),
const SizedBox(
width: 20,
),
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: Colors.black.withOpacity(0.5),
borderRadius: BorderRadius.circular(20),
),
child: IconButton(
onPressed: () {},
icon: const Icon(
Icons.more_vert,
color: Colors.white,
),
),
),
],
),
],
),
),
);
}
}
class SecondWidget extends ViewModelWidget<DetailMakananViewModel> {
const SecondWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, DetailMakananViewModel viewModel) {
return MyWhiteContainer(
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Burger King Handcrafted Burgers ",
style: regularTextStyle.copyWith(
fontSize: 17,
),
),
const SizedBox(
height: 10,
),
Text(
"Rp. 25.000",
style: regularTextStyle.copyWith(
fontSize: 18,
color: dangerColor,
),
),
const SizedBox(
height: 10,
),
Row(
children: [
Expanded(
child: Text(
"49 Terjual",
style: regularTextStyle.copyWith(
fontSize: 14,
color: fontGrey,
),
),
),
const SizedBox(
width: 10,
),
IconButton(
onPressed: () {},
icon: const Icon(
Icons.favorite_border,
color: fontGrey,
),
),
const SizedBox(
width: 10,
),
],
)
],
),
),
],
),
);
}
}
class TopMenuWidget extends ViewModelWidget<DetailMakananViewModel> {
const TopMenuWidget({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, DetailMakananViewModel viewModel) {
return Stack(
children: [
SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height * 0.35,
child: Image.network(
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
fit: BoxFit.cover,
),
),
Positioned(
bottom: 10,
right: 10,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 5,
),
// width: 20,
height: 20,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: const Center(
child: Text(
'1 / 2',
style: TextStyle(
color: fontGrey,
fontSize: 12,
),
),
),
),
),
],
);
}
}

View File

@ -0,0 +1,8 @@
import '../../../../../app/app.logger.dart';
import '../../../../../app/core/custom_base_view_model.dart';
class DetailMakananViewModel extends CustomBaseViewModel {
final log = getLogger('DetailMakananViewModel');
Future<void> init() async {}
}

View File

@ -1,6 +1,9 @@
import 'package:flutter/material.dart';
import 'package:reza_app/ui/widgets/my_textformfield.dart';
import 'package:reza_app/ui/widgets/my_white_container.dart';
import 'package:stacked/stacked.dart';
import '../../../../app/themes/app_colors.dart';
import './makanan_list_view_model.dart';
class MakananListView extends StatelessWidget {
@ -18,11 +21,177 @@ class MakananListView extends StatelessWidget {
MakananListViewModel model,
Widget? child,
) {
return const Scaffold(
body: Center(
child: Text(
'MakananListView',
),
return Scaffold(
backgroundColor: backgroundColor,
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// get the top height of the notification bar
SizedBox(
height: MediaQuery.of(context).padding.top,
),
MyWhiteContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
flex: 2,
child: IconButton(
onPressed: () => model.back(),
icon: const Icon(Icons.arrow_back),
),
),
const SizedBox(
width: 10,
),
Expanded(
flex: 10,
child: MyTextFormField(
// controller: model.searchController,
hintText: 'Cari Makanan',
suffixIcon: IconButton(
onPressed: () {},
icon: const Icon(Icons.search),
),
),
),
Expanded(
flex: 1,
child: IconButton(
onPressed: () {},
icon: const Icon(Icons.filter_list),
),
),
TextButton(
onPressed: () {},
child: const Text('Filter'),
),
],
),
),
const SizedBox(
height: 5,
),
MyWhiteContainer(
child: IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: TextButton(
onPressed: () {},
child: const Text('Terbaru'),
),
),
const VerticalDivider(
color: mainGrey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Text(
'Terlaris',
style: TextStyle(
color: mainGrey,
),
),
),
),
const VerticalDivider(
color: Colors.grey,
thickness: 1,
),
Expanded(
child: TextButton(
onPressed: () {},
child: const Row(
children: [
Text(
'Harga',
style: TextStyle(
color: mainGrey,
),
),
Icon(
Icons.arrow_drop_down,
color: mainGrey,
),
],
),
),
),
],
),
),
),
const SizedBox(
height: 10,
),
Expanded(
child: Center(
child: SingleChildScrollView(
child: Wrap(
spacing: 10,
runSpacing: 10,
children: [
for (var i = 0; i < 10; i++)
GestureDetector(
onTap: () => model.goToDetailMakanan(),
child: Container(
width: MediaQuery.of(context).size.width * 0.46,
color: Colors.white,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Image.network(
'https://a.cdn-hotels.com/gdcs/production0/d1513/35c1c89e-408c-4449-9abe-f109068f40c0.jpg?impolicy=fcrop&w=800&h=533&q=medium',
height: 150,
width: double.infinity,
fit: BoxFit.fill,
),
const SizedBox(
height: 5,
),
const Padding(
padding: EdgeInsets.only(
left: 5,
),
child: Text(
'Product Name',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(
height: 5,
),
const Padding(
padding: EdgeInsets.only(
left: 5,
),
child: Text(
'Rp. 100.000',
style: TextStyle(
color: Colors.grey,
),
),
),
const SizedBox(
height: 5,
),
],
),
),
),
],
),
),
),
),
],
),
);
},

View File

@ -1,5 +1,13 @@
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 MakananListViewModel extends CustomBaseViewModel {
final log = getLogger('MakananListViewModel');
Future<void> init() async {}
goToDetailMakanan() {
log.i('goToDetailMakanan');
navigationService.navigateTo(Routes.detailMakananView);
}
}

View File

@ -25,27 +25,14 @@ class UserIndexTrackingView extends StatelessWidget {
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,
],
),
backgroundColor: backgroundColor,
extendBody: false,
body: ExtendedNavigator(
navigatorKey: StackedService.nestedNavigationKey(3),
router: UserIndexTrackingViewRouter(),
observers: [
StackedService.routeObserver,
],
),
bottomNavigationBar: StylishBottomBar(
items: [
@ -56,13 +43,16 @@ class UserIndexTrackingView extends StatelessWidget {
model.bottomNavBarList.indexOf(item)
? sixthGrey
: backgroundColor),
title: Text(
item['name'],
style: regularTextStyle.copyWith(
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? sixthGrey
: Colors.grey,
title: Align(
alignment: Alignment.centerLeft,
child: Text(
item['name'],
style: regularTextStyle.copyWith(
color: model.currentIndex ==
model.bottomNavBarList.indexOf(item)
? sixthGrey
: Colors.grey,
),
),
),
backgroundColor:

View File

@ -0,0 +1,27 @@
import 'package:flutter/material.dart';
class MyWhiteContainer extends StatelessWidget {
final Widget? child;
final double? height;
const MyWhiteContainer({
Key? key,
this.child,
this.height,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: height,
padding: const EdgeInsets.symmetric(
vertical: 10,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: child,
);
}
}