diff --git a/lib/core/viewModels/pharmacyModule/product_detail_view_model.dart b/lib/core/viewModels/pharmacyModule/product_detail_view_model.dart index c7ac0a04..2b1d3f86 100644 --- a/lib/core/viewModels/pharmacyModule/product_detail_view_model.dart +++ b/lib/core/viewModels/pharmacyModule/product_detail_view_model.dart @@ -36,7 +36,7 @@ class ProductDetailViewModel extends BaseViewModel{ Future getProductLocationData() async { hasError = false; - setState(ViewState.Busy); + setState(ViewState.BusyLocal); await _productDetailService.getProductAvailabiltyDetail(); if (_productDetailService.hasError) { error = _productDetailService.error; diff --git a/lib/pages/pharmacies/screens/product-details/availability_info.dart b/lib/pages/pharmacies/screens/product-details/availability_info.dart index 55d2468c..6a6fdfd5 100644 --- a/lib/pages/pharmacies/screens/product-details/availability_info.dart +++ b/lib/pages/pharmacies/screens/product-details/availability_info.dart @@ -6,80 +6,76 @@ import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart'; import 'package:flutter/material.dart'; class AvailabilityInfo extends StatelessWidget { + final ProductDetailViewModel previousModel; + + const AvailabilityInfo({Key key, this.previousModel}) : super(key: key); @override Widget build(BuildContext context) { - return BaseView( - onModelReady: (model) => model.getProductLocationData(), - allowAny: true, - builder: (_, model, wi) => NetworkBaseView( - baseViewModel: model, - child: model.productLocationService.length == 0 - ? Container( - padding: EdgeInsets.all(15), - alignment: Alignment.center, - child: Text( - TranslationBase.of(context).noLocationAvailable, - ), - ) - : ListView.builder( - physics: ScrollPhysics(), - scrollDirection: Axis.vertical, - shrinkWrap: true, - itemCount: model.productLocationService.length, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: EdgeInsets.all(8.0), - child: Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Expanded( - flex: 1, - child: Image.network(model - .productLocationService[index].projectImageUrl), - ), - SizedBox( - width: 10, - ), - Expanded( - flex: 4, - child: Text( - model.productLocationService[index] - .locationDescription + - "\n" + - convertCityName( - model.productLocationService[0].cityName - .toString(), - ), - style: TextStyle(fontSize: 12), - ), - ), - Expanded( - flex: 1, - child: IconButton( - icon: Icon(Icons.location_on), - color: Colors.red, - onPressed: () {}, - ), - ), - Expanded( - flex: 1, - child: IconButton( - icon: Icon(Icons.phone), - color: Colors.red, - onPressed: () {}, - ), - ), - ], - ), - Divider(height: 1.2, color: Colors.grey) - ], + return previousModel.productLocationService.length == 0 + ? Container( + padding: EdgeInsets.all(15), + alignment: Alignment.center, + child: Text( + TranslationBase.of(context).noLocationAvailable, + ), + ) + : ListView.builder( + physics: ScrollPhysics(), + scrollDirection: Axis.vertical, + shrinkWrap: true, + itemCount: previousModel.productLocationService.length, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.all(8.0), + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Expanded( + flex: 1, + child: Image.network(previousModel + .productLocationService[index].projectImageUrl), + ), + SizedBox( + width: 10, + ), + Expanded( + flex: 4, + child: Text( + previousModel.productLocationService[index] + .locationDescription + + "\n" + + convertCityName( + previousModel.productLocationService[0].cityName + .toString(), + ), + style: TextStyle(fontSize: 12), + ), + ), + Expanded( + flex: 1, + child: IconButton( + icon: Icon(Icons.location_on), + color: Colors.red, + onPressed: () {}, ), - ); - }, + ), + Expanded( + flex: 1, + child: IconButton( + icon: Icon(Icons.phone), + color: Colors.red, + onPressed: () {}, + ), + ), + ], ), - ), + Divider(height: 1.2, color: Colors.grey) + ], + ), + ); + }, ); } } diff --git a/lib/pages/pharmacies/screens/product-details/discount_description.dart b/lib/pages/pharmacies/screens/product-details/discount_description.dart index 1c2b27d4..1dde8175 100644 --- a/lib/pages/pharmacies/screens/product-details/discount_description.dart +++ b/lib/pages/pharmacies/screens/product-details/discount_description.dart @@ -1,5 +1,4 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart'; -import 'package:diplomaticquarterapp/core/viewModels/project_view_model.dart'; import 'package:flutter/material.dart'; class DiscountDescription extends StatelessWidget { diff --git a/lib/pages/pharmacies/screens/product-details/footor/footer-widget.dart b/lib/pages/pharmacies/screens/product-details/footor/footer-widget.dart index 3ecf4b83..7cdfe7f2 100644 --- a/lib/pages/pharmacies/screens/product-details/footor/footer-widget.dart +++ b/lib/pages/pharmacies/screens/product-details/footor/footer-widget.dart @@ -1,8 +1,5 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart'; import 'package:diplomaticquarterapp/core/service/AuthenticatedUserObject.dart'; -import 'package:diplomaticquarterapp/pages/landing/landing_page.dart'; -import 'package:diplomaticquarterapp/pages/login/login.dart'; -import 'package:diplomaticquarterapp/pages/login/welcome.dart'; import 'package:diplomaticquarterapp/pages/pharmacies/screens/product-details/footor/quantity_box.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; import 'package:diplomaticquarterapp/widgets/buttons/secondary_button.dart'; diff --git a/lib/pages/pharmacies/screens/product-details/product-detail.dart b/lib/pages/pharmacies/screens/product-details/product-detail.dart index 5e8f4dd5..c263f77a 100644 --- a/lib/pages/pharmacies/screens/product-details/product-detail.dart +++ b/lib/pages/pharmacies/screens/product-details/product-detail.dart @@ -25,7 +25,7 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/recommendedProduct_mo import '../cart-order-page.dart'; import 'package:diplomaticquarterapp/uitl/app_shared_preferences.dart'; -import 'ProductAppBar.dart'; +import 'shared/product_details_app_bar.dart'; import 'availability_info.dart'; import 'details_info.dart'; import 'discount_description.dart'; @@ -102,304 +102,228 @@ class __ProductDetailPageState extends State } Widget build(BuildContext context) { - ProjectViewModel projectViewModel = Provider.of(context); - final screenSize = MediaQuery.of(context).size; - - return AppScaffold( - appBarTitle: TranslationBase.of(context).productDetails, - isShowAppBar: true, - isPharmacy: true, - isShowDecPage: false, - customAppBar: ProductAppBar(product: widget.product,), - body: SingleChildScrollView( - child: Column( - children: [ - Container( - width: double.infinity, - color: Colors.white, - child: Column( - children: [ - if (widget.product.images.isNotEmpty) - Container( - height: MediaQuery.of(context).size.height * .40, - child: Image.network( - widget.product.images[0].src.trim(), - fit: BoxFit.contain, + return BaseView( + allowAny: true, + builder: (_, model, wi) => AppScaffold( + appBarTitle: TranslationBase.of(context).productDetails, + isShowAppBar: true, + isPharmacy: true, + isShowDecPage: false, + customAppBar: ProductAppBar( + product: widget.product, + ), + body: SingleChildScrollView( + child: Column( + children: [ + Container( + width: double.infinity, + color: Colors.white, + child: Column( + children: [ + if (widget.product.images.isNotEmpty) + Container( + height: MediaQuery.of(context).size.height * .40, + child: Image.network( + widget.product.images[0].src.trim(), + fit: BoxFit.contain, + ), ), - ), - if (widget.product.discountDescription != null) - DiscountDescription(product: widget.product) - ], + if (widget.product.discountDescription != null) + DiscountDescription(product: widget.product) + ], + ), ), - ), - SizedBox( - height: 4, - ), - Container( - color: Colors.white, - child: ProductNameAndPrice( - context, - widget.product, - customerId: customerId, - addToWishlistFunction: (item) { - addToWishlistFunction(item); - setState(() {}); - }, - deleteFromWishlistFunction: (item) { - deleteFromWishlistFunction(item); - setState(() {}); - }, - notifyMeWhenAvailable: (context, itemId) { - notifyMeWhenAvailable(context, itemId); - }, - isInWishList: isInWishList, + SizedBox( + height: 4, ), - ), - SizedBox( - height: 6, - ), - Container( - color: Colors.white, - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: EdgeInsets.symmetric( - vertical: 15, horizontal: 10), - child: Texts( - TranslationBase.of(context).specification, - fontSize: 15, - fontWeight: FontWeight.bold, + Container( + color: Colors.white, + child: ProductNameAndPrice( + context, + widget.product, + customerId: customerId, + addToWishlistFunction: (item) { + addToWishlistFunction(item); + setState(() {}); + }, + deleteFromWishlistFunction: (item) { + deleteFromWishlistFunction(item); + setState(() {}); + }, + notifyMeWhenAvailable: (context, itemId) { + notifyMeWhenAvailable(context, itemId); + }, + isInWishList: isInWishList, + ), + ), + SizedBox( + height: 6, + ), + Container( + color: Colors.white, + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + padding: EdgeInsets.symmetric( + vertical: 15, horizontal: 10), + child: Texts( + TranslationBase.of(context).specification, + fontSize: 15, + fontWeight: FontWeight.bold, + ), + width: double.infinity, ), - width: double.infinity, - ), - // Divider(color: Colors.grey), - ], + // Divider(color: Colors.grey), + ], + ), ), - ), - SizedBox( - height: 6, - ), - // Container( - // height: 500, - // color: Colors.white, - // child: Scaffold( - // backgroundColor: Colors.white, - // extendBodyBehindAppBar: false, - // appBar: PreferredSize( - // preferredSize: Size.fromHeight( - // MediaQuery.of(context).size.height * 0.070), - // child: Container( - // height: MediaQuery.of(context).size.height * 0.070, - // decoration: BoxDecoration( - // border: Border( - // bottom: BorderSide( - // color: Theme.of(context).dividerColor, - // width: 0.5), //width: 0.7 - // ), - // color: Colors.white), - // child: Center( - // child: TabBar( - // isScrollable: false, - // controller: _tabController, - // // indicatorColor: Colors.transparent, - // indicatorWeight: 1.0, - // indicatorSize: TabBarIndicatorSize.tab, - // indicatorColor:Colors.green, - // labelColor: Theme.of(context).primaryColor, - // labelPadding: EdgeInsets.only( - // top: 0, left: 0, right: 0, bottom: 0), - // unselectedLabelColor: Colors.grey[800], - // tabs: [ - // tabWidget(screenSize, _activeTab == 0, - // TranslationBase.of(context).details, - // ), - // tabWidget(screenSize, _activeTab == 1, - // TranslationBase.of(context).review, - // ), - // tabWidget(screenSize, _activeTab == 2, - // TranslationBase.of(context).availability), - // ], - // ), - // ), - // ), - // ), - // body: Column( - // children: [ - // Expanded( - // child: TabBarView( - // physics: BouncingScrollPhysics(), - // controller: _tabController, - // children: [ - // DetailsInfo( - // product: widget.product, - // ), - // ReviewsInfo( - // product: widget.product, - // ), - // AvailabilityInfo() - // ], - // ), - // ), - // - // ], - // ), - // ), - // ), - - SizedBox( - height: 6, - ), - - //TODO Elham* Remove this - Container( - // width: 500, - margin: EdgeInsets.only(bottom: 6), - color: Colors.white, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - Column( - children: [ - FlatButton( - onPressed: () { - setState(() { - isDetails = true; - isReviews = false; - isAvailability = false; - }); - }, - child: Text( - TranslationBase.of(context).details, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold), + SizedBox( + height: 6, + ), + Container( + // width: 500, + margin: EdgeInsets.only(bottom: 6), + color: Colors.white, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + Column( + children: [ + FlatButton( + onPressed: () { + setState(() { + isDetails = true; + isReviews = false; + isAvailability = false; + }); + }, + child: Text( + TranslationBase.of(context).details, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold), + ), + color: Colors.white, ), - color: Colors.white, - ), - CustomDivider( - color: isDetails - ? Colors.green - : Colors.transparent, - ) - ], - ), - SizedBox( - width: 20, - ), - Column( - children: [ - FlatButton( - onPressed: () { - setState(() { - isDetails = false; - isReviews = true; - isAvailability = false; - }); - }, - child: Text( - TranslationBase.of(context).reviews, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold), + CustomDivider( + color: isDetails + ? Colors.green + : Colors.transparent, + ) + ], + ), + SizedBox( + width: 20, + ), + Column( + children: [ + FlatButton( + onPressed: () async { + if(widget.product.approvedTotalReviews>0) { + GifLoaderDialogUtils.showMyDialog( + context); + await model.getProductReviewsData( + widget.product.id); + GifLoaderDialogUtils.hideDialog(context); + } + setState(() { + isDetails = false; + isReviews = true; + isAvailability = false; + }); + }, + child: Text( + TranslationBase.of(context).reviews, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold), + ), + color: Colors.white, ), - color: Colors.white, - ), - CustomDivider( - color: isReviews - ? Colors.green - : Colors.transparent, - ), - ], - ), - SizedBox( - width: 20, - ), - Column( - children: [ - FlatButton( - onPressed: () { - setState(() { - isDetails = false; - isReviews = false; - isAvailability = true; - }); - }, - child: Text( - TranslationBase.of(context).availability, - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold), + CustomDivider( + color: isReviews + ? Colors.green + : Colors.transparent, ), - color: Colors.white, - ), - CustomDivider( - color: isAvailability - ? Colors.green - : Colors.transparent, - ), - ], - ), - ], - ), - SizedBox( - height: 10, - ), - isDetails - ? DetailsInfo( - product: widget.product, - ) - : isReviews - ? ReviewsInfo( - product: widget.product, - ) - : isAvailability - ? AvailabilityInfo() - : Container(), - ], - ), - ), - - ///TODO Elham* check if we need recommanded - // Row( - // children: [ - // customerId != null - // ? Container( - // width: 410, - // height: 50, - // color: Colors.white, - // child: Texts( - // TranslationBase.of(context).recommended, - // bold: true, - // ), - // ) - // : Container(), - // ], - // ), - // RecommendedProducts(product: widget.product) + ], + ), + SizedBox( + width: 20, + ), + Column( + children: [ + FlatButton( + onPressed: () async { + GifLoaderDialogUtils.showMyDialog( + context); + await model.getProductLocationData(); + GifLoaderDialogUtils.hideDialog(context); - SizedBox( - height: 80, - ) - ], + setState(() { + isDetails = false; + isReviews = false; + isAvailability = true; + }); + }, + child: Text( + TranslationBase.of(context).availability, + style: TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold), + ), + color: Colors.white, + ), + CustomDivider( + color: isAvailability + ? Colors.green + : Colors.transparent, + ), + ], + ), + ], + ), + SizedBox( + height: 10, + ), + isDetails + ? DetailsInfo( + product: widget.product, + ) + : isReviews + ? ReviewsInfo( + product: widget.product, + previousModel: model, + ) + : isAvailability + ? AvailabilityInfo( + previousModel: model, + ) + : Container(), + ], + ), + ), + SizedBox( + height: 80, + ) + ], + ), ), - ), - bottomSheet: FooterWidget( - widget.product.stockAvailability != 'Out of stock', - widget.product.orderMaximumQuantity, - widget.product.orderMinimumQuantity, - widget.product.stockQuantity, - widget.product, - price: price, - isOverQuantity: isOverQuantity, - addToCartFunction: addToCartFunction, - ), - ); - + bottomSheet: FooterWidget( + widget.product.stockAvailability != 'Out of stock', + widget.product.orderMaximumQuantity, + widget.product.orderMinimumQuantity, + widget.product.stockQuantity, + widget.product, + price: price, + isOverQuantity: isOverQuantity, + addToCartFunction: addToCartFunction, + ), + )); } } diff --git a/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart b/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart index 619a4fb1..4301ce36 100644 --- a/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart +++ b/lib/pages/pharmacies/screens/product-details/product-name-and-price.dart @@ -10,7 +10,7 @@ import 'package:provider/provider.dart'; import 'package:rating_bar/rating_bar.dart'; import '../../../../locator.dart'; -import 'CustomIcon.dart'; +import 'shared/icon_with_bg.dart'; class ProductNameAndPrice extends StatefulWidget { BuildContext context; diff --git a/lib/pages/pharmacies/screens/product-details/reviews_info.dart b/lib/pages/pharmacies/screens/product-details/reviews_info.dart index c48e249f..15260071 100644 --- a/lib/pages/pharmacies/screens/product-details/reviews_info.dart +++ b/lib/pages/pharmacies/screens/product-details/reviews_info.dart @@ -1,97 +1,89 @@ import 'package:diplomaticquarterapp/core/model/pharmacies/PharmacyProduct.dart'; import 'package:diplomaticquarterapp/core/viewModels/pharmacyModule/product_detail_view_model.dart'; -import 'package:diplomaticquarterapp/pages/base/base_view.dart'; import 'package:diplomaticquarterapp/uitl/translations_delegate_base.dart'; -import 'package:diplomaticquarterapp/widgets/others/network_base_view.dart'; import 'package:flutter/material.dart'; import 'package:rating_bar/rating_bar.dart'; class ReviewsInfo extends StatelessWidget { final PharmacyProduct product; + final ProductDetailViewModel previousModel; - const ReviewsInfo({Key key, this.product}) : super(key: key); + const ReviewsInfo({Key key, this.product, this.previousModel}) : super(key: key); @override Widget build(BuildContext context) { - return BaseView( - onModelReady: (model) => model.getProductReviewsData(product.id), - allowAny: true, - builder: (_, model, wi) => NetworkBaseView( - baseViewModel:model , - child: model.productDetailService.length != 0 && - model.productDetailService[0].reviews.length != 0 - ? ListView.builder( - physics: ScrollPhysics(), - itemCount: model.productDetailService[0].reviews.length, - scrollDirection: Axis.vertical, - shrinkWrap: true, - itemBuilder: (BuildContext context, int index) { - return Padding( - padding: EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - child: Row( - children: [ - Container( - child: Text( - model.productDetailService[0].reviews[index] - .customerId - .toString(), - style: TextStyle( - fontSize: 17, - color: Colors.grey, - fontWeight: FontWeight.w600), - ), - ), - Container( - margin: EdgeInsets.only(left: 210), - child: RatingBar.readOnly( - initialRating: model.productDetailService[0] - .reviews[index].rating - .toDouble(), - size: 15.0, - filledColor: Colors.yellow[700], - emptyColor: Colors.grey[500], - isHalfAllowed: true, - halfFilledIcon: Icons.star_half, - filledIcon: Icons.star, - emptyIcon: Icons.star, - ), - ), - ], - ), - ), - SizedBox( - height: 10, - ), - Container( - child: Text( - model.productDetailService[0].reviews[index] - .reviewText, - style: TextStyle(fontSize: 20), - ), - ), - SizedBox( - height: 50, - ), - Divider(height: 1, color: Colors.grey), - ], + return previousModel.productDetailService.length != 0 && + previousModel.productDetailService[0].reviews.length != 0 + ? ListView.builder( + physics: ScrollPhysics(), + itemCount: previousModel.productDetailService[0].reviews.length, + scrollDirection: Axis.vertical, + shrinkWrap: true, + itemBuilder: (BuildContext context, int index) { + return Padding( + padding: EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + child: Row( + children: [ + Container( + child: Text( + previousModel.productDetailService[0].reviews[index] + .customerId + .toString(), + style: TextStyle( + fontSize: 17, + color: Colors.grey, + fontWeight: FontWeight.w600), + ), ), - ); - }, - ) - : Container( - padding: EdgeInsets.all(15), - alignment: Alignment.center, + Container( + margin: EdgeInsets.only(left: 210), + child: RatingBar.readOnly( + initialRating: previousModel.productDetailService[0] + .reviews[index].rating + .toDouble(), + size: 15.0, + filledColor: Colors.yellow[700], + emptyColor: Colors.grey[500], + isHalfAllowed: true, + halfFilledIcon: Icons.star_half, + filledIcon: Icons.star, + emptyIcon: Icons.star, + ), + ), + ], + ), + ), + SizedBox( + height: 10, + ), + Container( child: Text( - TranslationBase.of(context).noReviewsAvailable, + previousModel.productDetailService[0].reviews[index] + .reviewText, + style: TextStyle(fontSize: 20), ), -// Text('No Reviews Available'), ), + SizedBox( + height: 50, + ), + Divider(height: 1, color: Colors.grey), + ], + ), + ); + }, + ) + : Container( + padding: EdgeInsets.all(15), + alignment: Alignment.center, + child: Text( + TranslationBase.of(context).noReviewsAvailable, ), +// Text('No Reviews Available'), ); } } diff --git a/lib/pages/pharmacies/screens/product-details/CustomIcon.dart b/lib/pages/pharmacies/screens/product-details/shared/icon_with_bg.dart similarity index 93% rename from lib/pages/pharmacies/screens/product-details/CustomIcon.dart rename to lib/pages/pharmacies/screens/product-details/shared/icon_with_bg.dart index fc8b2288..9033cd72 100644 --- a/lib/pages/pharmacies/screens/product-details/CustomIcon.dart +++ b/lib/pages/pharmacies/screens/product-details/shared/icon_with_bg.dart @@ -11,7 +11,6 @@ class IconWithBg extends StatelessWidget { @override Widget build(BuildContext context) { return Container( - // margin: EdgeInsets.only(left: 25), width: 40, height: 40, decoration: BoxDecoration( diff --git a/lib/pages/pharmacies/screens/product-details/ProductAppBar.dart b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart similarity index 96% rename from lib/pages/pharmacies/screens/product-details/ProductAppBar.dart rename to lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart index 2fad8016..0fd1f03d 100644 --- a/lib/pages/pharmacies/screens/product-details/ProductAppBar.dart +++ b/lib/pages/pharmacies/screens/product-details/shared/product_details_app_bar.dart @@ -7,10 +7,10 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:provider/provider.dart'; -import '../../../../locator.dart'; -import '../../compare-list.dart'; -import '../cart-order-page.dart'; -import 'CustomIcon.dart'; +import '../../../../../locator.dart'; +import '../../../compare-list.dart'; +import '../../cart-order-page.dart'; +import 'icon_with_bg.dart'; class ProductAppBar extends StatelessWidget with PreferredSizeWidget {