Initial commit

This commit is contained in:
jahongireshonqulov
2025-10-17 19:42:02 +05:00
commit 9fbdabafb4
1420 changed files with 28021 additions and 0 deletions

View File

@@ -0,0 +1,459 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/custom_ui/toast_ui.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/models/city_response.dart';
import 'package:grostore/models/country_response.dart';
import 'package:grostore/models/state_response.dart';
import 'package:grostore/presenters/address_presenter.dart';
import 'package:grostore/screens/address/addresses.dart';
import 'package:grostore/screens/profile.dart';
class AddressNewOrUpdate extends StatefulWidget {
int? addressId;
AddressNewOrUpdate({super.key, this.addressId});
@override
State<AddressNewOrUpdate> createState() => _AddressNewOrUpdateState();
}
class _AddressNewOrUpdateState extends State<AddressNewOrUpdate> {
AddressPresenter addressPresenter = AddressPresenter();
@override
void initState() {
// TODO: implement initState
if (widget.addressId != null) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
addressPresenter.getEditAddressData(widget.addressId, context);
});
}else{
addressPresenter.getCountries();
}
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar.show(
title: widget.addressId == null
? AppLang.local(context).add_new_address_ucf
: AppLang.local(context).update_address,
context: context),
body: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.all(StyleConfig.padding),
child: ListenableBuilder(
listenable: addressPresenter,
builder: (context, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
//buildLabelText(AppLang.local(context).country),
space(size: 10),
// buildButton(AppLang.local(context).select_country,
// addressPresenter.selectedCountry?.name ?? "", () {
// showCountryDialog();
// }),
countryDropDown(),
space(),
//buildLabelText(AppLang.local(context).state),
//space(size: 10),
// buildButton(AppLang.local(context).select_state,
// addressPresenter.selectedState?.name ?? '', () {
// if (addressPresenter.selectedCountry != null) {
// showStateDialog();
// } else {
// ToastUi.show(context,
// AppLang.local(context).please_select_a_country);
// }
// }),
stateDropDown(),
space(),
// buildLabelText(AppLang.local(context).city),
// space(size: 10),
// buildButton(AppLang.local(context).select_city,
// addressPresenter.selectedCity?.name ?? '', () {
// if (addressPresenter.selectedState != null) {
// showCityDialog();
// } else {
// ToastUi.show(context,
// AppLang.local(context).please_select_a_state);
// }
// }),
cityDropDown(),
space(),
isDefaultDropDown(),
space(),
Container(
height: 100,
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
decoration: BoxDecorations.customRadius(
radius: BorderRadius.circular(8))
.copyWith(
border: Border.all(color: ThemeConfig.grey)),
child: TextField(
controller: addressPresenter.addressController,
decoration: const InputDecoration.collapsed(
hintText: "2/5 Elephant Road, New Town"),
),
),
space(),
Button(
onPressed: () {
if (widget.addressId != null) {
addressPresenter.updateAddress(context,
id: widget.addressId!,
countryInfo: addressPresenter.selectedCountry,
stateInfo: addressPresenter.selectedState,
cityInfo: addressPresenter.selectedCity,
fullAddress: addressPresenter.addressController.text.trim(),
isDefault:
addressPresenter.defaultAddress == "No"
? 0
: 1);
} else {
addressPresenter.addAddress(context,
countryInfo: addressPresenter.selectedCountry,
stateInfo: addressPresenter.selectedState,
cityInfo: addressPresenter.selectedCity,
fullAddress: addressPresenter
.addressController.text
.trim(),
isDefault:
addressPresenter.defaultAddress == "No"
? 0
: 1);
}
Navigator.of(context).pop();
},
shape: StyleConfig.buttonRadius(8),
color: ThemeConfig.red,
minWidth: getWidth(context),
minHeight: 40.0,
child: Text(
AppLang.local(context).save,
style: StyleConfig.fs14cWhitefwBold,
))
],
);
}),
),
),
);
}
Text buildLabelText(String text) => Text(
text,
style: StyleConfig.fs14fwBold,
);
Widget space({size = 24}) {
return SizedBox(
height: size.toDouble(),
);
}
Button buildButton(String title, value, onPress) {
return Button(
onPressed: () => onPress(),
color: ThemeConfig.grey,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8), topLeft: Radius.circular(8))),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
width: 120,
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecorations.customRadius(
radius: const BorderRadius.only(
bottomLeft: Radius.circular(8),
topLeft: Radius.circular(8)),
color: ThemeConfig.secondaryColor),
child: Text(
title,
style: StyleConfig.fs14cWhitefwNormal,
),
),
Container(
constraints: BoxConstraints(maxWidth: getWidth(context) * 0.5),
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 10),
//decoration: BoxDecorations.customRadius(radius: BorderRadius.only(bottomRight: Radius.circular(8),topRight: Radius.circular(8)),color: ThemeConfig.grey),
child: Text(
value,
style: StyleConfig.fs14cWhitefwNormal,
maxLines: 1,
),
),
const Spacer(),
const Icon(Icons.arrow_drop_down_outlined)
],
));
}
Widget countryDropDown(){
return DropdownButtonFormField<CountryInfo>(
decoration: InputDecoration(
labelText: AppLang.local(context).select_country,
border: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor)
),
),
value: addressPresenter.selectedCountry,
onChanged: (CountryInfo? country) {
if(country!=null){
addressPresenter.setSelectedCountry(country);
}
},
dropdownColor: Colors.white,
items:addressPresenter.countries.map<DropdownMenuItem<CountryInfo>>((e) =>DropdownMenuItem(
value: e,
child: Text(e.name,style: StyleConfig.fs14fwNormal,),
) ).toList(),
);
}
Widget stateDropDown(){
return DropdownButtonFormField<StateInfo>(
decoration: InputDecoration(
labelText: AppLang.local(context).select_state,
border: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor)
),
),
value: addressPresenter.selectedState,
onChanged: (StateInfo? state) {
if(state!=null) {
addressPresenter.setSelectedState(state);
}
},
dropdownColor: Colors.white,
items:addressPresenter.states.map<DropdownMenuItem<StateInfo>>((e) =>DropdownMenuItem(
value: e,
child: Text(e.name,style: StyleConfig.fs14fwNormal,),
) ).toList(),
);
}
Widget cityDropDown(){
return DropdownButtonFormField<CityInfo>(
decoration: InputDecoration(
labelText: AppLang.local(context).select_city,
border: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor)
),
),
value: addressPresenter.selectedCity,
onChanged: (CityInfo? city) {
if(city!=null) {
addressPresenter.setSelectedCity(city);
}
},
dropdownColor: Colors.white,
items:addressPresenter.cities.map<DropdownMenuItem<CityInfo>>((e) =>DropdownMenuItem(
value: e,
child: Text(e.name,style: StyleConfig.fs14fwNormal,),
) ).toList(),
);
}
Widget isDefaultDropDown(){
return DropdownButtonFormField<String>(
decoration: InputDecoration(
labelText: AppLang.local(context).default_address,
border: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor)
),
),
onChanged: (String? value) {
if(value!=null) {
addressPresenter.setDefaultAddress(value);
}
},
value: addressPresenter.defaultAddress,
dropdownColor: Colors.white,
items:["No", "Set Default"].map<DropdownMenuItem<String>>((e) =>DropdownMenuItem(
value: e,
child: Text(e,style: StyleConfig.fs14fwNormal,),
) ).toList(),
);
}
/*
showCountryDialog() {
showDialog(
context: context,
builder: (context) => ListenableBuilder(
listenable: addressPresenter,
builder: (context, child) {
return AlertDialog(
title: TextField(
onChanged: (text) {
print(text);
addressPresenter.filterCountry(text);
},
decoration: InputDecorations.basic(hint_text: "search...")),
content: Container(
height: 250,
child: SingleChildScrollView(
child: Column(
children: List.generate(
addressPresenter.filteredCountries.length,
(index) => Button(
onPressed: () {
Navigator.pop(context);
},
child: Container(
constraints: BoxConstraints(
minWidth: getWidth(context)),
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecorations.basic(),
child: Text(
addressPresenter
.filteredCountries[index].name,
style: StyleConfig.fs14fwNormal,
)),
))),
),
),
actions: [
Button(
color: ThemeConfig.grey,
onPressed: () {
Navigator.pop(context);
},
child: Text(
AppLang.local(context).close,
style: StyleConfig.fs14cWhitefwNormal,
))
],
);
}));
}
showStateDialog() {
showDialog(
context: context,
builder: (context) => ListenableBuilder(
listenable: addressPresenter,
builder: (context, child) {
return AlertDialog(
title: TextField(
onChanged: (text) {
addressPresenter.filterState(text);
},
decoration: InputDecorations.basic(hint_text: "search...")),
content: Container(
height: 250,
child: SingleChildScrollView(
child: Column(
children: List.generate(
addressPresenter.filteredStates.length,
(index) => Button(
onPressed: () {
Navigator.pop(context);
addressPresenter.setSelectedState(
addressPresenter.filteredStates[index]);
},
child: Container(
constraints: BoxConstraints(
minWidth: getWidth(context)),
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecorations.basic(),
child: Text(
addressPresenter
.filteredStates[index].name,
style: StyleConfig.fs14fwNormal,
)),
))),
),
),
actions: [
Button(
color: ThemeConfig.grey,
onPressed: () {
Navigator.pop(context);
},
child: Text(
AppLang.local(context).close,
style: StyleConfig.fs14cWhitefwNormal,
))
],
);
}));
}
showCityDialog() {
showDialog(
context: context,
builder: (context) => ListenableBuilder(
listenable: addressPresenter,
builder: (context, child) {
return AlertDialog(
title: TextField(
onChanged: (text) {
addressPresenter.filterCity(text);
},
decoration: InputDecorations.basic(hint_text: "search...")),
content: Container(
height: 250,
child: SingleChildScrollView(
child: Column(
children: List.generate(
addressPresenter.filteredCities.length,
(index) => Button(
onPressed: () {
Navigator.pop(context);
addressPresenter.setSelectedCity(
addressPresenter.filteredCities[index]);
},
child: Container(
constraints: BoxConstraints(
minWidth: getWidth(context)),
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
margin: EdgeInsets.only(bottom: 10),
decoration: BoxDecorations.basic(),
child: Text(
addressPresenter
.filteredCities[index].name,
style: StyleConfig.fs14fwNormal,
)),
))),
),
),
actions: [
Button(
color: ThemeConfig.grey,
onPressed: () {
Navigator.pop(context);
},
child: Text(
AppLang.local(context).close,
style: StyleConfig.fs14cWhitefwNormal,
))
],
);
}));
}
*/
}

View File

@@ -0,0 +1,202 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Boxdecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/filter_dropdown.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/address_presenter.dart';
import 'package:grostore/presenters/user_presenter.dart';
import 'package:grostore/screens/address/address_new_or_update.dart';
import 'package:grostore/screens/check_out.dart';
import 'package:provider/provider.dart';
class Addresses extends StatefulWidget {
const Addresses({super.key});
@override
State<Addresses> createState() => _AddressesState();
}
class _AddressesState extends State<Addresses> {
@override
void initState() {
// TODO: implement initState
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<AddressPresenter>(context, listen: false).initState();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar.show(
title: AppLang.local(context).address,
context: context,
bottom: PreferredSize(
preferredSize: Size(getWidth(context), 40),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
minWidth: getWidth(context) - (StyleConfig.padding * 2),
shape: StyleConfig.buttonRadius(2)
.copyWith(side: BorderSide(color: ThemeConfig.extraDarkGrey)),
onPressed: () {
MakeRoute.go(context, AddressNewOrUpdate());
},
child: Text(
AppLang.local(context).add_new_address_ucf,
style: StyleConfig.fs14fwNormal,
),
),
),
),
body: Consumer<AddressPresenter>(builder: (context, data, child) {
return addresses(data);
}),
);
}
Widget addresses(AddressPresenter data) {
return RefreshIndicator(
onRefresh: data.onRefresh,
child: Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
//color: Colors.red,
width: getWidth(context),
child: data.isFetchAddress
? ListView.separated(
itemCount: data.addresses.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.vertical,
itemBuilder: (context, index) {
return Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
MakeRoute.goAndRemoveAll(context,const CheckOut());
},
child: Container(
padding: const EdgeInsets.all(10),
width: getWidth(context),
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(width: 2, color: ThemeConfig.grey)),
child: Stack(
children: [
Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.addresses[index].address,
style: StyleConfig.fs14fwNormal,
maxLines: 1,
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).city}: ",
style: StyleConfig.fs14fwBold,
),
Text(
data.addresses[index].cityName,
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).state}: ",
style: StyleConfig.fs14fwBold,
),
Text(
data.addresses[index].stateName,
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).country}: ",
style: StyleConfig.fs14fwBold,
),
Text(
data.addresses[index].countryName,
style: StyleConfig.fs14fwNormal,
),
],
),
),
],
),
Positioned(
top: 0,
right: 0,
child: Column(
children: [
SizedBox(
height: 25,
width: 25,
child: Button(
onPressed: (){
MakeRoute.go(context, AddressNewOrUpdate(addressId:data.addresses[index].id ,));
},
padding: EdgeInsets.zero,
minWidth: 10.0,
minHeight: 10.0,
child:const Icon(Icons.edit,),
),
),
const SizedBox(height: 15,),
SizedBox(
height: 25,
width: 25,
child: Button(
onPressed: (){
data.deleteAddress(data.addresses[index].id , context);
},
padding: EdgeInsets.zero,
minWidth: 10.0,
minHeight: 10.0,
child:const Icon(Icons.delete,),
),
),
],
))
],
),
),
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
height: 10,
);
},
)
: Shimmers.list(10, getWidth(context) * 0.5, 100),
),
);
}
}

View File

@@ -0,0 +1,300 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/auth_ui.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/auth/auth_presenter.dart';
import 'package:grostore/screens/auth/password_forget.dart';
import 'package:grostore/screens/auth/registration.dart';
import 'package:provider/provider.dart';
import '../../custom_ui/BoxDecorations.dart';
class Login extends StatefulWidget {
const Login({super.key});
@override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
@override
Widget build(BuildContext context) {
Provider.of<AuthPresenter>(context, listen: false).setContext(context);
return AuthScreen.buildScreen(
context, buildBody(context, getWidth(context))
);
}
Widget buildBody(BuildContext context, double screenWidth) {
return Consumer<AuthPresenter>(builder: (context, data, child) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
width: screenWidth * (3 / 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getWidth(context),
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).welcome_to_back,
style: StyleConfig.fs24fwBold,
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).phone,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
/// #Country change
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
decoration: BoxDecorations.basic(
),
height: 36,
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 14.0),
child: Icon(
Icons.phone,
size: 18,
color: ThemeConfig.mediumGrey,
),
),
Text(
"+998",
style: StyleConfig.fs14fwNormal,
),
// Button(
// minWidth: 80,
// onPressed: () {
// showDialog(
// context: context,
// builder: (context) {
// return buildFilterDialog(data);
// });
// },
// child: Row(
// children: [
// Image.asset(
// "${getAssetFlag(data.regCountry.code.toLowerCase())}.png"),
//
// ],
// ),
// ),
Container(
padding: const EdgeInsets.only(left: 10),
width: getWidth(context) - 200,
child: TextField(
keyboardType: TextInputType.number,
textInputAction: TextInputAction.next,
style: StyleConfig.fs14fwNormal,
decoration: const InputDecoration.collapsed(
hintText: "XX XXX XXX"),
controller: data.loginPhoneNumberController,
),
)
],
)),
),
// Padding(
// padding: const EdgeInsets.only(bottom: 8.0),
// child: Column(
// crossAxisAlignment: CrossAxisAlignment.end,
// children: [
// SizedBox(
// height: 36,
// child: TextField(
// controller: data.loginEmailController,
// autofocus: false,
// decoration: InputDecorations.basic(
// prefixIcon: Icon(
// Icons.email_outlined,
// size: 18,
// color: ThemeConfig.mediumGrey,
// ),
// hint_text: "user@example.com"),
// ),
// ),
// ],
// ),
// ),
// #Password
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).password,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(
height: 36,
child: TextField(
textInputAction: TextInputAction.search,
controller: data.loginPasswordController,
autofocus: false,
obscureText: true,
enableSuggestions: false,
autocorrect: false,
decoration: InputDecorations.basic(
prefixIcon: Icon(
Icons.lock,
size: 18,
color: ThemeConfig.mediumGrey,
),
hint_text: "• • • • • • • •"),
),
),
Button(
minWidth: 50,
padding: EdgeInsets.zero,
child: Text(
AppLang.local(context).forgot_password_q_ucf,
style: TextStyle(
color: ThemeConfig.blue,
fontStyle: FontStyle.italic),
),
onPressed: (){
MakeRoute.go(context, PasswordForget());
},
)
],
),
),
// #login Button
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Container(
height: 45,
child: Button.minSize(
width: getWidth(context),
height: 50,
color: ThemeConfig.red,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6.0))),
child: Text(
AppLang.local(context).login,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
data.onPressedLogin();
}),
),
),
// #register route text
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
AppLang.local(context).not_a_member,
style:
TextStyle(color: ThemeConfig.fontColor, fontSize: 12),
)),
const SizedBox(
width: 10,
),
Button(
minWidth: 20,
child: Text(
AppLang.local(context).register_now_ucf,
style: TextStyle(
color: ThemeConfig.red,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return Registration();
}));
},
),
],
),
),
],
),
);
});
}
// Country country = Country(name:"Uzbekistan" , dial_code: "+998", code: "+998");
// AlertDialog buildFilterDialog(AuthPresenter data) {
// return AlertDialog(
// title: const Text('Search Country'),
// content: Container(
// height: 300,
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: <Widget>[
// TextField(
// onChanged: data.filterCountry,
// decoration: const InputDecoration(
// hintText: 'Search',
// ),
// ),
// const SizedBox(height: 16.0),
// Expanded(
// child: SingleChildScrollView(
// child: Consumer<AuthPresenter>(
// builder: (context, filterData, child) {
// return Column(
// children: List.generate(filterData.filteredCountry.length,
// (index) {
// country = filterData.filteredCountry[index];
// return ListTile(
// leading: Image.asset(
// getAssetFlag("${country.code.toLowerCase()}.png"),
// height: 30,
// width: 30,
// ),
// title: Text(country.name),
// onTap: () {
// data.onChangeCountry(country);
// Navigator.of(context).pop();
// filterData.filteredCountry = filterData.country;
// },
// );
// }),
// );
// }),
// ),
// ),
// ],
// ),
// ),
// );
// }
}

View File

@@ -0,0 +1,148 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/auth_ui.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/auth/auth_presenter.dart';
import 'package:grostore/screens/auth/password_otp.dart';
import 'package:provider/provider.dart';
import '../../custom_ui/Boxdecorations.dart';
class PasswordForget extends StatefulWidget {
const PasswordForget({super.key});
@override
_PasswordForgetState createState() => _PasswordForgetState();
}
class _PasswordForgetState extends State<PasswordForget> {
@override
Widget build(BuildContext context) {
return AuthScreen.buildScreen(context, buildBody(getWidth(context), context));
}
Widget buildBody(double screenWidth, BuildContext context) {
return Consumer<AuthPresenter>(builder: (context, data, child) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
width: screenWidth * (3 / 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getWidth(context),
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).forgot_password_ucf,
style: StyleConfig.fs24fwBold,
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).please_enter_phone,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(
height: 45,
child: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
decoration: BoxDecorations.basic(),
height: 36,
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 14.0),
child: Icon(
Icons.phone,
size: 18,
color: ThemeConfig.mediumGrey,
),
),
Text(
"+998",
style: StyleConfig.fs14fwNormal,
),
// Button(
// minWidth: 80,
// onPressed: () {
// showDialog(
// context: context,
// builder: (context) {
// return buildFilterDialog(data);
// });
// },
// child: Row(
// children: [
// Image.asset(
// "${getAssetFlag(data.regCountry.code.toLowerCase())}.png"),
//
// ],
// ),
// ),
Container(
padding: const EdgeInsets.only(left: 10),
width: getWidth(context) - 200,
child: TextField(
style: StyleConfig.fs14fwNormal,
decoration: const InputDecoration.collapsed(
hintText: "XX XXX XXX"),
controller: data.forgetPhoneNumberController,
),
)
],
)),
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: SizedBox(
height: 45,
child: Button.minSize(
width: getWidth(context),
height: 50,
color: ThemeConfig.red,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6.0))),
child: Text(
AppLang.local(context).send,
style:const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
data.onPressSendCode();
// MakeRoute.go(context, PasswordOtp(phone_num:data.loginPhoneNumberController.text,));
}),
),
),
],
),
);
});
}
}

View File

@@ -0,0 +1,189 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/auth_ui.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/auth/auth_presenter.dart';
import 'package:provider/provider.dart';
class PasswordOtp extends StatefulWidget {
PasswordOtp({super.key,this.verify_by = "phone",this.phone_num});
String? verify_by;
String? phone_num;
@override
_PasswordOtpState createState() => _PasswordOtpState();
}
class _PasswordOtpState extends State<PasswordOtp> {
@override
Widget build(BuildContext context) {
return AuthScreen.buildScreen(context, buildBody(context, getWidth(context)));
}
Widget buildBody(BuildContext context, double screenWidth) {
return Consumer<AuthPresenter>(builder: (context, data, child) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
width: screenWidth * (3 / 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: getWidth(context),
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).otp_all_cap,
style: StyleConfig.fs24fwBold,
textAlign: TextAlign.center,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).otp_all_cap,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(
height: 36,
child: TextField(
controller: data.otpCodeController,
autofocus: false,
decoration: InputDecorations.basic(
prefixIcon: Icon(
Icons.pin,
size: 18,
color: ThemeConfig.fontColor,
),
hint_text: "XXX XXX"),
),
),
],
),
),
// Padding(
// padding: const EdgeInsets.only(bottom: 4.0),
// child: Text(
// AppLang.local(context).new_password_ucf,
// style: TextStyle(
// color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
// ),
// ),
// Padding(
// padding: const EdgeInsets.only(bottom: 8.0),
// child: Container(
// height: 36,
// child: TextField(
// controller: data.otpPasswordController,
// autofocus: false,
// obscureText: true,
// enableSuggestions: false,
// autocorrect: false,
// decoration: InputDecorations.basic(
// prefixIcon: Icon(
// Icons.lock,
// size: 18,
// color: ThemeConfig.fontColor,
// ),
// hint_text: "• • • • • • • •"),
// ),
// ),
// ),
// Padding(
// padding: const EdgeInsets.only(bottom: 4.0),
// child: Text(
// AppLang.local(context).confirm_password_ucf,
// style: TextStyle(
// color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
// ),
// ),
// Padding(
// padding: const EdgeInsets.only(bottom: 8.0),
// child: Container(
// height: 36,
// child: TextField(
// controller: data.otpPasswordConfirmController,
// autofocus: false,
// obscureText: true,
// enableSuggestions: false,
// autocorrect: false,
// decoration: InputDecorations.basic(
// prefixIcon: Icon(
// Icons.lock,
// size: 18,
// color: ThemeConfig.fontColor,
// ),
// hint_text: "• • • • • • • •"),
// ),
// ),
// ),
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: SizedBox(
height: 45,
child: Button.minSize(
width: getWidth(context),
height: 50,
color: ThemeConfig.red,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6.0))),
child: Text(
AppLang.local(context).send,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
data.onPressOTP();
}),
),
),
// Padding(
// padding: const EdgeInsets.only(top: 20.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.center,
// children: [
// Button(
// minWidth: 20,
// child: Text(
// AppLang.local(context).resend_otp_all_cap,
// style: TextStyle(
// color: ThemeConfig.accentColor,
// fontSize: 14,
// fontWeight: FontWeight.w600),
// ),
// onPressed: () {
// // Navigator.push(context,
// // MaterialPageRoute(builder: (context) {
// // return Registration();
// // }));
// },
// ),
// ],
// ),
// ),
],
),
);
});
}
}

View File

@@ -0,0 +1,347 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/constant/country_code.dart';
import 'package:grostore/constant/country_search.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/auth/auth_presenter.dart';
import 'package:grostore/screens/auth/login.dart';
import 'package:intl_phone_number_input/intl_phone_number_input.dart';
import 'package:provider/provider.dart';
import '../../custom_ui/auth_ui.dart';
class Registration extends StatefulWidget {
@override
_RegistrationState createState() => _RegistrationState();
}
class _RegistrationState extends State<Registration> {
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
Provider.of<AuthPresenter>(context).setContext(context);
return AuthScreen.buildScreen(
context, buildBody(context, getWidth(context)));
}
Widget buildBody(BuildContext context, double screenWidth) {
return Consumer<AuthPresenter>(builder: (context, data, child) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
width: screenWidth * (3 / 4),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// #Create New Account
Container(
width: getWidth(context),
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).create_new_account_ucf,
style: StyleConfig.fs24fwBold,
textAlign: TextAlign.center,
),
),
/// #Name
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).name,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
height: 36,
child: TextField(
controller: data.regNameController,
autofocus: false,
// decoration:InputDecoration(
// focusedBorder: OutlineInputBorder(
// borderRadius: BorderRadius.all(Radius.circular(5)),
// borderSide: BorderSide(
// color: ThemeConfig.red
// )
// )
// )
decoration: InputDecorations.basic(
prefixIcon: Icon(
Icons.person_outline,
size: 18,
color: ThemeConfig.mediumGrey,
),
hint_text: "Mr.John"),
),
),
),
/// #Phone Number
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).phone,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
decoration: BoxDecorations.basic(),
height: 36,
child: Row(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 14.0),
child: Icon(
Icons.phone,
size: 18,
color: ThemeConfig.mediumGrey,
),
),
// Button(
// minWidth: 80,
// onPressed: () {
// showDialog(
// context: context,
// builder: (context) {
// return buildFilterDialog(data);
// });
// },
// child: Row(
// children: [
// Padding(
// padding: const EdgeInsets.all(8.0),
// child: Image.asset(
// "${getAssetFlag(data.regCountry.code.toLowerCase())}.png"),
// ),
// Text(
// data.regCountry.dial_code,
// style: StyleConfig.fs14fwNormal,
// )
// ],
// ),
// ),
Text(
"+998",
style: StyleConfig.fs14fwNormal,
),
Container(
padding: const EdgeInsets.only(left: 10),
width: getWidth(context) - 200,
child: TextField(
style: StyleConfig.fs14fwNormal,
decoration: const InputDecoration.collapsed(
hintText: "XX XXX XXX"),
controller: data.regPhoneNumberController,
),
)
],
)),
),
/// #Password
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).password,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
height: 36,
child: TextField(
controller: data.regPasswordController,
autofocus: false,
obscureText: true,
enableSuggestions: false,
autocorrect: false,
decoration: InputDecorations.basic(
prefixIcon: Icon(
Icons.lock,
size: 18,
color: ThemeConfig.mediumGrey,
),
hint_text: "• • • • • • • •"),
),
),
Text(
AppLang.local(context).password_must_be_at_last_6_digit,
style: TextStyle(
color: ThemeConfig.lightGrey,
fontStyle: FontStyle.italic),
)
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).confirm_password_ucf,
style: TextStyle(
color: ThemeConfig.fontColor, fontWeight: FontWeight.w600),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
height: 36,
child: TextField(
controller: data.regPasswordConfirmController,
autofocus: false,
obscureText: true,
enableSuggestions: false,
autocorrect: false,
decoration: InputDecorations.basic(
prefixIcon: Icon(
Icons.lock,
size: 18,
color: ThemeConfig.mediumGrey,
),
hint_text: "• • • • • • • •"),
),
),
),
/// #Send button
Padding(
padding: const EdgeInsets.only(top: 30.0),
child: Container(
height: 45,
child: Button.minSize(
width: getWidth(context),
height: 50,
color: ThemeConfig.red,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6.0))),
child: Text(
AppLang.local(context).sign_up_ucf,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
data.onPressSignUp();
}),
),
),
/// #Text
Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: Text(
AppLang.local(context).already_have_an_account,
style:
TextStyle(color: ThemeConfig.fontColor, fontSize: 12),
)),
const SizedBox(
width: 10,
),
/// #login route text
Button(
minWidth: 20,
child: Text(
AppLang.local(context).login,
style: TextStyle(
color: ThemeConfig.red,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) {
return const Login();
}));
},
),
],
),
),
],
),
);
});
}
// Country country = Country(name:"Uzbekistan" , dial_code: "+998", code: "+998");
// AlertDialog buildFilterDialog(AuthPresenter data) {
// return AlertDialog(
// title: const Text('Search Country'),
// content: Container(
// height: 300,
// child: Column(
// mainAxisSize: MainAxisSize.min,
// children: <Widget>[
// TextField(
// onChanged: data.filterCountry,
// decoration: const InputDecoration(
// hintText: 'Search',
// ),
// ),
// const SizedBox(height: 16.0),
// Expanded(
// child: SingleChildScrollView(
// child: Consumer<AuthPresenter>(
// builder: (context, filterData, child) {
// return Column(
// children: List.generate(filterData.filteredCountry.length,
// (index) {
// country = filterData.filteredCountry[index];
// return ListTile(
// leading: Image.asset(
// getAssetFlag("${country.code.toLowerCase()}.png"),
// height: 30,
// width: 30,
// ),
// title: Text(country.name),
// onTap: () {
// // data.onChangeCountry(country);
// Navigator.of(context).pop();
// filterData.filteredCountry = filterData.country;
// },
// );
// }),
// );
// }),
// ),
// ),
// ],
// ),
// ),
// );
// }
}

View File

@@ -0,0 +1,316 @@
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/Image_view.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/cart_presenter.dart';
import 'package:grostore/screens/check_out.dart';
import 'package:provider/provider.dart';
import '../helpers/common_functions.dart';
class Cart extends StatefulWidget {
const Cart({Key? key}) : super(key: key);
@override
State<Cart> createState() => _CartState();
}
class _CartState extends State<Cart> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).cart, context: context),
body: SizedBox(
height: getHeight(context),
width: getWidth(context),
child: Stack(
children: [
Container(
child: Consumer<CartPresenter>(
builder: (context, data, child) {
if(data.isCartResponseFetch && data.cartResponse.carts.isNotEmpty) {
return ListView.separated(
padding: const EdgeInsets.only(top: 16, bottom: 200),
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.only(
left: StyleConfig.padding,
right: StyleConfig.padding,
bottom:
index == data.cartResponse.carts.length - 1
? 80
: 0),
decoration: BoxDecorations.shadow(),
width: getWidth(context),
child: Row(
children: [
Expanded(
child: ImageView(
url: data.cartResponse.carts[index].thumbnailImage,
width: 120,
height: 100,
),
),
const SizedBox(
width: 8
),
Expanded(
flex:2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.cartResponse.carts[index].category,
style: StyleConfig.fs10,
maxLines: 1,
),
Text(
data.cartResponse.carts[index].name,
style: StyleConfig.fs14fwBold,
maxLines: 1,
),
Row(
children: [
Text(
data.cartResponse.carts[index].unit,
style: StyleConfig.fs12,
maxLines: 1,
),
Text(
"Narx: ",
style: StyleConfig.fs12,
maxLines: 1,
),
Text(
showPrice(data.cartResponse.carts[index].price),
style: StyleConfig.fs12,
maxLines: 1,
),
],
),
],
),
),
quantitySection(context, data, index),
],
),
);
},
separatorBuilder: (context, index) {
print(index);
return Padding(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding),
child: Divider(
height: 1,
color: ThemeConfig.grey,
),
);
},
itemCount: data.cartResponse.carts.length);
} else {
return Center(child: Text(AppLang.local(context).empty,style: StyleConfig.fs16fwBold,));
}
},
),
),
Consumer<CartPresenter>(builder: (context, data, child) {
return data.cartResponse.carts.isNotEmpty
? Positioned(
bottom: 0,
left: 0,
right: 0,
child: Column(
children: [
Container(
height: 200,
width: 400,
decoration: BoxDecorations.customRadius(
radius: const BorderRadius.only(
topLeft: Radius.circular(24),
topRight: Radius.circular(24)))
.copyWith(color: ThemeConfig.white),
child: Column(
children: [
const SizedBox(
height: 16,
),
Text(
AppLang.local(context).order_info_ucf,
style: StyleConfig.fs16fwBold,
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding,
vertical: 5),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).subtotal}:",
style: StyleConfig.fs14fwNormal,
),
Text(
"${showPrice(data.cartResponse.subTotal)}",
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding,
vertical: 5),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).coupon_discount_ucf}:",
style: StyleConfig.fs14fwNormal,
),
Text(
"${showPrice(data.cartResponse.couponDiscount)}",
style: StyleConfig.fs14fwNormal,
),
],
),
),
/// Dotted line
Padding(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding,
vertical: 5),
child: DottedLine(
direction: Axis.horizontal,
lineLength: double.infinity,
lineThickness: 1.0,
dashLength: 4.0,
dashColor: ThemeConfig.grey,
//dashGradient: [Colors.red, Colors.blue],
dashRadius: 0.0,
dashGapLength: 4.0,
dashGapColor: Colors.transparent,
//dashGapGradient: [Colors.red, Colors.blue],
dashGapRadius: 0.0,
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding,
vertical: 5),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).total}:",
style: StyleConfig.fs14fwNormal,
),
Text(
"${showPrice(data.cartResponse.total)}",
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding),
child: Button(
shape: StyleConfig.buttonRadius(4),
color: ThemeConfig.red,
onPressed: () {
MakeRoute.go(context, const CheckOut());
},
padding: const EdgeInsets.symmetric(vertical: 16),
minWidth: getWidth(context),
child: Text(
AppLang.local(context)
.review_n_payment_ucf,
style: StyleConfig.fs16cWhitefwBold,
),
),
)
],
),
),
],
))
: const SizedBox.shrink();
})
],
),
),
);
}
Container quantitySection(BuildContext context, CartPresenter data, index) {
return Container(
// padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
//height: 50,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Button(
minWidth: 20,
shape: const CircleBorder(),
color: ThemeConfig.fontColor,
padding: const EdgeInsets.all(8),
onPressed: () {
data.updateCart(
cartId: data.cartResponse.carts[index].id,
action: "decrease",
context: context);
},
child: const Icon(
Icons.remove,
color: ThemeConfig.white,
size: 10,
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 2),
constraints: const BoxConstraints(minWidth: 40),
alignment: Alignment.center,
child: Text(
"${data.cartResponse.carts[index].quantity}",
style: StyleConfig.fs14fwBold,
)),
Button(
minWidth: 20,
shape: const CircleBorder(),
color: ThemeConfig.red,
padding: const EdgeInsets.all(8),
onPressed: () {
data.updateCart(
cartId: data.cartResponse.carts[index].id,
action: "increase",
context: context);
},
child: const Icon(
Icons.add,
color: ThemeConfig.white,
size: 10,
),
),
],
),
);
}
}

View File

@@ -0,0 +1,80 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/category_ui.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/categories_presenter.dart';
import 'package:grostore/screens/filter.dart';
import 'package:provider/provider.dart';
class Categories extends StatefulWidget {
Categories({Key? key, this.fromBottomBar = true}) : super(key: key);
bool fromBottomBar;
@override
State<Categories> createState() => _CategoriesState();
}
class _CategoriesState extends State<Categories> {
@override
void initState() {
Provider.of<CategoriesPresenter>(context, listen: false)
.setContext(context);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<CategoriesPresenter>(context, listen: false).initState();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).categories,
context: context,
showBackButton: !widget.fromBottomBar),
body: Consumer<CategoriesPresenter>(builder: (context, data, child) {
return RefreshIndicator(
onRefresh: data.onRefresh,
child: data.isCategoryInit
? GridView.builder(
controller: data.scrollController,
padding: EdgeInsets.only(
left: 10,
right: 10,
top: 10,
bottom: widget.fromBottomBar ? 80 : 10),
itemCount: data.categories.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 1),
itemBuilder: (context, index) => Button(
minWidth: getWidth(context),
padding: EdgeInsets.zero,
onPressed: () {
MakeRoute.go(
context,
Filter(
category_id:
data.categories[index].id.toString(),
));
},
child: CategoryUi(
img: data.categories[index].thumbnailImage,
name: data.categories[index].name),
))
: Shimmers.gridShimmer(3, 15));
}),
);
}
}

View File

@@ -0,0 +1,912 @@
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/Image_view.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
// import 'package:grostore/custom_ui/loading.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/models/payment_types_response.dart';
import 'package:grostore/models/time_slote_response.dart';
import 'package:grostore/presenters/check_out_presenter.dart';
import 'package:grostore/screens/address/addresses.dart';
// import 'package:grostore/presenters/user_presenter.dart';
// import 'package:grostore/screens/main.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';
class CheckOut extends StatefulWidget {
const CheckOut({Key? key}) : super(key: key);
@override
State<CheckOut> createState() => _CheckOutState();
}
class _CheckOutState extends State<CheckOut> {
bool pay = false;
String dostavka = '';
@override
void initState() {
Provider.of<CheckOutPresenter>(context, listen: false)
.init(context);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).check_out_ucf, context: context),
body: SingleChildScrollView(
child: Consumer<CheckOutPresenter>(builder: (context, data, child) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 24),
/// #build shipping address
buildShippingAddress(context, data),
const SizedBox(height: 24),
/// #Billing address
// buildBillingAddress(context, data),
// const SizedBox(
// height: 24
// ),
/// #Build Logistics
if (data.logistics.isNotEmpty)
buildLogistic(context, data)
else
Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: const EdgeInsets.all(8),
decoration: BoxDecorations.shadow(radius: 8).copyWith(color: ThemeConfig.red),
child: Text(AppLang.local(context).we_are_not_shipping_to_your_city_now,style: StyleConfig.fs14cWhitefwNormal,)),
const SizedBox(height: 24),
/// #Prefer Delivery time text
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).preferred_delivery_time,
style: StyleConfig.fs16fwBold,
),
),
/// #Prefer Delivery time
data.isFetchTimeSlot?buildDeliveryTime(context, data):timeSlotShimmer(),
const SizedBox(height: 24),
/// #Personal info
buildPersonalInfo(context,data),
const SizedBox(height: 24),
/// #Payment Method text
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).payment_method,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(height: 10),
/// #Payment Method Button
Container(
height: 100,
decoration: BoxDecorations.shadow(radius: 8),
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding,vertical: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
pay = !pay;
data.peyMethod("Karta");
},
child: Container(
height: MediaQuery.sizeOf(context).height,
width: MediaQuery.sizeOf(context).width,
padding: EdgeInsets.all(5),
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1.5,
color:pay ?ThemeConfig.red:ThemeConfig.xxlightGrey
)
),
child: Column(
children: [
Icon(Icons.add_card,color:pay?ThemeConfig.red :ThemeConfig.xlightGrey),
Text(AppLang.local(context).when_receiving_by_card,style:pay? StyleConfig.fs12Red :StyleConfig.fs12cGrey,textAlign: TextAlign.center,),
],
),
),
),
),
),
const SizedBox(width: 20),
Expanded(
child: Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
pay = !pay;
data.peyMethod("Naqd pul");
},
child: Container(
height: MediaQuery.sizeOf(context).height,
width: MediaQuery.sizeOf(context).width,
alignment: Alignment.center,
padding: EdgeInsets.all(5),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1.5,
color:pay?ThemeConfig.xxlightGrey :ThemeConfig.red
)
),
child: Column(
children: [
Icon(Icons.payments_outlined,color:pay ?ThemeConfig.xxlightGrey :ThemeConfig.red,),
Text(AppLang.local(context).when_receiving_by_cash,style:pay? StyleConfig.fs12cGrey:StyleConfig.fs12Red ,textAlign: TextAlign.center,),
],
),
),
),
),
),
],
),
),
const SizedBox(height: 24),
/// #Tips title
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).add_tips_for_deliveryman,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 10
),
/// #tips
Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
decoration: BoxDecorations.shadow(radius: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLang.local(context).tips,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
TextField(
controller: data.tipsTxt,
keyboardType: TextInputType.phone,
decoration: InputDecorations.phone(hint_text: AppLang.local(context).tips),
),
],
),
),
const SizedBox(height: 24),
/// #Order Summary
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).order_summary,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 10,
),
Container(
width: getWidth(context),
decoration: BoxDecorations.shadow(radius: 8),
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding14,
vertical: StyleConfig.padding14),
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).subtotal} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice(data.orderSummeryResponse.subTotal),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).delivery_fee_ucf} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice("${data.orderSummeryResponse.shippingCharge}"),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).tax} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice(data.orderSummeryResponse.tax),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 10,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).coupon_discount_ucf} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice(data.orderSummeryResponse.couponDiscount),
style: StyleConfig.fs14fwNormal,
),
],
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 8.0),
child: DottedLine(
direction: Axis.horizontal,
lineLength: double.infinity,
lineThickness: 1.0,
dashLength: 4.0,
dashColor: ThemeConfig.grey,
//dashGradient: [Colors.red, Colors.blue],
dashRadius: 0.0,
dashGapLength: 4.0,
dashGapColor: Colors.transparent,
//dashGapGradient: [Colors.red, Colors.blue],
dashGapRadius: 0.0,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${AppLang.local(context).total} :",
style: StyleConfig.fs14fwNormal,
),
Text(
showPrice("${data.orderSummeryResponse.total} so'm} "),
style: StyleConfig.fs14fwNormal,
),
],
),
],
),
),
const SizedBox( height: 24 ),
/// #Order contract button
Button(
minWidth: getWidth(context),
color: ThemeConfig.red,
onPressed: (){
data.placeOrder(context);
},
padding: const EdgeInsets.symmetric(vertical: 20),
child: Text(
AppLang.local(context).place_order,
// "Place Order",
style: StyleConfig.fs16cWhitefwBold,
),
)
],
);
}),
),
);
}
// int subster(String text){
// final a = text.substring(0,6);
// final b = a.split(",");
// final c = "${b[0]}${b[1]}";
// print("-----------");
// print("heloH :: $c ::");
// print("-----------");
// final e = int.parse(c);
// return e;
// }
/// #tieslot timer
Widget timeSlotShimmer(){
return Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding,vertical: 5),
child: Column(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8),
child: Shimmers(
height: 40,
width: getWidth(context),
),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8),
child: Shimmers(
height: 40,
width: getWidth(context),
),
)
],
),
);
}
/// #Delivery Time
Column buildDeliveryTime(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 10,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Button(
minWidth: getWidth(context),
onPressed: () {
data.onChangeDeliveryType("regular");
},
child:Container(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: data.shipping_delivery_type == "regular"
? Border.all(color: ThemeConfig.red, width: 2)
: null),
child: Row(
children: [
Icon(
Icons.local_shipping_outlined,
size: 45,
color: ThemeConfig.grey,
),
const SizedBox(
width: 10,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
AppLang.local(context).reg_delivery,
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: 200,
child: Text(
AppLang.local(context).we_will_deliver_your_products_soon,
style: StyleConfig.fs14fwNormal,
overflow: TextOverflow.ellipsis,
),
),
],
),
],
),
)
,
),
),
Button(
minWidth: getWidth(context),
onPressed: () {
data.onChangeDeliveryType("scheduled");
setState(() {});
},
child: Container(
margin: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20),
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: data.shipping_delivery_type == "scheduled"
? Border.all(color: ThemeConfig.red, width: 2)
: null),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: getWidth(context) * 0.35,
child: Button(
minWidth: getWidth(context) * 0.35,
alignment: Alignment.centerLeft,
child: Text(
DateFormat("d MMM").format(data.selectedDate!),
style: StyleConfig.fs14fwNormal,
),
onPressed: () async {
DateTime date = await chooseDate(data);
data.onChangeDate(date);
data.onChangeDeliveryType("scheduled");
setState(() { });
},
),
),
SizedBox(
width: getWidth(context) * 0.35,
child: Button(
minWidth: getWidth(context),
child: SizedBox(
width: getWidth(context) * 0.35,
child: buildTimeDropDown(data),
),
),
),
],
),
),
),
],
);
}
/// #Date Picker
chooseDate(CheckOutPresenter data) async {
return await showDatePicker(
initialEntryMode: DatePickerEntryMode.calendar,
initialDate: data.selectedDate!,
firstDate: data.firstDate,
lastDate: data.lastDate,
context: context,
);
}
/// #Personal information
Column buildPersonalInfo(BuildContext context,CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).personal_information,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 10,
),
Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
decoration: BoxDecorations.shadow(radius: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLang.local(context).phone,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
TextField(
controller:data.phoneTxt ,
keyboardType: TextInputType.phone,
decoration: InputDecorations.phone(hint_text: "Phone"),
),
const SizedBox(
height: 10,
),
Text(
AppLang.local(context).alternative_phone_ucf,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
TextField(
controller: data.additionalPhoneTxt,
keyboardType: TextInputType.phone,
decoration: InputDecorations.phone(
hint_text: AppLang.local(context).alternative_phone_ucf),
),
const SizedBox(
height: 10,
),
Text(
AppLang.local(context).additional_info_ucf,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 10,
),
Container(
padding: const EdgeInsets.all(8),
constraints: const BoxConstraints(minHeight: 80),
width: getWidth(context),
decoration: BoxDecorations.basic().copyWith(
border: Border.all(color: ThemeConfig.grey, width: 1)),
child: TextField(
controller: data.additionalInfoTxt,
decoration: InputDecoration.collapsed(
hintText: AppLang.local(context).additional_info_ucf),
),
)
],
),
),
],
);
}
/// #build shipping address
Column buildShippingAddress(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
AppLang.local(context).delivery_address_ucf,
style: StyleConfig.fs16fwBold,
),
Material(
clipBehavior: Clip.antiAlias,
borderRadius: const BorderRadius.all(Radius.circular(10)),
child: InkWell(
onTap: (){
MakeRoute.go(context, const Addresses());
},
child: Container(
alignment: Alignment.center,
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10)),
border: Border.all(
width: 1,
color: ThemeConfig.red,
)
),
child: const Text("Manzil qo'shish"),
),
),
)
],
),
),
SizedBox(
//color: Colors.red,
height: 150,
width: getWidth(context),
child: data.isFetchDeliveryAddress?ListView.separated(
itemCount: data.addresses.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(
width: 2,
color:
data.selectedShippingAddress.id == data.addresses[index].id
? ThemeConfig.red
: ThemeConfig.grey)),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
shape: StyleConfig.buttonRadius(8),
minWidth: getWidth(context) * 0.5,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.addresses[index].countryName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].stateName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].cityName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].address,
style: StyleConfig.fs14fwNormal,
maxLines: 1,
),
],
),
onPressed: () {
data.onChangeShippingAddress(data.addresses[index]);
},
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
):Shimmers.horizontalList(10, getWidth(context) * 0.5, 100),
)
],
);
}
/// #Build billing address
Column buildBillingAddress(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).billing_address_ucf,
style: StyleConfig.fs16fwBold,
),
),
SizedBox(
//color: Colors.red,
height: 150,
width: getWidth(context),
child: data.isFetchDeliveryAddress?ListView.separated(
itemCount: data.addresses.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(
width: 2,
color: data.billingAddressId == data.addresses[index].id
? ThemeConfig.red
: ThemeConfig.grey)),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
shape: StyleConfig.buttonRadius(8),
minWidth: getWidth(context) * 0.5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
data.addresses[index].countryName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].stateName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].cityName,
style: StyleConfig.fs14fwNormal,
),
Text(
data.addresses[index].address,
style: StyleConfig.fs14fwNormal,
),
],
),
onPressed: () {
data.onChangeBillingAddress(data.addresses[index].id);
},
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
):Shimmers.horizontalList(10, getWidth(context) * 0.5, 100),
),
],
);
}
/// #Build logistics
Column buildLogistic(BuildContext context, CheckOutPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).available_logistics_ucf,
style: StyleConfig.fs16fwBold,
),
),
SizedBox(
//color: Colors.red,
height: 150,
width: getWidth(context),
child:ListView.separated(
itemCount: data.logistics.length,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecorations.shadow(radius: 8).copyWith(
border: Border.all(
width: 2,
color:
data.selectedLogistic.id == data.logistics[index].id
? ThemeConfig.red
: ThemeConfig.grey)),
child: Button(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
shape: StyleConfig.buttonRadius(8),
minWidth: getWidth(context) * 0.5,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
data.logistics[index].name,
style: StyleConfig.fs14fwNormal,
),
ImageView(
url: data.logistics[index].image,
height: 40,
width: getWidth(context) * 0.4,
),
Text(
showPrice(data.logistics[index].price),
style: StyleConfig.fs12,
),
],
),
onPressed: () {
data.onChangeLogistic(data.logistics[index]);
},
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
),
),
],
);
}
/// #Build time dropdown
Widget buildTimeDropDown(CheckOutPresenter data) {
return DropdownButton<TimeSlot>(
menuMaxHeight: 300,
isDense: true,
underline: Container(),
isExpanded: true,
onChanged: (TimeSlot? value) {
data.onChangeTimeSlot(value!);
},
icon: const Icon(Icons.arrow_drop_down),
value: data.selectedTimeslot,
items: data.timeSlots
.map(
(value) => DropdownMenuItem<TimeSlot>(
value: value,
child: Text(
value.timeline,
),
),
)
.toList(),
);
}
/// #Payment Method
Future<PaymentTypesResponse?> showPaymentMethods(CheckOutPresenter data)async{
return showDialog<PaymentTypesResponse>(context: context, builder: (context){
return AlertDialog(
titlePadding: EdgeInsets.zero,
title: Container(
alignment: Alignment.center,
color: ThemeConfig.accentColor,
padding: const EdgeInsets.symmetric(horizontal: 14,vertical: 24),
child: Text("Choose Payment Method",style: StyleConfig.fs16cWhitefwBold,),
),
content:Column(
children: List.generate(data.paymentTypes.length, (index) {
return Column(
children: [
Button(
minWidth: getWidth(context),
onPressed: (){
Navigator.pop(context,data.paymentTypes[index]);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
width: getWidth(context)*0.3,
child: Text(data.paymentTypes[index].name,style: StyleConfig.fs14fwBold,)),
Container(
width: getWidth(context)*0.3,
padding: const EdgeInsets.all(8),
child: ImageView.svg(url: data.paymentTypes[index].image,height:50,width: 50),
),
],
))
],
);
}),
) ,
actions: [
Button(
minWidth:getWidth(context),
padding: const EdgeInsets.symmetric(vertical: 20),
color: ThemeConfig.red,
onPressed: (){
Navigator.pop(context);
},
child: Text("Close",style: StyleConfig.fs14cWhitefwNormal,),
)
],
);
});
}
}

View File

@@ -0,0 +1,229 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_countdown_timer/countdown.dart';
import 'package:flutter_countdown_timer/current_remaining_time.dart';
import 'package:flutter_countdown_timer/flutter_countdown_timer.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/custom_ui/toast_ui.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/coupon_presenter.dart';
import 'package:provider/provider.dart';
class Coupons extends StatefulWidget {
const Coupons({Key? key}) : super(key: key);
@override
State<Coupons> createState() => _CouponsState();
}
class _CouponsState extends State<Coupons> {
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<CouponPresenter>(context, listen: false).initState();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar.show(
title: AppLang.local(context).coupons, context: context),
body: Consumer<CouponPresenter>(builder: (context, data, child) {
print(data.isCouponsInit);
if (!data.isCouponsInit) {
return Container(
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child:
Shimmers.list(10, getWidth(context) - StyleConfig.padding, 150),
);
}
return ListView.separated(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
itemBuilder: (context, index) {
return Container(
height: getWidth(context) * 0.5,
width: getWidth(context),
decoration:
BoxDecorations.image(url: data.coupons[index].banner),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text("UP to ${data.coupons[index].discountValue.toString()}${data.coupons[index].discountType== 'percent'?'%':''} OFF",style: StyleConfig.fs24fwBold.copyWith(color: Colors.red,),),
),
SizedBox(height: 14,),
Container(
height: 40,
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
decoration: BoxDecoration(
// border: Border.all(),
borderRadius: BorderRadius.circular(8),
color: ThemeConfig.white
),
child: Row(
children: [
Padding(
padding: const EdgeInsets.only(left:8 ,right: 8.0),
child: Text(data.coupons[index].code,style: StyleConfig.fs16fwBold,),
),
Spacer(),
Button(
padding: EdgeInsets.symmetric(horizontal: 10),
color: ThemeConfig.accentColor,
minHeight: 40.0,
minWidth: 10,
shape: StyleConfig.buttonRadius(8),
onPressed: ()async{
await Clipboard.setData(ClipboardData(text:data.coupons[index].code));
ToastUi.show(context, "Copied");
},
child: Text(AppLang.local(context).copy_code_ucf,
style: StyleConfig.fs14cWhitefwNormal,
),
)
],
),
),
SizedBox(height: 14,),
buildCounterRow(data, index)
],
),
);
},
separatorBuilder: (context, index) => SizedBox(
height: StyleConfig.smSectionSpacer,
),
itemCount: data.coupons.length);
}),
);
}
Row buildCounterRow(CouponPresenter data, int index) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
CountdownTimer(
controller: data.controller[index],
widgetBuilder: (context, timer) {
return buildCounterContainer(TimerType.day, timer);
},
),
CountdownTimer(
controller: data.controller[index],
widgetBuilder: (context, timer) {
return buildCounterContainer(TimerType.hours, timer);
},
),
CountdownTimer(
controller: data.controller[index],
widgetBuilder: (context, timer) {
return buildCounterContainer(TimerType.min, timer);
},
),
CountdownTimer(
controller: data.controller[index],
widgetBuilder: (context, timer) {
return buildCounterContainer(TimerType.sec, timer);
},
),
],
);
}
Container buildCounterContainer(TimerType timerType, CurrentRemainingTime? timer) {
return Container(
width: getWidth(context) / 6,
height: getWidth(context) / 6,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
border: Border.all(color: ThemeConfig.amber, width: 1),
color: ThemeConfig.white),
child:makeCounter(timerType, timer)
);
}
makeCounter(TimerType timerType, CurrentRemainingTime? timer){
if(timerType==TimerType.day){
return buildCounterDate(timer, context);
}else if(timerType ==TimerType.hours){
return buildCounterHours(timer, context);
}else if(timerType ==TimerType.min){
return buildCounterMin(timer, context);
}else {
return buildCounterSec(timer, context);
}
}
Column buildCounterDate(CurrentRemainingTime? timer, BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
timer?.days.toString() ?? "",
style: StyleConfig.fs14fwNormal,
),
Text(
AppLang.local(context).days,
style: StyleConfig.fs14fwNormal,
),
],
);
}
Column buildCounterHours(CurrentRemainingTime? timer, BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
timer?.hours.toString() ?? "",
style: StyleConfig.fs14fwNormal,
),
Text(
AppLang.local(context).hours,
style: StyleConfig.fs14fwNormal,
),
],
);
}
Column buildCounterMin(CurrentRemainingTime? timer, BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
timer?.min.toString() ?? "",
style: StyleConfig.fs14fwNormal,
),
Text(
AppLang.local(context).min,
style: StyleConfig.fs14fwNormal,
),
],
);
}
Column buildCounterSec(CurrentRemainingTime? timer, BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
timer?.sec.toString() ?? "",
style: StyleConfig.fs14fwNormal,
),
Text(
AppLang.local(context).sec,
style: StyleConfig.fs14fwNormal,
),
],
);
}
}
enum TimerType{
day,hours,min,sec
}

View File

@@ -0,0 +1,475 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/category_ui.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/product_card.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/cart_presenter.dart';
import 'package:grostore/presenters/categories_presenter.dart';
import 'package:grostore/presenters/filter_presenter.dart';
import 'package:grostore/screens/auth/login.dart';
import 'package:grostore/screens/cart.dart';
import 'package:provider/provider.dart';
class Filter extends StatefulWidget {
String? searchKey,
sort_by,
max_price,
min_price,
category_id,
tag_id,
per_page;
bool isFocus;
Filter(
{Key? key,
this.searchKey,
this.sort_by,
this.max_price,
this.min_price,
this.category_id,
this.tag_id,
this.per_page,
this.isFocus=false})
: super(key: key);
@override
State<Filter> createState() => _FilterState();
}
class _FilterState extends State<Filter> {
@override
void initState() {
super.initState();
Provider.of<FilterPresenter>(context,listen: false).setContext(context);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<FilterPresenter>(context,listen: false).clearAll();
if(!widget.isFocus) {
Provider.of<FilterPresenter>(context, listen: false).setInitData(
min_price: widget.min_price,
max_price: widget.max_price,
category_id: widget.category_id);
Provider.of<FilterPresenter>(context, listen: false).initState();
}
Provider.of<FilterPresenter>(context, listen: false).getCategories();
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).filter,
context: context,
bottom: buildSearchOptions(context)),
body: Consumer<FilterPresenter>(builder: (context, data, child) {
return RefreshIndicator(
onRefresh: data.onRefresh,
child:buildProductSection(data),
);
}),
/// #Bottom Navigation Bar
bottomNavigationBar:BottomAppBar(
color: ThemeConfig.white,
child: Consumer<CartPresenter>(
builder: (context, cart, child) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Your Cart: ${showPrice(cart.cartResponse.total)}",
style: StyleConfig.fs14fwNormal,
),
Button(
color: ThemeConfig.red,
padding: const EdgeInsets.symmetric(horizontal: 18,vertical: 8),
shape: StyleConfig.buttonRadius(5),
onPressed: () {
if (SystemData.isLogIn) {
MakeRoute.go(context, const Cart());
} else {
Navigator.push(
context, MaterialPageRoute(builder: (context) => const Login()));
return;
}
},
child: Text(AppLang.local(context).go_to_cart,style: StyleConfig.fs14cWhitefwNormal,))
],
);
},
),
) ,
/* bottomSheet:BottomSheet(
onClosing: (){}, builder: (context)=>Container(
height: 250,
width: getWidth(context),
color: Colors.red,
child: Consumer<FilterPresenter>(
builder: (context, data, child) {
return Column(
children: [
spacer(height: 10),
headerTitle(AppLang.local(context).categories),
spacer(height: StyleConfig.xsSectionSpacer),
buildCategorySection(data),
spacer(height: StyleConfig.smSectionSpacer),
headerTitle(AppLang.local(context).price_range_ucf),
RangeSlider(
onChanged: (nPrice) {
data.onChangePrice(nPrice);
print(nPrice);
},
//onChangeEnd: data.onChangePrice,
min: 0,
max: 500,
values: data.price,
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
children: [
Text(
data.price.start.round().toString(),
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: StyleConfig.xsSectionSpacer,
),
Text(
AppLang.local(context).to,
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: StyleConfig.xsSectionSpacer,
),
Text(
data.price.end.round().toString(),
style: StyleConfig.fs14fwNormal,
),
],
),
)
],
);
}
),
))
*/
/*bottomNavigationBar: Container(
color: ThemeConfig.white,
height: 280,
width: getWidth(context),
child: Consumer<FilterPresenter>(
builder: (context, data, child) {
return Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
spacer(height: 10),
headerTitle(AppLang.local(context).categories),
spacer(height: StyleConfig.xsSectionSpacer),
buildCategorySection(data),
spacer(height: StyleConfig.smSectionSpacer),
headerTitle(AppLang.local(context).price_range_ucf),
RangeSlider(
onChanged: (nPrice) {
data.onChangePrice(nPrice);
},
min: 0,
max: 500,
values: (data.price),
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
children: [
Text(
data.price.start.round().toString(),
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: StyleConfig.xsSectionSpacer,
),
Text(
AppLang.local(context).to,
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: StyleConfig.xsSectionSpacer,
),
Text(
data.price.end.round().toString(),
style: StyleConfig.fs14fwNormal,
),
],
),
),
Spacer(),
Button(
color: ThemeConfig.green,
minWidth: getWidth(context),
padding: EdgeInsets.symmetric(vertical: 14),
onPressed: (){
},
child: Text(AppLang.local(context).filter,style: StyleConfig.fs16cWhitefwBold,))
],
);
}
),
),*/
);
}
PreferredSize buildSearchOptions(BuildContext context) {
return PreferredSize(
preferredSize: Size(getWidth(context),50),
child: Consumer<FilterPresenter>(
builder: (context, data, child) {
return Container(
margin: EdgeInsets.symmetric(
horizontal: StyleConfig.padding14, vertical: 10),
width: getWidth(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
decoration: BoxDecoration(
border: Border.all(color: ThemeConfig.grey, width: 1),
borderRadius: BorderRadius.circular(8)),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.xsSectionSpacer, vertical: 10),
width: getWidth(context)-100,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: getWidth(context)-220,
child: TextField(
autofocus: widget.isFocus,
controller: data.searchTxt,
onEditingComplete: () {
data.clearCategory();
data.clearPriceRange();
data.getFilteredProducts();
},
decoration: const InputDecoration.collapsed(hintText: "Search"),
),
),
SizedBox(
height: 30,
width: 30,
child: Button(
padding: EdgeInsets.zero,
minWidth: 30,
onPressed: () {
data.clearCategory();
data.clearPriceRange();
data.getFilteredProducts();
},
child: Icon(Icons.search,size:24,color: ThemeConfig.fontColor,)),
)
],
),
),
SizedBox(
width: 60,
child: Button(
onPressed: (){
showFilterDialog();
},
shape: StyleConfig.buttonRadius(6),
color: ThemeConfig.red,
padding: const EdgeInsets.symmetric( vertical: 16,horizontal: 10),
minWidth: 40,
child: Text(AppLang.local(context).filter,style: StyleConfig.fs14cWhitefwNormal,)),
)
],
),
);
}
),
);
}
Widget buildCategorySection(FilterPresenter data) {
return SizedBox(
height: 87,
child: data.isCategoryInit
? ListView.separated(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
itemBuilder: (context, index) {
return SizedBox(
width: 100,
child: Button(
shape: StyleConfig.buttonRadius(0).copyWith(
side: BorderSide(
color: data.categories[index].id.toString() ==
data.selectedCategoryId.toString()
? ThemeConfig.accentColor
: ThemeConfig.noColor)),
padding: const EdgeInsets.all(5),
onPressed: () {
data.onSelectCategory(data.categories[index].id);
},
child: CategoryUi(
img: data.categories[index].thumbnailImage,
name: data.categories[index].name),
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 8,
);
},
itemCount: data.categories.length)
: Shimmers.horizontalList(8, 80, 80),
);
}
Widget headerTitle(text) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
text,
style: StyleConfig.fs16fwBold,
),
);
}
Widget spacer({height = 24}) {
return SizedBox(
height: double.parse(height.toString()),
);
}
Widget buildProductSection(FilterPresenter data){
return GridView.builder(
controller: data.scrollController,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding,vertical: StyleConfig.smSectionSpacer),
physics: const AlwaysScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.72
),
itemCount: data.products.length,
itemBuilder: (context, index) {
return ProductCard(
product: data.products[index],context: this.context,);
});
}
showFilterDialog(){
showDialog(context: context, builder: (context)=>Consumer<FilterPresenter>(
builder: (context,data,child) {
return AlertDialog(
title: Center(child: Text("Filter Form",style: StyleConfig.fs14fwBold,)),
content: Container(
height: getHeight(context)*0.30,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
headerTitle(AppLang.local(context).categories),
spacer(height: StyleConfig.xsSectionSpacer),
SizedBox(
width: getWidth(context),
child: buildCategorySection(data)),
spacer(height: StyleConfig.smSectionSpacer),
headerTitle(AppLang.local(context).price_range_ucf),
RangeSlider(
onChanged: (nPrice) {
data.onChangePrice(nPrice);
},
min: 0,
max: 500,
values: (data.price),
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
children: [
Text(
data.price.start.round().toString(),
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: StyleConfig.xsSectionSpacer,
),
Text(
AppLang.local(context).to,
style: StyleConfig.fs14fwNormal,
),
SizedBox(
width: StyleConfig.xsSectionSpacer,
),
Text(
data.price.end.round().toString(),
style: StyleConfig.fs14fwNormal,
),
],
),
),
],
),
),
actions: [
Button(
shape: StyleConfig.buttonRadius(6),
color: ThemeConfig.grey,
onPressed: (){
Navigator.pop(context);
},
child: Text(AppLang.local(context).close,style: StyleConfig.fs12cWhite,)),
Button(
shape: StyleConfig.buttonRadius(6),
color: ThemeConfig.green,
onPressed: (){
Navigator.pop(context);
data.clearKeyWord();
data.getFilteredProducts();
}
,
child: Text(AppLang.local(context).submit,style: StyleConfig.fs12cWhite))
],
);
}
));
}
Widget allProductShimmer() {
return GridView.builder(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 2/3),
itemCount: 10,
itemBuilder: (context, index) {
return Shimmers(width: 160, height: 186,radius: 8,);
});
}
}

View File

@@ -0,0 +1,100 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/help_center_presenter.dart';
import 'package:url_launcher/url_launcher.dart';
class HelpCenter extends StatefulWidget {
const HelpCenter({super.key});
@override
State<HelpCenter> createState() => _HelpCenterState();
}
class _HelpCenterState extends State<HelpCenter> {
HelpCenterPresenter helpCenterPresenter=HelpCenterPresenter();
@override
void initState() {
// TODO: implement initState
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
helpCenterPresenter.initState();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(title: AppLang.local(context).help_center_ucf, context: context),
body: Center(
child: ListenableBuilder(
listenable: helpCenterPresenter,
builder: (context,child) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 10),
margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
height: 200,
width: getWidth(context),
decoration: BoxDecorations.shadow(radius: 8),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.location_on_outlined),
SizedBox(
width: getWidth(context)*0.7,
child: Text(helpCenterPresenter.helpCenter?.location??""))
],
),
const SizedBox(height: 10,),
Button(
onPressed: (){
launchUrl(Uri(scheme: 'tel', path: helpCenterPresenter.helpCenter?.contactNumber??"123"));
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.phone),
SizedBox(
width: getWidth(context)*0.7,
child: Text(helpCenterPresenter.helpCenter?.contactNumber??""))
],
),
),
Button(
onPressed: (){
launchUrl(Uri(scheme: 'mailto', path: helpCenterPresenter.helpCenter?.email??""));
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.email_outlined),
SizedBox(
width: getWidth(context)*0.7,
child: Text(helpCenterPresenter.helpCenter?.email??""))
],
),
),
],
),
);
}
),
),
);
}
}

View File

@@ -0,0 +1,317 @@
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/category_ui.dart';
import 'package:grostore/custom_ui/product_card.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/home_presenter.dart';
import 'package:grostore/screens/filter.dart';
import 'package:provider/provider.dart';
class Home extends StatefulWidget {
String? id;
Home({Key? key, this.id}) : super(key: key);
@override
State<Home> createState() => _HomeState();
}
class _HomeState extends State<Home> {
@override
void initState() {
Provider.of<HomePresenter>(context,listen: false).setContext(context);
Provider.of<HomePresenter>(context, listen: false).initState(context);
super.initState();
}
// @override
// void dispose() {
// Provider.of<HomePresenter>(context, listen: false).dispose();
// super.dispose();
// }
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: buildSearchOption(context),
body: Consumer<HomePresenter>(builder: (context, data, child) {
return RefreshIndicator(
onRefresh: data.onRefresh,
child: SingleChildScrollView(
controller: data.homeScrollController,
child: SafeArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildSliderSection(data),
const SizedBox(
height: 14,
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
children: [
Text(
AppLang.local(context).top_categories_ucf,
style: StyleConfig.fs16fwBold,
),
const SizedBox(
width: 8,
),
Image.asset(
getAssetIcon("fire.png"),
height: 20,
width: 20,
)
],
),
),
const SizedBox(
height: 10,
),
buildTopCategorySection(data),
const SizedBox(
height: 14,
),
Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
children: [
Text(
AppLang.local(context).best_selling_products_ucf,
style: StyleConfig.fs16fwBold,
),
const SizedBox(
width: 8,
),
Image.asset(
getAssetIcon("fire.png"),
height: 20,
width: 20,
)
],
),
),
const SizedBox(
height: 10,
),
SizedBox(
// color: Colors.red,
height:225,
child: buildBestSellingProductSection(data)),
const SizedBox(height: 14,),
Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
children: [
Text(
AppLang.local(context).all_products_ucf,
style: StyleConfig.fs16fwBold,
),
const SizedBox(
width: 8,
),
Image.asset(
getAssetIcon("fire.png"),
height: 20,
width: 20,
)
],
),
),
const SizedBox(
height: 10,
),
allProducts(data),
const SizedBox(
height: 14,
),
],
),
),
),
);
}),
),
);
}
Container buildTopCategorySection(HomePresenter data) {
return Container(
height: 100,
child: data.isTopCategoryInitial
? ListView.separated(
scrollDirection: Axis.horizontal,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
itemBuilder: (context, index) {
return Button(
minWidth: 40,
onPressed: (){
MakeRoute.go(context, Filter(category_id:data.topCategoryList[index].id.toString() ,));
},
child: SizedBox(
width: 100,
child: CategoryUi(
img: data.topCategoryList[index].thumbnailImage,
name: data.topCategoryList[index].name),
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 8,
);
},
itemCount: data.topCategoryList.length)
: categoryShimmer(),
);
}
SizedBox buildSliderSection(HomePresenter data) {
return SizedBox(
height: 170,
child: CarouselSlider(
items:
data.isHomeBannerInitial ? data.homeBannerImages : sliderShimmer(),
options: CarouselOptions(
aspectRatio: 2,
viewportFraction: 0.94,
height: 150,
// enlargeCenterPage: true,
scrollDirection: Axis.horizontal,
autoPlay: true,
onPageChanged: (index, reason) {
data.onChangeBannerIndex(index);
},
),
),
);
}
PreferredSize buildSearchOption(BuildContext context) {
return PreferredSize(
preferredSize: Size(getWidth(context), 54),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 14),
margin: const EdgeInsets.only(top:12, left: 24, right: 24),
width: getWidth(context),
decoration: BoxDecorations.shadow(radius: 6.0),
child: Button(
onPressed: ()=>MakeRoute.go(context, Filter(isFocus: true,)),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image.asset(
getAssetIcon("search.png"),
height: 16,
width: 16,
),
const SizedBox(
width: 8,
),
Text(
AppLang.local(context).search_product_ucf,
style: StyleConfig.fs12cGrey,
)
],
),
),
));
}
List<Widget> sliderShimmer() {
return [
Shimmers(width: getWidth(context) - 40, height: 200),
Shimmers(width: getWidth(context) - 40, height: 200),
Shimmers(width: getWidth(context) - 40, height: 200),
Shimmers(width: getWidth(context) - 40, height: 200),
];
}
ListView categoryShimmer() {
return ListView.separated(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return Shimmers(
width: 76,
height: 87,
radius: 6.0,
);
},
separatorBuilder: (context, index) {
return const SizedBox(
width: 8,
height: 10,
);
},
itemCount: 10);
}
Widget allProductShimmer() {
return GridView.builder(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 2/3),
itemCount: 10,
itemBuilder: (context, index) {
return Shimmers(width: 160, height: 186,radius: 8,);
});
}
Widget buildBestSellingProductSection(HomePresenter data){
return
data.isBestSellingProductInitial ?
ListView.separated(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
return ProductCard(
product: data.bestSellingProductList[index],context: this.context,);
},
separatorBuilder: (context,index)=>const SizedBox(width: 10,), itemCount: data.bestSellingProductList.length)
:Shimmers.horizontalList(10, 160, 160);
}
Widget allProducts(HomePresenter data){
String datas = '';
return data.isAllProductInitial?GridView.builder(
padding: EdgeInsets.only(left: StyleConfig.padding,right: StyleConfig.padding,bottom: 20),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
itemCount: data.products.length,
itemBuilder: (context, index) {
datas = data.products[index].name;
return ProductCard(product: data.products[index],context: this.context,);
},
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.72,
// childAspectRatio: 2.1/3
),
):allProductShimmer();
}
}

View File

@@ -0,0 +1,115 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/app_config.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/screens/auth/login.dart';
import 'package:grostore/screens/auth/registration.dart';
import '../../helpers/device_info_helper.dart';
class AuthPageModel extends StatelessWidget {
const AuthPageModel({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
width: getWidth(context),
height: getHeight(context),
decoration: BoxDecoration(
//color: ThemeConfig.splashBackgrund,
image: DecorationImage(
image: AssetImage(getAssetImage("splash_background.png")))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Spacer(),
Image.asset(
getAssetLogo("img_logo2.png"),
width: 150,
height: 150,
),
// const SizedBox(
// height: 10,
// ),
// Text(
// AppConfig.appName,
// style: StyleConfig.fs30fwEBold(),
// textAlign: TextAlign.center,
// ),
// const SizedBox(
// height: 64,
// ),
Text(
AppLang.local(context).welcome_to_back,
style: StyleConfig.fs22fwEBold,
textAlign: TextAlign.center,
),
const SizedBox(
height: 10,
),
Text(
AppLang.local(context)
.energetically_streamline_one_to_one_web_readiness_before_extensive_meta_services,
style: StyleConfig.fs12cLightfwNormal,
textAlign: TextAlign.center,
),
const Spacer(),
Row(
children: [
Button(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(5)),
side: BorderSide(
color: ThemeConfig.red
)
),
// StyleConfig.buttonRadius(5),
minWidth: getWidth(context) * 0.42,
// color: ThemeConfig.secondaryColor,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding14,
vertical: StyleConfig.padding14),
child: Text(
AppLang.local(context).login,
style: StyleConfig.fs14cRedfwNormal,
),
onPressed: (){
MakeRoute.go(context, const Login());
},
),
const Spacer(),
Button(
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(5)),
side: BorderSide(
color: ThemeConfig.red
)
),
// StyleConfig.buttonRadius(5),
minWidth: getWidth(context) * 0.42,
// color: ThemeConfig.secondaryColor,
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding14,
vertical: StyleConfig.padding14),
onPressed: (){
MakeRoute.go(context, Registration());
},
child: Text(
AppLang.local(context).register,
style: StyleConfig.fs14cRedfwNormal,
),
),
],
),
const Spacer(),
],
),
);
}
}

View File

@@ -0,0 +1,105 @@
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/helpers/shared_value_helper.dart';
import 'package:grostore/presenters/landing_page_presenter.dart';
import 'package:grostore/screens/landing_pages/page_model.dart';
import 'package:grostore/screens/landing_pages/auth_model.dart';
import 'package:grostore/screens/main.dart';
import 'package:provider/provider.dart';
class LandingPage extends StatefulWidget {
const LandingPage({Key? key}) : super(key: key);
@override
State<LandingPage> createState() => _LandingPageState();
}
class _LandingPageState extends State<LandingPage> {
@override
void initState() {
// );
//show_landing_page.update((p0) => false);
// TODO: implement initState
super.initState();
}
@override
Widget build(BuildContext context) {
Provider.of<LandingPagePresenter>(context).setContext(context);
Provider.of<LandingPagePresenter>(context).iniState();
return Consumer<LandingPagePresenter>(
builder: (context,data,child) {
return Scaffold(
body: Column(
children: [
SizedBox(
height: getHeight(context)*0.88,
child: CarouselSlider(
carouselController:data.controller ,
items: data.pages,
options: CarouselOptions(
autoPlay: false,
height: MediaQuery.of(context).size.height,
initialPage: 0,
enableInfiniteScroll: false,
viewportFraction: 1.0,
onPageChanged: (index, reason) {
data.indexChange(index);
},
),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: data.pages.map((page) {
int index = data.pages.indexOf(page);
return AnimatedContainer(
duration: const Duration(milliseconds: 100),
width:data.currentIndex == index? 20:5,
height:5,
margin:const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
// shape: BoxShape.circle,
borderRadius: BorderRadius.circular(5),
color: data.currentIndex == index ? ThemeConfig.red : Colors.grey,
),
);
}).toList(),
),
const Spacer(),
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Button(
shape: StyleConfig.buttonRadius(5.0),
color: ThemeConfig.red,
padding: EdgeInsets.symmetric(vertical: StyleConfig.padding14),
minWidth: getWidth(context),
onPressed: (){
if(data.currentIndex==3) {
MakeRoute.goName(context, "/main");
} else {
data.onChangeSlider();
}
},
child: Text(data.currentIndex==3?AppLang.local(context).skip:AppLang.local(context).next,style: StyleConfig.fs12cWhitefwBold,),),
),
const SizedBox(height: 14,)
],
),
);
}
);
}
}

View File

@@ -0,0 +1,38 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
class PageModel extends StatelessWidget {
String img,headerTxt,txt;
PageModel({Key? key,required this.img,required this.headerTxt,required this.txt}) : super(key: key);
@override
Widget build(BuildContext context) {
AppLang.setContext(context);
return SizedBox(
child: Center(
child: Column(
children: [
Image.asset(getAssetImage(img),height: getHeight(context)*0.7,width: getWidth(context),fit: BoxFit.cover,),
Padding(
padding: EdgeInsets.symmetric(horizontal:StyleConfig.padding),
child: Column(
children: [
Text(headerTxt,style: StyleConfig.fs18BlackfwBold,textAlign: TextAlign.center,),
SizedBox(height: 10,),
Text(txt,style: StyleConfig.fs12cLightfwEBold,textAlign: TextAlign.center,),
],
),
),
],
),
),
);
}
}

View File

@@ -0,0 +1,165 @@
import 'package:flutter/material.dart';
import 'package:badges/badges.dart' as badges;
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/models/product_mini_response.dart';
import 'package:grostore/presenters/main_persenter.dart';
import 'package:grostore/presenters/stock_locations_presenter.dart';
import 'package:grostore/screens/auth/login.dart';
import 'package:grostore/screens/cart.dart';
import 'package:provider/provider.dart';
import '../presenters/cart_presenter.dart';
class Main extends StatefulWidget {
const Main({super.key});
@override
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
@override
void initState() {
Provider.of<MainPresenter>(context, listen: false).setContext(context);
Future.delayed(const Duration(seconds: 1)).then((value) {
Provider.of<StockLocationsPresenter>(context, listen: false)
.fetchLocations(context);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<MainPresenter>(builder: (context, data, child) {
return PopScope(
onPopInvoked: (a) async {
if (data.bottomAppbarIndex != 0) {
data.onTapped(0);
} else {
return Future.delayed(Duration.zero);
}
return Future.delayed(Duration.zero);
},
child: Scaffold(
extendBody: true,
body: data.bottomAppbarChildren[data.bottomAppbarIndex],
bottomNavigationBar: SizedBox(
height: 90,
child: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: data.onTapped,
currentIndex: data.bottomAppbarIndex,
backgroundColor: Colors.white.withOpacity(0.95),
unselectedItemColor: const Color.fromRGBO(168, 175, 179, 1),
selectedItemColor: ThemeConfig.secondaryColor,
selectedLabelStyle: TextStyle(
fontWeight: FontWeight.w700,
color: ThemeConfig.secondaryColor,
fontSize: 12),
unselectedLabelStyle: const TextStyle(
fontWeight: FontWeight.w400,
color: Color.fromRGBO(168, 175, 179, 1),
fontSize: 12),
items: [
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Image.asset(
getAssetIcon("home.png"),
color: data.bottomAppbarIndex == 0
? ThemeConfig.secondaryColor
: ThemeConfig.grey,
height: 16,
),
),
label: AppLang.local(context).home),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Image.asset(
getAssetIcon("categories.png"),
color: data.bottomAppbarIndex == 1
? ThemeConfig.secondaryColor
: ThemeConfig.grey,
height: 16,
),
),
label: AppLang.local(context).categories),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Image.asset(
getAssetIcon("orders.png"),
color: data.bottomAppbarIndex == 2
? ThemeConfig.secondaryColor
: const Color.fromRGBO(153, 153, 153, 1),
height: 16,
),
),
label: AppLang.local(context).orders),
BottomNavigationBarItem(
icon: Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Image.asset(
getAssetIcon("profile.png"),
color: data.bottomAppbarIndex == 3
? ThemeConfig.secondaryColor
: ThemeConfig.grey,
height: 16,
),
),
label: AppLang.local(context).profile,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
if (SystemData.isLogIn) {
MakeRoute.go(context, const Cart());
} else {
Navigator.push(
context, MaterialPageRoute(builder: (context) => const Login()));
return;
}
},
backgroundColor: ThemeConfig.amber,
child: badges.Badge(
position: badges.BadgePosition.custom(end: 12, bottom: -15),
badgeStyle: badges.BadgeStyle(
shape: badges.BadgeShape.circle,
badgeColor: ThemeConfig.red,
borderRadius: BorderRadius.circular(20),
borderSide: const BorderSide(width: 1, color: ThemeConfig.white)
//padding: EdgeInsets.all(5),
),
badgeContent: Consumer<CartPresenter>(
builder: (context, cart, child) {
return Text(
"${cart.cartResponse.cartCount}",
style: const TextStyle(fontSize: 10, color: Colors.white),
);
},
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
getAssetIcon("cart.png"),
color: ThemeConfig.white,
height: 20,
),
),
),
),
floatingActionButtonLocation:
FloatingActionButtonLocation.centerDocked,
),
);
});
}
}

View File

@@ -0,0 +1,472 @@
import 'package:dotted_line/dotted_line.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/order_item.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/order_details_presenter.dart';
import 'package:grostore/screens/order/pdf_api.dart';
import 'package:grostore/screens/order/pdf_invoice_api.dart';
import '../../helpers/common_functions.dart';
class OrderDetails extends StatefulWidget {
final code;
const OrderDetails({super.key, this.code});
@override
State<OrderDetails> createState() => _OrderDetailsState();
}
class _OrderDetailsState extends State<OrderDetails> {
OrderDetailsPresenter orderDetailsPresenter = OrderDetailsPresenter();
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
orderDetailsPresenter.initState(widget.code);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).order_details, context: context),
body: ListenableBuilder(
listenable: orderDetailsPresenter,
builder: (context, child) {
return RefreshIndicator(
onRefresh: () {
return orderDetailsPresenter.onRefresh(widget.code);
},
child: SingleChildScrollView(
child: orderDetailsPresenter.isInitDetails
? Container(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 24),
Container(
width: getWidth(context),
decoration: BoxDecorations.shadow(radius: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Buyurtma raqami: ${orderDetailsPresenter.orderInfo?.code ?? ''}",
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 14,
),
Text(
"Buyurtma sanasi: ${orderDetailsPresenter.orderInfo?.date ?? ''}",
style: StyleConfig.fs14fwBold,
),
],
),
),
const SizedBox(
height: 14,
),
Text(
"Billing Address",
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 8,
),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 8),
decoration: BoxDecorations.shadow(radius: 8),
child: buildBillingAddress(context)),
const SizedBox(
height: 14,
),
Text(
"Shipping Address",
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 8,
),
Container(
decoration: BoxDecorations.shadow(radius: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 8),
child: buildShippingAddress(context)),
const SizedBox(
height: 14,
),
Text(
"Products",
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 8,
),
Container(
//decoration: BoxDecorations.shadow(radius: 8),
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 8),
child: Column(
children: [
/*Row(
children: [
Container(
width: getWidth(context)*0.35,
child: Text("Product Name")),
Container(
width: getWidth(context)*0.18,
child: Text("Unit Price")),
Container(
width: getWidth(context)*0.1,
child: Text("QTY")),
Container(
width: getWidth(context)*0.18,
child: Text("Total Price")),
],
),
Divider(color: ThemeConfig.fontColor,),*/
GridView.builder(
//padding: EdgeInsets.only(left: StyleConfig.padding,right: StyleConfig.padding,bottom: 20),
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(),
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 8,
childAspectRatio: 0.62),
itemBuilder: (context, index) =>
OrderItem(
context: context,
onReq: (value) {
if (value) {
orderDetailsPresenter
.onRefresh(widget.code);
}
},
item: orderDetailsPresenter
.orderInfo!.items[index],
)
/*Container(
child: Row(
children: [
Container(
width: getWidth(context)*0.35,
child: Text(orderDetailsPresenter.orderInfo?.items[index].product?.name??"")),
Container(
width: getWidth(context)*0.18,
child: Text(showPrice(orderDetailsPresenter.orderInfo?.items[index].unitPrice??""))),
Container(
width: getWidth(context)*0.1,
child: Text("${orderDetailsPresenter.orderInfo?.items[index].qty??''}")),
Container(
width: getWidth(context)*0.18,
child: Text(showPrice(orderDetailsPresenter.orderInfo?.items[index].totalPrice??""))),
],
),
),
,
separatorBuilder: (context, index) => Column(
children: [
SizedBox(
height: 15,
),
Divider(color: ThemeConfig.fontColor,),
],
)*/
,
itemCount: orderDetailsPresenter
.orderInfo?.items.length ??
0),
],
),
),
const SizedBox(
height: 14,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Payment Method",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter
.orderInfo?.payment_method
.toUpperCase() ??
"",
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 14,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Sub Total",
style: StyleConfig.fs14fwBold,
),
Text(
showPrice(orderDetailsPresenter
.orderInfo?.subTotalAmount ??
""),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 14,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Tips",
style: StyleConfig.fs14fwBold,
),
Text(
showPrice(orderDetailsPresenter
.orderInfo?.totalTips ??
""),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 14,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Shipping Cost",
style: StyleConfig.fs14fwBold,
),
Text(
showPrice(orderDetailsPresenter
.orderInfo?.totalShippingCost ??
""),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 14,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Coupon Discount",
style: StyleConfig.fs14fwBold,
),
Text(
showPrice(orderDetailsPresenter
.orderInfo?.couponDiscountAmount ??
""),
style: StyleConfig.fs14fwNormal,
),
],
),
const SizedBox(
height: 14,
),
const DottedLine(),
const SizedBox(
height: 14,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Total Price",
style: StyleConfig.fs14fwBold,
),
Text(
showPrice(orderDetailsPresenter
.orderInfo?.totalPrice ??
""),
style: StyleConfig.fs14fwBold
.copyWith(color: ThemeConfig.red),
),
],
),
const SizedBox(
height: 24,
),
Button(
minHeight: 40.0,
shape: StyleConfig.buttonRadius(10),
minWidth: MediaQuery.sizeOf(context).width,
color: ThemeConfig.red,
child: Text(
AppLang.local(context).download_invoice,
style: StyleConfig.fs14cWhitefwBold,
),
onPressed: () async {
final pdf = await PdfInvoiceApi.generate(orderDetailsPresenter.orderInfo);
PdfApi.openFile(pdf);
},
),
const SizedBox(
height: 30,
)
],
),
)
: SizedBox(
height: getHeight(context),
child:
const Center(child: CircularProgressIndicator())),
),
);
}),
);
}
Column buildBillingAddress(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
orderDetailsPresenter.orderInfo?.billingAddress?.address ?? "",
style: StyleConfig.fs14fwNormal,
maxLines: 1,
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).city}: ",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter.orderInfo?.billingAddress?.cityName ?? "",
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).state}: ",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter.orderInfo?.billingAddress?.stateName ??
"",
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).country}: ",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter.orderInfo?.billingAddress?.countryName ??
"",
style: StyleConfig.fs14fwNormal,
),
],
),
),
],
);
}
Column buildShippingAddress(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
orderDetailsPresenter.orderInfo?.shippingAddress?.address ?? "",
style: StyleConfig.fs14fwNormal,
maxLines: 1,
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).city}: ",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter.orderInfo?.shippingAddress?.cityName ??
"",
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).state}: ",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter.orderInfo?.shippingAddress?.stateName ??
"",
style: StyleConfig.fs14fwNormal,
),
],
),
),
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Row(
children: [
Text(
"${AppLang.local(context).country}: ",
style: StyleConfig.fs14fwBold,
),
Text(
orderDetailsPresenter.orderInfo?.shippingAddress?.countryName ??
"",
style: StyleConfig.fs14fwNormal,
),
],
),
),
],
);
}
}

View File

@@ -0,0 +1,148 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/order_view_model.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/order_presenter.dart';
import 'package:grostore/screens/main.dart';
import 'package:provider/provider.dart';
class Orders extends StatefulWidget {
bool fromBottomBar;
bool fromCheckOut;
Orders({Key? key, this.fromBottomBar = true,this.fromCheckOut=false}) : super(key: key);
@override
State<Orders> createState() => _OrdersState();
}
class _OrdersState extends State<Orders> {
OrderPresenter order = OrderPresenter();
@override
void initState() {
super.initState();
Provider.of<OrderPresenter>(context, listen: false).setContext(context);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<OrderPresenter>(context, listen: false).initState();
});
}
@override
Widget build(BuildContext context) {
return PopScope(
onPopInvoked: (a) async {
if(widget.fromCheckOut){
MakeRoute.goAndRemoveAll(context, const Main());
return Future(() => true);
}
return Future(() => true);
},
child: Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).orders,
context: context,
gotoMain: widget.fromCheckOut,
showBackButton: !widget.fromBottomBar),
body: Consumer<OrderPresenter>(builder: (context, data, child) {
return RefreshIndicator(
onRefresh: () => data.onRefresh(),
child: SingleChildScrollView(
child: Column(
children: [
const SizedBox(
height: 10,
),
buildTapbar(context, data),
if (!data.isOrdersInit)
SizedBox(
width: getWidth(context),
height: getHeight(context) - 100,
child: Shimmers.list(10, getWidth(context), 80),
)
else if (data.isOrdersInit && data.orders.isNotEmpty)
ListView.separated(
padding: EdgeInsets.only(
left: 10,
right: 10,
top: 10,
bottom: widget.fromBottomBar ? 80 : 10),
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: data.orders.length,
separatorBuilder: (context, index) {
return const SizedBox(
height: 10,
);
},
itemBuilder: (context, index) {
return Button(
//padding: EdgeInsets.symmetric(vertical: 10,horizontal: 20),
minWidth: 100,
onPressed: () {},
child: OrderViewModel(
orderInfo: data.orders[index],
context: context,
));
},
)
else
Container(
height: getHeight(context)-180,
alignment: Alignment.center,
child: Text(AppLang.local(context).data_is_not_available))
],
),
),
);
}),
),
);
}
SizedBox buildTapbar(BuildContext context, OrderPresenter data) {
return SizedBox(
// color: Colors.red,
width: getWidth(context),
height: 40,
child: ListView.separated(
padding: const EdgeInsets.symmetric(horizontal: 10),
scrollDirection: Axis.horizontal,
itemCount: data.searchKey.values.length,
separatorBuilder: (context, index) {
return const SizedBox(
width: 10,
);
},
itemBuilder: (context, index) {
return Button(
padding: const EdgeInsets.symmetric(vertical: 3, horizontal: 15),
color: data.keySelectedIndex == index
? ThemeConfig.red
: ThemeConfig.white,
minWidth: 80,
minHeight: 40.0,
shape: StyleConfig.buttonRadius(10),
onPressed: () {
data.onChangeIndex(index);
},
child: Text( data.searchKey.values.elementAt(index),
style: data.keySelectedIndex == index
? StyleConfig.fs14cWhitefwBold
: StyleConfig.fs14fwBold,
),
);
},
),
);
}
}

View File

@@ -0,0 +1,27 @@
import 'dart:io';
import 'package:open_file/open_file.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/widgets.dart';
class PdfApi {
static Future<File> saveDocument({
required String name,
required Document pdf,
}) async {
final bytes = await pdf.save();
final dir = await getApplicationDocumentsDirectory();
final file = File('${dir.path}/$name');
await file.writeAsBytes(bytes);
return file;
}
static Future openFile(File file) async {
final url = file.path;
await OpenFile.open(url);
}
}

View File

@@ -0,0 +1,152 @@
import 'dart:io';
import 'package:flutter/material.dart' show Colors;
import 'package:flutter/services.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/screens/order/pdf_api.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:pdf/widgets.dart';
import '../../models/order/order_details_response.dart';
class PdfInvoiceApi {
static Future<File> generate(OrderDetailsInfo? detailsInfo) async {
final img = await rootBundle.load(getAssetLogo("logo2x2.png"));
final imageBytes = img.buffer.asUint8List();
final imgQr = await rootBundle.load(getAssetLogo("img.png"));
final qr = imgQr.buffer.asUint8List();
final pdf = Document();
pdf.addPage(MultiPage(
build: (context) => [
buildLogo(imageBytes),
pw.SizedBox(height: 0.3 * PdfPageFormat.cm),
buildDottedDivider(),
pw.SizedBox(height: 0.5 * PdfPageFormat.cm),
buildAddress(
"${detailsInfo?.shippingAddress?.address}, ${detailsInfo?.shippingAddress?.cityName}, ${detailsInfo?.shippingAddress?.stateName}, ${detailsInfo?.shippingAddress?.countryName}"),
pw.SizedBox(height: 0.3 * PdfPageFormat.cm),
buildPhoneNumber("${detailsInfo?.payment_method}"),
pw.SizedBox(height: 0.5 * PdfPageFormat.cm),
buildDottedDivider(),
pw.SizedBox(height: 0.5 * PdfPageFormat.cm),
buildCheckDate("${detailsInfo?.code}", "${detailsInfo?.date}"),
pw.SizedBox(height: 0.3 * PdfPageFormat.cm),
buildDottedDivider(),
pw.SizedBox(height: 0.5 * PdfPageFormat.cm),
buildItemsList(detailsInfo?.items ?? []),
pw.SizedBox(height: 0.7 * PdfPageFormat.cm),
buildDottedDivider(),
pw.SizedBox(height: 0.5 * PdfPageFormat.cm),
buildSummery(detailsInfo),
buildDottedDivider(),
pw.SizedBox(height: 1.2 * PdfPageFormat.cm),
buildQrCode(qr)
],
//footer: (context) => buildFooter(invoice),
));
return PdfApi.saveDocument(name: 'Check.pdf', pdf: pdf);
}
static Widget buildLogo(Uint8List image) {
return Row(mainAxisAlignment: pw.MainAxisAlignment.spaceBetween, children: [
Text("Karvon market",
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
)),
pw.Image(pw.MemoryImage(image), height: 40)
]);
}
static Widget buildDottedDivider() {
return Row(
children: List.generate(
800 ~/ 10,
(index) => index % 2 == 0
? Expanded(
child: pw.Container(height: 1, color: PdfColor(0, 0, 0)),
)
: Expanded(
child: Container(height: 2, color: null),
)));
}
static Widget buildAddress(String address) {
return pw.Text(address, style: TextStyle(fontSize: 14));
}
static Widget buildPhoneNumber(String phoneNumber) {
return pw.Text("To'lov turi: $phoneNumber", style: TextStyle(fontSize: 14));
}
static Widget buildCheckDate(String checkNumber, String date) {
return Column(
mainAxisAlignment: pw.MainAxisAlignment.start,
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
Text("Check raqami: $checkNumber", style: TextStyle(fontSize: 14)),
pw.SizedBox(height: 0.2 * PdfPageFormat.cm),
Text("Chiqarilgan: $date", style: TextStyle(fontSize: 14))
]);
}
static Widget buildItemsList(List<Item> items) {
return Column(
mainAxisSize: pw.MainAxisSize.min,
mainAxisAlignment: pw.MainAxisAlignment.start,
children: List.generate(
items.length,
(index) => Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
Text("${index + 1}.${items[index].product?.name}",
style: TextStyle(
fontSize: 16, fontWeight: pw.FontWeight.bold)),
pw.SizedBox(height: 0.1 * PdfPageFormat.cm),
Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceAround,
children: [
Text("Narxi:",
style: TextStyle(
fontSize: 16, fontWeight: pw.FontWeight.normal)),
Text(items[index].unitPrice,
style: TextStyle(
fontSize: 15, fontWeight: pw.FontWeight.normal)),
Text("${items[index].qty} ta",
style: TextStyle(
fontSize: 15, fontWeight: pw.FontWeight.normal)),
Text(items[index].totalPrice,
style: TextStyle(
fontSize: 17, fontWeight: pw.FontWeight.bold)),
])
]),
));
}
static Widget buildSummery(OrderDetailsInfo? info) {
return Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
mainAxisAlignment: pw.MainAxisAlignment.start,
children: [
Text("Mahsulot narxi: ${info?.subTotalAmount}",
style: TextStyle(fontSize: 15)),
pw.SizedBox(height: 0.2 * PdfPageFormat.cm),
Text("Yuk tashish narxi:${info?.totalShippingCost}",
style: TextStyle(fontSize: 15)),
pw.SizedBox(height: 0.2 * PdfPageFormat.cm),
Text("Chegirmasi: ${info?.couponDiscountAmount}",
style: TextStyle(fontSize: 15)),
pw.SizedBox(height: 0.2 * PdfPageFormat.cm),
Text("Jami narxi: ${info?.totalPrice}",
style: TextStyle(fontSize: 15, fontWeight: pw.FontWeight.bold)),
pw.SizedBox(height: 0.5 * PdfPageFormat.cm),
]);
}
static Widget buildQrCode(Uint8List qrcode) {
return pw.Center(child: pw.Image(pw.MemoryImage(qrcode), height: 200));
}
}

View File

@@ -0,0 +1,44 @@
import 'package:flutter/material.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/presenters/page_presenter.dart';
import 'package:webview_flutter/webview_flutter.dart';
class Pages extends StatefulWidget {
final String slug;
const Pages({super.key, required this.slug});
@override
State<Pages> createState() => _PagesState();
}
class _PagesState extends State<Pages> {
PagePresenter pagePresenter = PagePresenter();
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
pagePresenter.initState(widget.slug);
});
super.initState();
}
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: pagePresenter,
builder: (context,child) {
return Scaffold(
appBar: CommonAppbar.show(title: pagePresenter.pageInfo?.title??"", context: context),
body:Padding(
padding: const EdgeInsets.all(8.0),
child: WebViewWidget(controller: pagePresenter.controller,),
) ,
);
}
);
}
}

View File

@@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:grostore/configs/app_config.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/helpers/shared_value_helper.dart';
import 'package:grostore/presenters/page_presenter.dart';
import 'package:grostore/presenters/payment_presenter.dart';
import 'package:grostore/screens/order/orders.dart';
import 'package:webview_flutter/webview_flutter.dart';
class Payment extends StatefulWidget {
final int code;
final String payment_method;
final String title;
const Payment(
{super.key,
required this.code,
required this.payment_method,
required this.title});
@override
State<Payment> createState() => _PaymentState();
}
class _PaymentState extends State<Payment> {
PaymentPresenter paymentPresenter = PaymentPresenter();
@override
void initState() {
// TODO: implement initState
// WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// paymentPresenter.initState(widget.code, widget.payment_method);
// });
paymentPresenter.controller.loadRequest(
Uri.parse(
"${AppConfig.apiUrl}/order/online-payment?code=${widget.code}&payment_method=${widget.payment_method}"),
headers: {"Authorization": "Bearer ${access_token.$}"});
paymentPresenter.controller.setNavigationDelegate(NavigationDelegate(
onPageFinished: (page){
if(page.contains('checkout-complete')||page.contains('success')||page.contains("cancel")||page.contains("callback")){
MakeRoute.go(context, Orders(fromBottomBar: false,fromCheckOut: true,));
}
}
));
super.initState();
}
@override
Widget build(BuildContext context) {
return ListenableBuilder(
listenable: paymentPresenter,
builder: (context, child) {
return Scaffold(
appBar: CommonAppbar.show(title: widget.title, context: context),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: WebViewWidget(
controller: paymentPresenter.controller,
),
),
);
});
}
}

View File

@@ -0,0 +1,548 @@
import 'package:carousel_slider/carousel_slider.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/Image_view.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/product_card.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/custom_ui/toast_ui.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/cart_presenter.dart';
import 'package:grostore/presenters/product_details_presenter.dart';
import 'package:grostore/presenters/wishlist_presenter.dart';
import 'package:grostore/screens/auth/login.dart';
import 'package:grostore/screens/cart.dart';
import 'package:badges/badges.dart' as badges;
import 'package:provider/provider.dart';
class ProductDetails extends StatefulWidget {
late String slug;
ProductDetails({Key? key, required this.slug}) : super(key: key);
@override
State<ProductDetails> createState() => _ProductDetailsState();
}
class _ProductDetailsState extends State<ProductDetails> {
// WishlistPresenter wishlistPresenter = WishlistPresenter();
@override
void initState() {
Provider.of<ProductDetailsPresenter>(context, listen: false)
.setContext(context);
Future.delayed(const Duration(seconds: 0)).then((value) {
Provider.of<ProductDetailsPresenter>(context, listen: false)
.iniState(widget.slug);
});
super.initState();
}
@override
void dispose() {
super.dispose();
}
@override
Widget build(BuildContext context) {
return Consumer<ProductDetailsPresenter>(builder: (context, data, child) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: data.productInfo != null ? data.productInfo!.name : "",
context: context),
body: RefreshIndicator(
onRefresh: data.onRefresh,
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildSliderSection(data),
buildProductNameSection(context, data),
const SizedBox(
height: 16,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).description,
style: StyleConfig.fs14fwBold,
),
),
const SizedBox(
height: 16
),
data.isProductInfoInitial
? Padding(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
data.productInfo?.shortDescription??"",
style: StyleConfig.fs14fwNormal.copyWith(height: 1.8),
),
)
: Shimmers(width: getWidth(context), height: 150),
const SizedBox(
height: 16,
),
if (data.productInfo != null)
Container(
padding:
EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: ListView.separated(
physics:const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, variationIndex) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.variations[variationIndex].name,
style: StyleConfig.fs16fwBold,
),
const SizedBox(
height: 10,
),
Wrap(
spacing: 10,
children: List.generate(
data.variations[variationIndex].values
.length, (valueIndex) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 5, vertical: 5),
decoration: BoxDecorations.shadow(radius: 6)
.copyWith(
border: Border.all(
color: data
.variations[
variationIndex]
.values[valueIndex]
.isChosen
? ThemeConfig.accentColor
: ThemeConfig.grey,
width: 2)),
child: InkWell(
onTap: () {
data.onChangeVariation(
variationIndex, valueIndex);
},
child: data.variations[variationIndex]
.id ==
2
? Container(
height: 40,
width: 40,
color: Color(int.parse(data
.variations[variationIndex]
.values[valueIndex]
.code)),
)
: Text(
data.variations[variationIndex]
.values[valueIndex].name,
style: StyleConfig.fs14fwNormal,
),
),
);
}),
)
],
);
},
separatorBuilder: (context, index) {
return const SizedBox(
height: 16,
);
},
itemCount: data.variations.length),
),
const SizedBox(
height: 16,
),
buildPriceAndQuantitySection(context, data),
const SizedBox(
height: 16,
),
Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Text(
AppLang.local(context).related_product_ucf,
style: StyleConfig.fs16fwBold,
),
),
const SizedBox(
height: 16,
),
buildRelatedProductSection(data),
],
),
),
),
/*floatingActionButton: Container(
//margin: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
width: getWidth(context),
height: 70,
//color: Colors.red,
child:Button(
shape: StyleConfig.buttonRadius(10),
color: ThemeConfig.accentColor,
minWidth: getWidth(context)-40,
onPressed: (){},
child: Text(AppLang.local(context).add_to_cart,style: StyleConfig.fs14cWhitefwNormal,),
),
),
*/
// floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
bottomNavigationBar: data.selectedVariation != null
? SizedBox(
width: getWidth(context),
height: 50,
child: Button(
color: ThemeConfig.fontColor,
minWidth: getWidth(context) - 40,
onPressed: () {
if (SystemData.isLogIn) {
MakeRoute.go(context, const Cart());
}else{
MakeRoute.go(context, const Login());
}
},
child: Consumer<CartPresenter>(
builder: (context,data,child) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Total: ${showPrice(data.cartResponse.subTotal)}",style: StyleConfig.fs16cWhitefwBold,),
Text(
AppLang.local(context).go_to_cart,
style: StyleConfig.fs16cWhitefwBold,
),
],
),
);
}
),
),
)
: null,
);
});
}
Widget relatedProductShimmer() {
return GridView.builder(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.8),
itemCount: 10,
itemBuilder: (context, index) {
return Shimmers(
width: 160,
height: 186,
radius: 8,
);
});
}
Widget buildRelatedProductSection(ProductDetailsPresenter data) {
return data.isRelatedInitial
? GridView.builder(
padding: EdgeInsets.only(
left: StyleConfig.padding,
right: StyleConfig.padding,
bottom: StyleConfig.padding,
),
shrinkWrap: true,
physics:const NeverScrollableScrollPhysics(),
gridDelegate:const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.65
),
itemCount: data.relatedProducts.length,
itemBuilder: (context, index) {
return ProductCard(
product: data.relatedProducts[index],
context: this.context,
);
})
: relatedProductShimmer();
}
Container buildPriceAndQuantitySection(
BuildContext context, ProductDetailsPresenter data) {
return Container(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
height: 50,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
AppLang.local(context).price,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 6,
),
data.isProductInfoInitial
? Text(showPrice(data.selectedVariation!.price),
style: StyleConfig.fs16cRedfwBold)
: Shimmers(width: 100, height: 25),
],
),
const Spacer(),
/// Add to cart or login route
Consumer<WishlistPresenter>(
// listenable: wishlistPresenter,
builder: (context,wishlistPresenter,child) {
return Button(
onPressed: () {
if(SystemData.isLogIn) {
if(wishlistPresenter.isAddedWishlist) {
wishlistPresenter.deleteWishlist(data.productInfo!.id,context);
}else{
wishlistPresenter.addWishlist(data.productInfo!.id, context);
}
} else {
MakeRoute.go(context,const Login());
}
},
child: Icon(wishlistPresenter.isAddedWishlist? Icons.favorite:Icons.favorite_border,color: ThemeConfig.red,size: 35,));
},
),
Button(
minWidth:40,
shape: StyleConfig.buttonRadius(6),
color: ThemeConfig.red,
padding: const EdgeInsets.symmetric(horizontal: 24,vertical: 12),
onPressed: () {
if (SystemData.isLogIn) {
if (data.selectedVariation!.sock > 0) {
Provider.of<CartPresenter>(context, listen: false)
.addToCart(data.selectedVariation!.id,
data.quantity, context);
} else {
ToastUi.show(context, "Stock out");
}
}else{
MakeRoute.go(context, const Login());
}
},
child:Text(AppLang.local(context).add_to_cart,style: StyleConfig.fs12cWhitefwBold,)
/* Icon(
Icons.add_shopping_cart_outlined,
color: ThemeConfig.white,
size: 18,
),*/
),
/*Button(
minWidth: 30,
shape: CircleBorder(),
color: ThemeConfig.fontColor,
padding: EdgeInsets.all(8),
onPressed: () {
data.decrementQty();
},
child: Icon(
Icons.remove,
color: ThemeConfig.white,
size: 18,
),
),
Container(
padding: EdgeInsets.symmetric(horizontal: 5),
constraints: BoxConstraints(minWidth: 40),
alignment: Alignment.center,
child: Text(
"${data.quantity}",
style: StyleConfig.fs14fwBold,
)),
Button(
minWidth: 30,
shape: CircleBorder(),
color: ThemeConfig.accentColor,
padding: EdgeInsets.all(8),
onPressed: () {
data.incrementQty();
},
child: Icon(
Icons.add,
color: ThemeConfig.white,
size: 18,
),
),*/
],
),
);
}
Container buildProductNameSection(
BuildContext context, ProductDetailsPresenter data) {
return Container(
height: 60,
width: getWidth(context),
color: ThemeConfig.white,
child: Container(
alignment: Alignment.bottomLeft,
padding: EdgeInsets.only(left: StyleConfig.padding),
decoration: BoxDecorations.customRadius(
radius: const BorderRadius.only(topLeft: Radius.circular(70)),
color: ThemeConfig.xxlightGrey),
child: data.isProductInfoInitial
? Text(
data.productInfo!.name,
style: StyleConfig.fs20fwBold,
)
: Shimmers(width: 170, height: 30)),
);
}
Widget buildSliderSection(ProductDetailsPresenter data) {
return Container(
height: 200,
decoration: BoxDecorations.customRadius(
radius: const BorderRadius.only(bottomRight: Radius.circular(70))),
child: Column(
children: [
Stack(
children: [
CarouselSlider(
items: data.isProductInfoInitial
? buildImages(data)
: sliderShimmer(),
options: CarouselOptions(
aspectRatio: 1,
height: 150,
enlargeCenterPage: true,
scrollDirection: Axis.horizontal,
autoPlay: true,
onPageChanged: (index, reason) {
data.onChangeBannerIndex(index);
},
),
),
/*Positioned(
right: 10,
top: 10,
child: Button(
onPressed: () {
MakeRoute.go(context, const Cart());
},
shape: StyleConfig.buttonRadius(30),
padding: EdgeInsets.all(8),
color:ThemeConfig.amber,
minWidth: 35,
child: badges.Badge(
position: badges.BadgePosition.custom(end: 12, bottom: -15),
badgeStyle: badges.BadgeStyle(
shape: badges.BadgeShape.circle,
badgeColor: ThemeConfig.red,
borderRadius: BorderRadius.circular(20),
borderSide: BorderSide(width: 1, color: ThemeConfig.white)
//padding: EdgeInsets.all(5),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Image.asset(
getAssetIcon("cart.png"),
color: ThemeConfig.white,
height: 20,
),
),
badgeContent: Consumer<CartPresenter>(
builder: (context, cart, child) {
return Text(
"${cart.cartResponse.cartCount}",
style: TextStyle(fontSize: 10, color: Colors.white),
);
},
),
),
)
)*/
],
),
const SizedBox(
height: 24,
),
if (data.isProductInfoInitial)
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: data.productInfo!.galleryImages.map((page) {
int index = data.productInfo!.galleryImages.indexOf(page);
return AnimatedContainer(
duration: const Duration(milliseconds: 100),
width: data.currentSlider == index ? 20 : 8,
height: 8,
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
// shape: BoxShape.circle,
borderRadius: BorderRadius.circular(5),
color: data.currentSlider == index
? ThemeConfig.accentColor
: ThemeConfig.accentColor.withOpacity(0.4),
),
);
}).toList(),
),
],
),
);
}
Widget imageSample(String data) {
// print(data);
return Container(
margin: const EdgeInsets.symmetric(horizontal: 5),
child: ImageView(
url: data,
width: getWidth(context) - 40,
height: 200,
),
);
}
buildImages(ProductDetailsPresenter data) {
List<Widget> sliders = [];
data.productInfo!.galleryImages.forEach((image) {
sliders.add(imageSample(image));
});
return sliders;
}
List<Widget> sliderShimmer() {
return [
Shimmers(width: getWidth(context) - 40, height: 200),
Shimmers(width: getWidth(context) - 40, height: 200),
Shimmers(width: getWidth(context) - 40, height: 200),
Shimmers(width: getWidth(context) - 40, height: 200),
];
}
}

View File

@@ -0,0 +1,300 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/Image_view.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/presenters/auth/auth_presenter.dart';
import 'package:grostore/screens/address/addresses.dart';
import 'package:grostore/screens/auth/login.dart';
import 'package:grostore/screens/coupons.dart';
import 'package:grostore/screens/help_center.dart';
import 'package:grostore/screens/main.dart';
import 'package:grostore/screens/order/orders.dart';
import 'package:grostore/screens/pages.dart';
import 'package:grostore/screens/profile_edit.dart';
import 'package:grostore/screens/refund.dart';
import 'package:grostore/screens/setting.dart';
import 'package:grostore/screens/stock_locations.dart';
import 'package:grostore/screens/track_order.dart';
import 'package:grostore/screens/wallet.dart';
import 'package:grostore/screens/wishlist.dart';
import 'package:provider/provider.dart';
import 'package:route_transitions/route_transitions.dart';
import 'package:toast/toast.dart';
class Account extends StatefulWidget {
const Account({super.key});
@override
_AccountState createState() => _AccountState();
}
class _AccountState extends State<Account> with TickerProviderStateMixin {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.secondaryColor,
// appBar: AppBar(
// backgroundColor: ThemeConfig.accentColor,
// elevation: 0,
// leading: SizedBox.shrink(),
// actions: [
// buildBackButtonContainer(context),
// ],
// ),
// PreferredSize(preferredSize: Size(getWidth(context),40),
// child:
// ),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 15,),
Expanded(
flex: 1,
child: Container(
height: 80,
width: getWidth(context),
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding, vertical: 10),
child:SystemData.isLogIn ?
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.all(15.0),
child: ImageView(url: SystemData.userInfo.avatar,fit: BoxFit.cover, width: 50, height: 50,radius:50),
),
const SizedBox(width: 14,),
/// Name and Phone number.
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(SystemData.userInfo.name??"JAhongir",style: StyleConfig.fs16cWhitefwBold,),
const SizedBox(height: 10,),
Text(SystemData.userInfo.phone,style: StyleConfig.fs12cWhitefwBold,),
],
),
const Spacer(),
Button(
onPressed: (){
MakeRoute.go(context, ProfileEdit());
},
minWidth: 60,
padding: const EdgeInsets.symmetric(horizontal: 10,vertical: 10),
shape: StyleConfig.buttonRadius(8).copyWith(
side: const BorderSide(width: 1, color: ThemeConfig.white))
// RoundedRectangleBorder(borderRadius: BorderRadius.c),
,
child: Text(AppLang.local(context).edit_profile_ucf, style: StyleConfig.fs12cWhitefwBold,),
)
],
)
:
/// ELSE Condition
Row(
children: [
Container(
height:50,width: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(45),
color: ThemeConfig.extraDarkGrey
),
padding: const EdgeInsets.symmetric(horizontal: 14,vertical: 14),
child: Image.asset(getAssetIcon("profile.png"),color: ThemeConfig.lightGrey,),
),
const SizedBox(width: 10,),
Button(minWidth: 20,
// shape: StyleConfig.buttonRadius(10).copyWith(side: BorderSide(width: 1,color: ThemeConfig.white))
// RoundedRectangleBorder(borderRadius: BorderRadius.c),
onPressed:(){
MakeRoute.go(context, const Login());
},
child: Text("Login", style: StyleConfig.fs16fwBold.copyWith(
decoration: TextDecoration.underline),),
)
],
),
),
),
// SizedBox(height: 20,),
Expanded(
flex: 6,
child: Container(
padding: EdgeInsets.only(left: StyleConfig.padding,
right: StyleConfig.padding,
top: 40),
//height: getHeight(context)-220,
decoration: BoxDecorations.customRadius(radius: const BorderRadius.only(
topLeft: Radius.circular(10), topRight: Radius.circular(10)),
color: ThemeConfig.white),
child: SingleChildScrollView(
child: Column(
children: [
optionModel(AppLang
.local(context)
.pick_a_location, getAssetIcon("address.png"), StockLocations()),
if(SystemData.isLogIn)
Column(
children: [
/// #Voucherva Cupon
// optionModel(AppLang
// .local(context)
// .voucher_n_offers_ucf, getAssetIcon("coupons.png"),
// const Coupons()),
optionModel(AppLang
.local(context)
.favorite, getAssetIcon("favorite.png"),
const Wishlist()),
optionModel(AppLang
.local(context)
.order_n_recording_ucf, getAssetIcon("orders.png"),
Orders(fromBottomBar: false,)),
// optionModel(AppLang
// .local(context)
// .my_profile_ucf, getAssetIcon("profile.png"),
// Container()),
optionModel(AppLang.local(context).address, getAssetIcon("address.png"),const Addresses()),
// optionModel(AppLang
// .local(context)
// .notification, getAssetIcon("notification.png"),
// Container()),
// optionModel(AppLang
// .local(context)
// .security, getAssetIcon("security.png"),
// Container()),
optionModel(AppLang
.local(context)
.track_my_order_ucf, getAssetIcon("track.png"),
const TrackOrder()),
// optionModel(AppLang
// .local(context)
// .wallet_history_ucf, getAssetIcon("wallet.png"),
// const Wallet()),
// optionModel(AppLang
// .local(context)
// .refund_history_ucf, getAssetIcon("refund.png"),
// const Refund()),
],
),
optionModel(AppLang
.local(context)
.help_center_ucf, getAssetIcon("help_center.png"),
const HelpCenter()),
optionModel(AppLang
.local(context)
.settings, getAssetIcon("setting.png"),const Setting()),
optionModel(AppLang
.local(context)
.terms_n_conditions_ucf,
getAssetIcon("terms_condition.png"), const Pages(slug: "terms-conditions")),
if(SystemData.isLogIn)
logoutModel(AppLang
.local(context)
.log_out_ucf, getAssetIcon("logout.png"),(){
Provider.of<AuthPresenter>(context,listen: false).logout(context);
MakeRoute.goAndRemoveAll(context, const Main());
}),
if(!SystemData.isLogIn)
optionModel(AppLang
.local(context)
.login, getAssetIcon("login.png"), const Login()),
],
),
),
),
)
],
),
);
}
Container buildBackButtonContainer(BuildContext context) {
return Container(
height: 47,
alignment: Alignment.topRight,
child: SizedBox(
width: 47,
child: Button(
minWidth: 0,
padding: EdgeInsets.zero,
onPressed: () {
pop(context);
},
child: const Icon(
Icons.close,
size: 30,
color: ThemeConfig.white,
),
),
),
);
}
Widget optionModel(String title, String logo, Widget route) {
return Container(
margin: EdgeInsets.only(bottom: StyleConfig.xsSectionSpacer),
height: 50,
child: Button(
minWidth: 50,
onPressed: () {
MakeRoute.go(context, route);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(logo, width: 25, height: 25, color: ThemeConfig.extraDarkGrey),
const SizedBox(width: 26,),
Text(title, style: StyleConfig.fs14fwNormal,),
const Spacer(),
// Image.asset(getAssetIcon("next.png"), width: 14,
// height: 14,
// color: ThemeConfig.fontColor),
],
),
),
);
}
Widget logoutModel(String title, String logo, dynamic onPress) {
return Container(
margin: EdgeInsets.only(bottom: StyleConfig.padding),
height: 40,
child: Button(
minWidth: 40,
onPressed:onPress,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Image.asset(logo, width: 18, height: 18, color: ThemeConfig.extraDarkGrey),
const SizedBox(width: 26,),
Text(title, style: StyleConfig.fs14fwNormal,),
const Spacer(),
// Image.asset(getAssetIcon("next.png"), width: 14,
// height: 14,
// color: ThemeConfig.fontColor),
],
),
),
);
}
}

View File

@@ -0,0 +1,465 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/Image_view.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/user_presenter.dart';
import 'package:provider/provider.dart';
class ProfileEdit extends StatefulWidget {
@override
_ProfileEditState createState() => _ProfileEditState();
}
class _ProfileEditState extends State<ProfileEdit> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: buildAppBar(context),
body: Consumer<UserPresenter>(builder: (context, data, child) {
return buildBody(data);
}),
);
}
AppBar buildAppBar(BuildContext context) {
return AppBar(
backgroundColor: Colors.white,
centerTitle: false,
leading: Builder(
builder: (context) => IconButton(
icon: Icon(Icons.arrow_back, color: ThemeConfig.darkGrey),
onPressed: () => Navigator.of(context).pop(),
),
),
title: Text(
AppLang.local(context).edit_profile_ucf,
style: TextStyle(
fontSize: 16,
color: ThemeConfig.fontColor,
fontWeight: FontWeight.bold),
),
elevation: 0.0,
titleSpacing: 0,
);
}
Widget buildBody(UserPresenter data) {
return RefreshIndicator(
onRefresh: data.refresh,
color: ThemeConfig.accentColor,
backgroundColor: Colors.white,
//onRefresh: _onPageRefresh,
displacement: 10,
child: CustomScrollView(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
slivers: [
SliverList(
delegate: SliverChildListDelegate([
buildTopSection(data),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0),
),
buildProfileForm(data)
]),
)
],
),
);
}
buildTopSection(UserPresenter data) {
log("Data.file is not empty${data.file?.path ?? "NO data"}");
log("User avatar ${SystemData.userInfo.avatar}");
return Column(
children: [
Padding(
padding: const EdgeInsets.only(top: 16.0, bottom: 8.0),
child: Stack(
children: [
data.file != null
? ImageView.roundFileImage(
file: File(data.file!.path),
height: 120.0,
width: 120.0,
context: context,
radius: 60)
: ImageView.round(
url: SystemData.userInfo.avatar,
height: 120.0,
width: 120.0,
context: context,
radius: 60),
/*
Container(
width: 120,
height: 120,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
border: Border.all(
color: Color.fromRGBO(112, 112, 112, .3), width: 2),
//shape: BoxShape.rectangle,
),
child: ClipRRect(
clipBehavior: Clip.hardEdge,
borderRadius: BorderRadius.all(Radius.circular(100.0)),
child: FadeInImage.assetNetwork(
placeholder: 'assets/placeholder.png',
image: "${avatar_original.$}",
fit: BoxFit.fill,
)),
),*/
Positioned(
right: 8,
bottom: 8,
child: SizedBox(
width: 24,
height: 24,
child: Button(
padding: const EdgeInsets.all(0),
shape: CircleBorder(
side: BorderSide(color: ThemeConfig.lightGrey),
),
color: ThemeConfig.lightGrey,
onPressed: () {
data.chooseAndUploadImage(context);
},
child: Icon(
Icons.edit,
color: ThemeConfig.fontColor,
size: 14,
),
),
),
)
],
),
),
],
);
}
buildProfileForm(UserPresenter data) {
return Padding(
padding:
const EdgeInsets.only(top: 8.0, bottom: 8.0, left: 16.0, right: 16.0),
child: Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
buildBasicInfo(data),
buildChangePassword(data),
],
),
),
);
}
Column buildChangePassword(UserPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 30.0, bottom: 10),
child: Text(
AppLang.local(context).password_change_ucf,
style: StyleConfig.fs14fwBold,
textHeightBehavior:
const TextHeightBehavior(applyHeightToFirstAscent: false),
textAlign: TextAlign.center,
softWrap: false,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).password,
style: TextStyle(
fontSize: 12,
color: ThemeConfig.fontColor,
fontWeight: FontWeight.normal),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Container(
decoration: BoxDecorations.basic(),
height: 36,
child: TextField(
style: const TextStyle(fontSize: 12),
controller: data.passwordController,
autofocus: false,
obscureText: !data.showPassword,
enableSuggestions: false,
autocorrect: false,
decoration:
InputDecorations.basic(hint_text: "• • • • • • • •")
.copyWith(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor),
),
suffixIcon: InkWell(
onTap: () {
data.passwordShowHide();
},
child: Icon(
data.showPassword
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
color: ThemeConfig.red,
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(top: 4.0),
child: Text(
AppLang.local(context).password_must_be_at_last_6_digit,
style: TextStyle(
color: ThemeConfig.red, fontStyle: FontStyle.italic),
),
)
],
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).confirm_password_ucf,
style: TextStyle(
fontSize: 12,
color: ThemeConfig.fontColor,
fontWeight: FontWeight.normal),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: Container(
decoration: BoxDecorations.basic(),
height: 36,
child: TextField(
controller: data.passwordConfirmController,
autofocus: false,
obscureText: !data.showConfirmPassword,
enableSuggestions: false,
autocorrect: false,
decoration:
InputDecorations.basic(hint_text: "• • • • • • • •").copyWith(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor),
),
suffixIcon: InkWell(
onTap: () {
data.conPasswordShowHide();
},
child: Icon(
data.showConfirmPassword
? Icons.visibility_outlined
: Icons.visibility_off_outlined,
color: ThemeConfig.red,
),
)),
),
),
),
Align(
alignment: Alignment.centerRight,
child: Container(
alignment: Alignment.center,
width: 150,
child: Button(
padding: const EdgeInsets.symmetric(vertical: 10),
minWidth: MediaQuery.of(context).size.width,
color: ThemeConfig.red,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
child: Text(
AppLang.local(context).update_password_ucf,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
data.onPressUpdatePassword(context);
},
),
),
),
],
);
}
Column buildBasicInfo(UserPresenter data) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 18.0),
child: Text(
AppLang.local(context).basic_info,
style: StyleConfig.fs14fwBold,
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).name,
style: TextStyle(
fontSize: 12,
color: ThemeConfig.fontColor,
fontWeight: FontWeight.normal),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 14.0),
child: Container(
decoration: BoxDecorations.basic(),
height: 36,
child: TextField(
controller: data.nameController,
autofocus: false,
style: TextStyle(color: ThemeConfig.fontColor, fontSize: 12),
decoration:
InputDecorations.basic(hint_text: "John Doe").copyWith(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.accentColor),
),
),
),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).phone,
style: TextStyle(
fontSize: 12,
color: ThemeConfig.fontColor,
fontWeight: FontWeight.normal),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 14.0),
child: Container(
decoration: BoxDecorations.basic(),
height: 36,
child: TextField(
controller: data.phoneController,
autofocus: false,
keyboardType: TextInputType.phone,
style: TextStyle(color: ThemeConfig.fontColor, fontSize: 12),
decoration:
InputDecorations.basic(hint_text: "+01xxxxxxxxxx").copyWith(
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(color: ThemeConfig.red),
),
),
),
),
),
Visibility(
visible: true,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: Text(
AppLang.local(context).name,
style: TextStyle(
fontSize: 12,
color: ThemeConfig.fontColor,
fontWeight: FontWeight.normal),
),
),
Padding(
padding: const EdgeInsets.only(bottom: 14.0),
child: Container(
decoration: BoxDecorations.basic(),
height: 36,
padding: const EdgeInsets.symmetric(horizontal: 16),
alignment: Alignment.centerLeft,
child: Text(
data.emailController.text,
style: TextStyle(fontSize: 12, color: ThemeConfig.grey),
)
/*TextField(
style: TextStyle(color:ThemeConfig.grey_153,fontSize: 12),
enabled: false,
enableIMEPersonalizedLearning: true,
controller: _emailController,
autofocus: false,
decoration: InputDecorations.buildInputDecoration_1(
hint_text: "jhon@example.com").copyWith(
//enabled: false,
labelStyle: TextStyle(color: ThemeConfig.grey_153),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide.none,
),),
),*/
),
),
],
),
),
Align(
alignment: Alignment.centerRight,
child: Container(
alignment: Alignment.center,
width: getWidth(context) / 2.5,
child: Button(
padding: const EdgeInsets.symmetric(vertical: 10),
minWidth: MediaQuery.of(context).size.width,
color: ThemeConfig.red,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(8.0))),
child: Text(
AppLang.local(context).update_profile_ucf,
style: const TextStyle(
color: Colors.white,
fontSize: 14,
fontWeight: FontWeight.w600),
),
onPressed: () {
data.onPressUpdate(context);
},
),
),
),
],
);
}
}

View File

@@ -0,0 +1,93 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/no_data.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/refund_presenter.dart';
import 'package:grostore/presenters/wallet_presenter.dart';
import 'package:provider/provider.dart';
class Refund extends StatefulWidget {
const Refund({super.key});
@override
State<Refund> createState() => _RefundState();
}
class _RefundState extends State<Refund> {
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
print("object11");
Provider.of<RefundPresenter>(context,listen: false).initState();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar.show(title: AppLang.local(context).refund_history_ucf, context: context),
body: Consumer<RefundPresenter>(
builder: (context,data,child) {
return RefreshIndicator(
onRefresh: data.onRefresh,
child: SingleChildScrollView(
physics: AlwaysScrollableScrollPhysics(),
child: data.isRefundInit && data.refundHistory.isEmpty?const NoData():data.isRefundInit?ListView.separated(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
itemBuilder: (context,index)=>Container(
padding: EdgeInsets.symmetric(horizontal: 14,vertical: 10),
decoration: BoxDecorations.shadow(radius: 10),
child: Row(
children: [
SizedBox(
width: getWidth(context)*0.4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(data.refundHistory[index].date),
SizedBox(height: 8,),
Text(data.refundHistory[index].orderCode),
SizedBox(height: 8,),
Text(data.refundHistory[index].productName),
],
),
),
Spacer(),
SizedBox(
width: getWidth(context)*0.4,
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Text(data.refundHistory[index].status.toUpperCase(),style: StyleConfig.fs14cSecondryfwBold.copyWith(color: data.refundHistory[index].status=="refunded"?ThemeConfig.fontColor:null),),
SizedBox(height: 8,),
Text(showPrice(data.refundHistory[index].amount),style: StyleConfig.fs14fwNormal),
],
),
),
],
),
),
separatorBuilder: (context,index)=>SizedBox(height: StyleConfig.padding,), itemCount: data.refundHistory.length):
Padding(padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Shimmers.list(15, getWidth(context), 55.0),
),
),
);
}
),
);
}
}

View File

@@ -0,0 +1,154 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/models/currency_response.dart';
import 'package:grostore/models/language_response.dart';
import 'package:grostore/presenters/setting_presenter.dart';
import 'package:http/http.dart';
import 'package:provider/provider.dart';
import '../presenters/bloc/lang/lang_bloc.dart';
class Setting extends StatefulWidget {
const Setting({super.key});
@override
State<Setting> createState() => _SettingState();
}
class _SettingState extends State<Setting> {
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<SettingPresenter>(context, listen: false).initState();
});
// TODO: implement initState
super.initState();
}
String datas = "uz";
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: ThemeConfig.xxlightGrey,
appBar: CommonAppbar.show(
title: AppLang.local(context).settings, context: context),
body: Consumer<SettingPresenter>(builder: (context, data, child) {
return Container(
padding: EdgeInsets.symmetric(
horizontal: StyleConfig.padding,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(
height: 20,
),
/* DropdownButton<LanguageInfo>(
value: data.selectedLanguage,
icon: const Icon(Icons.arrow_downward),
elevation: 16,
style: const TextStyle(color: Colors.deepPurple),
underline: Container(
height: 2,
color: Colors.deepPurpleAccent,
),
onChanged: (LanguageInfo? value) {
// This is called when the user selects an item.
if(value!=null) {
data.setLocale(value);
}
},
items: data.languageList.map<DropdownMenuItem<LanguageInfo>>((LanguageInfo value) {
return DropdownMenuItem<LanguageInfo>(
value: value,
child: Text(value.name),
);
}).toList(),
),*/
Text(
AppLang.local(context).currency,
style: StyleConfig.fs14fwBold,
),
const SizedBox(
height: 14,
),
Container(
width: getWidth(context),
padding: const EdgeInsets.symmetric(horizontal: 14),
decoration: BoxDecorations.customRadius(
radius: BorderRadius.circular(5))
.copyWith(
color: ThemeConfig.white,
),
child: DropdownButton<CurrencyInfo>(
isExpanded: true,
value: data.selectedCurrency,
elevation: 16,
underline: const SizedBox.shrink(),
style: const TextStyle(color: Colors.deepPurple),
onChanged: (CurrencyInfo? value) {
// This is called when the user selects an item.
if (value != null) {
data.onChange(value);
}
},
items: data.currencyList.map<DropdownMenuItem<CurrencyInfo>>(
(CurrencyInfo value) {
return DropdownMenuItem<CurrencyInfo>(
value: value,
child: Row(
children: [
Text(
value.name,
style: StyleConfig.fs14fwNormal,
),
],
),
);
}).toList(),
),
),
SizedBox(height: 10,),
// BlocBuilder<LangBloc, LangState>(
// builder: (context, state) {
// return Container(
// height: 100,
// margin: const EdgeInsets.only(top: 20),
// width: getWidth(context),
// padding: const EdgeInsets.symmetric(horizontal: 14),
// decoration: BoxDecoration(
// color: Colors.white,
// borderRadius: BorderRadius.all(Radius.circular(10)),
// ),
// child: DropdownButton<String>(
// value: datas ?? "uz",
// icon: Icon(Icons.arrow_drop_down_rounded),
// style: const TextStyle(color: Colors.deepPurple),
// onChanged: (String? value) {
// datas = value ?? "uz";
// context
// .read<LangBloc>()
// .add(LanguageEvent(locale: Locale(datas)));
// },
// items: const [
// DropdownMenuItem<String>(value: "uz", child: Text("Uz")),
// DropdownMenuItem<String>(value: 'en', child: Text("En")),
// DropdownMenuItem<String>(value: "ru", child: Text("Ru")),
// ]));
// },
// )
],
),
);
}),
);
}
}

View File

@@ -0,0 +1,109 @@
import 'package:flutter/material.dart';
import 'package:grostore/apis/auth_api.dart';
import 'package:grostore/apis/setting_api.dart';
import 'package:grostore/configs/app_config.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/helpers/common_functions.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/route.dart';
import 'package:grostore/helpers/shared_value_helper.dart';
import 'package:grostore/presenters/auth/auth_presenter.dart';
import 'package:grostore/presenters/cart_presenter.dart';
import 'package:grostore/presenters/setting_presenter.dart';
import 'package:grostore/screens/landing_pages/landing_page.dart';
import 'package:grostore/screens/main.dart';
import 'package:provider/provider.dart';
class Splash extends StatefulWidget {
const Splash({Key? key}) : super(key: key);
@override
State<Splash> createState() => _SplashState();
}
class _SplashState extends State<Splash> {
@override
void initState() {
super.initState();
getSettings();
system_currency.load().then((value){
Provider.of<SettingPresenter>(context, listen: false).initState();
});
Future.delayed(const Duration(seconds: 2)).then((value) {
access_token.load();
show_landing_page.load().then((value) {
checkLogin();
});
//Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (context)=>Main()), (route) => false);
});
}
checkLogin() async {
await show_landing_page.load();
var res = await AuthApi.tokenCheck(context);
print("-----}${res.result}{----");
if (res.result) {
SystemData.isLogIn = true;
SystemData.userInfo = res.user;
await app_language.load();
await stock_location_id.load();
Provider.of<CartPresenter>(context, listen: false).fetchCart();
}
if (show_landing_page.$) {
show_landing_page.$=false;
show_landing_page.save();
MakeRoute.goAndRemoveAll(context, const LandingPage());
} else {
Provider.of<AuthPresenter>(context,listen: false).tokenCheck(context);
MakeRoute.goAndRemoveAll(context, const Main());
}
}
getSettings() async {
var res = await SettingApi.getSettings();
SystemData.settings = res.object;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
width: getWidth(context),
height: getHeight(context),
decoration: BoxDecoration(
color: ThemeConfig.splashBackground,
image: DecorationImage(
image: AssetImage(getAssetImage("splash_background.png")))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
getAssetLogo("logo4x4.png"),
width: 250,
height: 300,
),
// const SizedBox(
// height: 10,
// ),
// Text(
// AppConfig.appName,
// style: StyleConfig.fs30fwEBold(),
// textAlign: TextAlign.center,
// ),
const SizedBox(
height: 10,
),
const CircularProgressIndicator()
],
),
),
);
}
}

View File

@@ -0,0 +1,174 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Boxdecorations.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/helpers/shared_value_helper.dart';
import 'package:grostore/presenters/stock_locations_presenter.dart';
import 'package:toast/toast.dart';
import 'package:provider/provider.dart';
class StockLocations extends StatefulWidget {
StockLocations({Key? key}) : super(key: key);
@override
_StockLocationsState createState() => _StockLocationsState();
}
class _StockLocationsState extends State<StockLocations> {
@override
void initState() {
// TODO: implement initState
super.initState();
Provider.of<StockLocationsPresenter>(context,listen: false).setContext(context);
}
@override
void dispose() {
super.dispose();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: buildAppBar(context),
body: Consumer<StockLocationsPresenter>(
builder: (context,data,child) {
return RefreshIndicator(
//color: MyTheme.accent_color,
backgroundColor: Colors.white,
onRefresh: data.onRefresh,
displacement: 0,
child: CustomScrollView(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics()),
slivers: [
SliverList(
delegate: SliverChildListDelegate([
Padding(
padding: const EdgeInsets.all(18.0),
child: buildLanguageMethodList(data),
),
]),
)
],
),
);
}
));
}
AppBar buildAppBar(BuildContext context) {
return CommonAppbar.show(title: AppLang.local(context).locations, context: context);
}
buildLanguageMethodList(StockLocationsPresenter data) {
if (!data.isLocationInit && data.locations.isEmpty) {
return SingleChildScrollView(
child: Shimmers.list(10, getWidth(context), 20));
} else if (data.locations.isNotEmpty) {
return SingleChildScrollView(
child: ListView.separated(
separatorBuilder: (context, index) {
return const SizedBox(
height: 14,
);
},
itemCount: data.locations.length,
scrollDirection: Axis.vertical,
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemBuilder: (context, index) {
return buildCard(index,data);
},
),
);
} else if (data.isLocationInit && data.locations.isEmpty) {
return Container(
height: 100,
child: Center(
child: Text(
AppLang.local(context).data_is_not_available,
style: TextStyle(color: ThemeConfig.fontColor),
)));
}
}
GestureDetector buildCard(index,StockLocationsPresenter data) {
return GestureDetector(
onTap: () {
print(data.locations[index].id);
data.onchange(data.locations[index].id);
},
child: Stack(
children: [
AnimatedContainer(
duration: const Duration(milliseconds: 400),
decoration: BoxDecorations.basic().copyWith(
border: Border.all(
color: stock_location_id.$ == data.locations[index].id.toString()
? ThemeConfig.accentColor: ThemeConfig.lightGrey,
width: stock_location_id.$ == data.locations[index].id.toString() ? 1.0 : 0.0)),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: 150,
height: 50,
alignment: Alignment.center,
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
"${data.locations[index].name}",
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
style: TextStyle(
color: ThemeConfig.fontColor,
fontSize: 14,
height: 1.6,
fontWeight: FontWeight.bold),
),
),
),
]),
),
// Positioned(
// left: 16,
// top: 16,
// child: buildCheckContainer(data.selectedIndex == index),
// )
],
),
);
}
// Container buildCheckContainer(bool check) {
// return check
// ? Container(
// height: 16,
// width: 16,
// decoration: BoxDecoration(
// borderRadius: BorderRadius.circular(16.0), color: Colors.green),
// child: Padding(
// padding: const EdgeInsets.all(3),
// child: Icon(Icons.check, color: Colors.white, size: 10),
// ),
// )
// : Container();
// }
}

View File

@@ -0,0 +1,186 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_classes/system_data.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/input_decorations.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/order_presenter.dart';
class TrackOrder extends StatefulWidget {
const TrackOrder({super.key});
@override
State<TrackOrder> createState() => _TrackOrderState();
}
class _TrackOrderState extends State<TrackOrder> {
OrderPresenter orderPresenter = OrderPresenter();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar.show(
title: AppLang.local(context).track_my_order_ucf, context: context),
body: ListenableBuilder(
listenable: orderPresenter,
builder: (context, child) {
return Container(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Column(
children: [
Container(
decoration: BoxDecorations.shadow(),
child: Row(
children: [
Container(
decoration: BoxDecoration(
color: ThemeConfig.grey,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(6),
bottomLeft: Radius.circular(6),
)),
padding: const EdgeInsets.symmetric(
horizontal: 10, vertical: 10),
child:
Text(SystemData.settings?.orderCodePrefix ?? ""),
),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6),
width: getWidth(context) * 0.5,
child: TextField(
onSubmitted: (text) {
orderPresenter.trackOrder(text.trim(), context);
},
controller: orderPresenter.trackOrderController,
decoration: const InputDecoration.collapsed(
hintText: "123456")),
),
Spacer(),
SizedBox(
width: 40,
height: 40,
child: Button(
onPressed: () {
orderPresenter.trackOrder(
orderPresenter.trackOrderController.text
.trim(),
context);
},
child: Icon(Icons.search))),
],
),
),
SizedBox(height: 24,),
if(orderPresenter.trackInfo!=null)
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(AppLang.local(context).order_tracking,style: StyleConfig.fs16fwBold,),
SizedBox(height: 14,),
Container(
decoration: BoxDecorations.shadow(radius: 5)
.copyWith(border: Border.all(color: ThemeConfig.grey)),
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0,vertical: 8),
child: Row(
children: [
SizedBox(
width: getWidth(context) * 0.25,
child: Text(
AppLang.local(context).date,
style: StyleConfig.fs14fwBold,
)),
SizedBox(
width: getWidth(context) * 0.55,
child: Text(
AppLang.local(context).note,
style: StyleConfig.fs14fwBold,
)),
],
),
),
Container(
width: getWidth(context),
height: 1,
color: ThemeConfig.grey,
),
Column(
children: List.generate(
orderPresenter.trackInfo?.orderUpdates.length ?? 0,
(index) => Column(
children: [
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: [
SizedBox(
width: getWidth(context) * 0.25,
child: Text(orderPresenter.trackInfo
?.orderUpdates[index].date ??
"")),
SizedBox(
width: getWidth(context) * 0.55,
child: Text(orderPresenter.trackInfo
?.orderUpdates[index].note ??
"")),
],
),
),
SizedBox(
height: 10,
),
Container(
width: getWidth(context),
height: 1,
color: ThemeConfig.grey,
),
],
),
),
),
Column(
children: [
SizedBox(
height: 10,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Row(
children: [
SizedBox(
width: getWidth(context) * 0.25,
child: Text(orderPresenter.trackInfo?.createdDate ??
"")),
SizedBox(
width: getWidth(context) * 0.55,
child: Text(AppLang.local(context).order_has_been_placed)),
],
),
),
SizedBox(
height: 10,
),
],
),
],
),
),
],
)
],
),
);
}),
);
}
}

View File

@@ -0,0 +1,81 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/custom_ui/BoxDecorations.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/helpers/device_info_helper.dart';
import 'package:grostore/presenters/wallet_presenter.dart';
import 'package:provider/provider.dart';
class Wallet extends StatefulWidget {
const Wallet({super.key});
@override
State<Wallet> createState() => _WalletState();
}
class _WalletState extends State<Wallet> {
@override
void initState() {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
Provider.of<WalletPresenter>(context,listen: false).initState();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CommonAppbar.show(title: AppLang.local(context).wallet_history_ucf, context: context),
body: Consumer<WalletPresenter>(
builder: (context,data,child) {
return RefreshIndicator(
onRefresh: data.onRefresh,
child: SingleChildScrollView(
physics: const AlwaysScrollableScrollPhysics(),
child: data.isWalletInit && data.walletHistory.isEmpty?
SizedBox(
height: getHeight(context),
child: Center(
child: Text(AppLang.local(context).data_is_not_available),
),
)
: data.isWalletInit?
ListView.separated(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
itemBuilder: (context,index)=>Container(
padding: const EdgeInsets.symmetric(horizontal: 14,vertical: 10),
decoration: BoxDecorations.shadow(radius: 10),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(data.walletHistory[index].date),
const SizedBox(height: 8,),
Text(data.walletHistory[index].paymentMethod),
],
),
const Spacer(),
Text(data.walletHistory[index].amount,style: StyleConfig.fs14cSecondryfwBold,),
],
),
),
separatorBuilder: (context,index)=>SizedBox(height: StyleConfig.padding,), itemCount: data.walletHistory.length):
Padding(padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding),
child: Shimmers.list(15, getWidth(context), 55.0),
),
),
);
}
),
);
}
}

View File

@@ -0,0 +1,90 @@
import 'package:flutter/material.dart';
import 'package:grostore/app_lang.dart';
import 'package:grostore/configs/style_config.dart';
import 'package:grostore/configs/theme_config.dart';
import 'package:grostore/custom_ui/Button.dart';
import 'package:grostore/custom_ui/common_appbar.dart';
import 'package:grostore/custom_ui/shimmers.dart';
import 'package:grostore/presenters/wishlist_presenter.dart';
import 'package:provider/provider.dart';
import '../custom_ui/product_card.dart';
class Wishlist extends StatefulWidget {
const Wishlist({Key? key}) : super(key: key);
@override
State<Wishlist> createState() => _WishlistState();
}
class _WishlistState extends State<Wishlist> {
WishlistPresenter data = WishlistPresenter();
@override
void initState() {
// TODO: implement initState
Provider.of<WishlistPresenter>(context,listen: false).setContext(context);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
// Provider.of<WishlistPresenter>(context,listen: false).initState();
data.initState();
});
super.initState();
}
@override
Widget build(BuildContext context) {
return
Scaffold(
appBar: CommonAppbar.show(title: AppLang.local(context).wishlist, context: context),
body: ListenableBuilder(
listenable: data,
builder: (context,child) {
return Container(
child: data.isWishlistInit?buildProductSection():Shimmers.gridShimmer(2, 10),
);
}
),
);
}
Widget buildProductSection(){
return RefreshIndicator(
onRefresh: data.reFresh,
child: GridView.builder(
padding: EdgeInsets.symmetric(horizontal: StyleConfig.padding,vertical: StyleConfig.smSectionSpacer),
physics: const AlwaysScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 16,
mainAxisSpacing: 16,
childAspectRatio: 0.8),
itemCount: data.wishlists.length,
itemBuilder: (context, index) {
return Stack(
fit: StackFit.expand,
children: [
ProductCard(
product: data.wishlists[index].product,context: this.context,),
Positioned(
right: 0,
top: 0,
child: Button(
shape: StyleConfig.buttonRadius(25),
color: ThemeConfig.lightGrey,
onPressed: (){
data.deleteWishlist(data.wishlists[index].product.id,context);
},
minWidth: 10.0,
minHeight: 10.0,
padding: const EdgeInsets.all(5),
child: const Icon(Icons.delete,size: 24,color: Colors.red,),
),
)
],
);
}),
);
}
}