263 lines
9.6 KiB
Dart
263 lines
9.6 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_screenutil/flutter_screenutil.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:loader_overlay/loader_overlay.dart';
|
|
|
|
import '../../../app/app.dart';
|
|
import 'widgets/product_image_header.dart';
|
|
import 'widgets/product_info.dart';
|
|
import 'widgets/product_specification_tab.dart';
|
|
import 'widgets/product_sliver_appbar.dart';
|
|
|
|
class ProductDetailsPage extends StatelessWidget {
|
|
final ProductModel model;
|
|
|
|
ProductDetailsPage({required this.model});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return GetX<ProductController>(
|
|
init: ProductController(model),
|
|
builder: (pc) => Scaffold(
|
|
body: pc.state.isLoading.value
|
|
? CustomLoader()
|
|
: SafeArea(
|
|
top: false,
|
|
child: LoaderOverlay(
|
|
useDefaultLoading: false,
|
|
overlayColor: Colors.transparent,
|
|
overlayWidget: CustomLoader(),
|
|
child: Scaffold(
|
|
appBar: CustomAppbarWidget(leading: AppBarBackBtn()),
|
|
body: SliverAppBarWithTabBar(model: model, pc: pc),
|
|
bottomNavigationBar: Padding(
|
|
padding: const EdgeInsets.only(left: 16.0, right: 16, bottom: 16.0, top: 8),
|
|
child: ColoredButton(
|
|
title: 'add_to_cart'.tr,
|
|
callback: () => pc.onAddToCart(context, model),
|
|
btnColor: ThemeColor.mainColor,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
List<Widget> buildSimpleProductScreen(ProductModel model) {
|
|
return [
|
|
SizedBox(height: 20.h),
|
|
ProductNameWidget(model: model),
|
|
SizedBox(height: 20.h),
|
|
ProductImageHeader(images: model.images, model: model),
|
|
SizedBox(height: 20.h),
|
|
ProductPriceWidget(model: model),
|
|
SizedBox(height: 20.h),
|
|
AppTheme.appColorDivider,
|
|
Container(
|
|
color: Colors.amber,
|
|
height: 1.sh - 120.h * 2, // 120.h is appbar height
|
|
child: ProductSpecificationsWidget(
|
|
model: model,
|
|
),
|
|
),
|
|
];
|
|
}
|
|
|
|
List<Widget> buildConfigurableProductScreen(ProductController pc) {
|
|
final selectedOption = pc.state.selectedOption.value;
|
|
|
|
final List<SimpleOption>? simpleOptions = pc.state.simpleAttribute.value?.options;
|
|
final selectedSimpleOption = pc.state.selectedSimpleOption.value;
|
|
|
|
final List<ProductModel>? optionProducts = selectedOption != null ? selectedOption.variants.products : [];
|
|
|
|
final attrText = pc.state.attribute.value != null ? pc.state.attribute.value!.attribute.name : '';
|
|
|
|
final attrValue = pc.state.selectedOption.value != null ? pc.state.selectedOption.value!.option : '';
|
|
|
|
final List<Option> options = pc.state.attribute.value != null ? pc.state.attribute.value!.options : [];
|
|
|
|
final ProductModel? selectedProduct = pc.state.selectedProduct.value;
|
|
|
|
final List<Widget> _list = [
|
|
SizedBox(height: 20.h),
|
|
selectedProduct != null ? ProductNameWidget(model: selectedProduct) : SizedBox.shrink(),
|
|
SizedBox(height: 20.h),
|
|
|
|
selectedProduct != null
|
|
? ProductImageHeader(
|
|
model: selectedProduct,
|
|
images: selectedOption != null
|
|
? selectedOption.images
|
|
: selectedSimpleOption != null
|
|
? selectedSimpleOption.images
|
|
: [],
|
|
)
|
|
: SizedBox.shrink(),
|
|
SizedBox(height: 20.h),
|
|
|
|
// label
|
|
selectedOption != null
|
|
? Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 4),
|
|
child: Row(
|
|
children: [
|
|
Text(attrText + ':'),
|
|
SizedBox(width: 6),
|
|
Text(
|
|
attrValue,
|
|
style: new TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
],
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
|
|
// images
|
|
selectedOption != null
|
|
? SingleChildScrollView(
|
|
scrollDirection: Axis.horizontal,
|
|
child: Row(
|
|
children: mapIndexed(
|
|
options,
|
|
(index, Option option) => Padding(
|
|
padding: const EdgeInsets.only(left: 8.0),
|
|
child: GestureDetector(
|
|
onTap: () => pc.onSuperAttributeChange(option),
|
|
child: Container(
|
|
width: 80.h,
|
|
height: 80.h,
|
|
padding: const EdgeInsets.all(4),
|
|
decoration: new BoxDecoration(
|
|
// color: Colors.amberAccent,
|
|
border: Border.all(
|
|
color: option.option == selectedOption.option
|
|
? ThemeColor.mainColor
|
|
: Colors.grey.withOpacity(0.50),
|
|
width: option.option == selectedOption.option ? 2 : 1,
|
|
),
|
|
borderRadius: BorderRadius.circular(8)),
|
|
// padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
|
|
margin: const EdgeInsets.symmetric(horizontal: 4, vertical: 4),
|
|
child: cachedImageNetwork(
|
|
option.images.length > 0 ? option.images.first.originalImageUrl : '',
|
|
BoxFit.fill,
|
|
const BorderRadius.all(Radius.circular(4.0)),
|
|
0.22.sw,
|
|
0.15.sh,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
).toList(),
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
|
|
selectedOption != null ? SizedBox(height: 20.h) : SizedBox.shrink(),
|
|
|
|
selectedProduct != null ? ProductPriceWidget(model: selectedProduct) : SizedBox.shrink(),
|
|
SizedBox(height: 20.h),
|
|
|
|
AppTheme.appColorDivider,
|
|
SizedBox(height: 10),
|
|
selectedOption != null
|
|
? Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Text(
|
|
selectedOption.variants.attribute!.name,
|
|
style: new TextStyle(fontWeight: FontWeight.bold),
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
|
|
SizedBox(height: 10),
|
|
|
|
optionProducts != null
|
|
? Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Wrap(
|
|
children: mapIndexed(
|
|
optionProducts,
|
|
(index, ProductModel product) => GestureDetector(
|
|
onTap: () => pc.onInnerAttributeChange(product),
|
|
child: Container(
|
|
decoration: new BoxDecoration(
|
|
border: Border.all(
|
|
color: product.id == selectedProduct?.id
|
|
? ThemeColor.mainColor
|
|
: Colors.grey.withOpacity(0.50),
|
|
width: product.id == selectedProduct?.id ? 2 : 1,
|
|
),
|
|
borderRadius: BorderRadius.circular(8)),
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
margin: EdgeInsets.only(right: 8),
|
|
child: Text(product.optionValue ?? ''),
|
|
),
|
|
),
|
|
).toList(),
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
|
|
// simple option label
|
|
pc.state.simpleAttribute.value != null
|
|
? Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Text(
|
|
pc.state.simpleAttribute.value?.attribute.name ?? '',
|
|
style: new TextStyle(
|
|
fontWeight: FontWeight.bold,
|
|
),
|
|
))
|
|
: SizedBox.shrink(),
|
|
|
|
SizedBox(height: 10),
|
|
|
|
simpleOptions != null
|
|
? Padding(
|
|
padding: EdgeInsets.symmetric(horizontal: 16.w),
|
|
child: Wrap(
|
|
children: mapIndexed(
|
|
simpleOptions,
|
|
(index, SimpleOption option) => GestureDetector(
|
|
onTap: () => pc.onSimpleAttributeChange(option),
|
|
child: Container(
|
|
decoration: new BoxDecoration(
|
|
border: Border.all(
|
|
color: option.option == selectedSimpleOption?.option
|
|
? ThemeColor.mainColor
|
|
: Colors.grey.withOpacity(0.50),
|
|
width: option.option == selectedSimpleOption?.option ? 2 : 1,
|
|
),
|
|
borderRadius: BorderRadius.circular(8)),
|
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
|
margin: EdgeInsets.only(right: 8),
|
|
child: Text(option.product.optionValue ?? ''),
|
|
),
|
|
),
|
|
).toList(),
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
|
|
SizedBox(height: 10),
|
|
AppTheme.appColorDivider,
|
|
|
|
selectedProduct != null
|
|
? Container(
|
|
color: Colors.amber,
|
|
height: 1.sh - 120.h * 2, // 120.h is appbar height
|
|
child: ProductSpecificationsWidget(
|
|
model: model,
|
|
),
|
|
)
|
|
: SizedBox.shrink(),
|
|
];
|
|
|
|
return _list;
|
|
}
|
|
}
|