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

@ -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: