initial commit to gitea

This commit is contained in:
2022-03-10 00:47:26 -05:00
parent 808ffa3211
commit f504e213a0
93 changed files with 4394 additions and 1539 deletions

View File

@@ -0,0 +1,464 @@
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../generated/l10n.dart';
import '../../models/group.dart';
import '../../pages/buy_service.dart';
import '../../routes.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
class CreateOnlineStore1 extends StatefulWidget {
final int businessId;
const CreateOnlineStore1(this.businessId, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return CreateOnlineStore1State();
}
}
class CreateOnlineStore1State extends State<CreateOnlineStore1> {
double sideSpace = 0;
double mainSpace = 1200;
TextEditingController groupNumberController = TextEditingController();
TextEditingController domainController = TextEditingController();
bool canSubmit = false;
List<dynamic> stores = [];
Map<String, dynamic> service;
dynamic selectedStore;
Group group;
String selectedDomain;
List<dynamic> domainResult = [];
@override
Widget build(BuildContext context) {
if (MediaQuery
.of(context)
.size
.width <= 1200) {
mainSpace = MediaQuery
.of(context)
.size
.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery
.of(context)
.size
.width - 1200) / 2;
}
Row row = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
row.children.add(
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 16.0, right: 16.0, top: 20, bottom: 20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(bottom: 4.0),
child: Text(
S.of(context).open_online_store,
style: TextStyle(
fontSize: 28,
),
),
),
Container(
padding: EdgeInsets.only(top: 4, bottom: 4),
child: Text(
S.of(context)
.select_a_store,
style: TextStyle(
color: Colors.black45,
),
),
),
Container(
padding: EdgeInsets.only(top: 4),
child: DropdownButton<dynamic>(
items: stores.map((e) => DropdownMenuItem<dynamic>(
value: e,
child: Text(e['name']),
)).toList(),
isExpanded: false,
hint: Text(S.of(context).select_a_store),
onChanged: (newValue) {
print('newValue $newValue');
setState(() {
selectedStore = newValue;
});
},
value: selectedStore,
),
),
],
),
decoration: BoxDecoration(
border: Border(
right: BorderSide(
width: 1,
color: Colors.black12,
),
),
),
),
),
);
row.children.add(
Expanded(
child: Container(
padding: EdgeInsets.only(
left: 16.0, right: 16.0, top: 20, bottom: 20),
child: Visibility(
child: getSearchDomainWidget(),
visible: selectedStore != null,
),
),
),
);
return Scaffold(
appBar: MiniNavigationBar(
title: S
.of(context)
.blog,
back: true,
breadCrumbs: [
BreadCrumb(S
.of(context)
.open_online_store, null),
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
),
body: SingleChildScrollView(
child: Row(
children: [
Container(
width: sideSpace,
),
Expanded(child: row,),
Container(
width: sideSpace,
),
],
),
),
bottomNavigationBar: BottomNav(),
);
}
Widget getSearchDomainWidget() {
if (selectedStore == null) {
return SizedBox.shrink();
}
Column col = Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
col.children.add(
Container(
padding: EdgeInsets.only(bottom: 4,),
child: Text(selectedStore == null ? '' : selectedStore['name'],
style: TextStyle(
fontSize: 28,
),
),
),
);
Map<String, dynamic> existing_web_svc;
if (selectedStore != null && (selectedStore['services'] as List).length > 0) {
for (Map<String, dynamic>svc in (selectedStore['services'] as List)) {
if (svc['code'] == Constants.WEB_MINISTORE_SERVICE) {
existing_web_svc = svc;
break;
}
}
}
if (existing_web_svc != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'${existing_web_svc['description']}',
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).expiration_date + ": "
+ Utils.utcDatetimeStringToLocalDatetimeString(context, existing_web_svc['expiration_date']),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).store + ": " + '${existing_web_svc['store']['name']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).domain_name + ": " + '${existing_web_svc['domain']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(S.of(context).renew_service_now),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: existing_web_svc['domain'],
sid: existing_web_svc['store']['id'],
),
));
},
),
),
);
} else {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(S.of(context).enter_desired_domain),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 0,),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: TextFormField(
controller: domainController,
decoration: new InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black12,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
labelText: S.of(context).domains_separated_comma,
),
style: TextStyle(
fontSize: 18.0
),
autofocus: true,
validator: (String value) {
if (value.trim().isEmpty) {
return S.of(context).domains_separated_comma;
}
return null;
},
onChanged: (string) {
if (string.isNotEmpty) {
canSubmit = true;
} else {
canSubmit = false;
}
setState(() {});
},
),
),
Container(
padding: EdgeInsets.only(left: 8.0),
child: ElevatedButton(
child: Text(
S.of(context).check_domain_name,
),
onPressed: domainController.text.length > 0 ? checkDomainAvailability : null,
),
),
],
),
)
);
if (domainResult.length > 0) {
for (dynamic dr in domainResult) {
col.children.add(_getDomain(dr));
}
}
if (selectedDomain != null && service != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['description'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['options'][0]['name'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'\$${service['options'][0]['price']}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.orange,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(
S.of(context).place_order_now,
),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: selectedDomain,
sid: selectedStore['id'],
),
));
},
),
),
);
}
}
return Container(
padding: EdgeInsets.only(bottom: 4,),
child: col,
);
}
@override
void initState() {
super.initState();
HttpUtil.httpGet(
'v1/get-contact-stores',
queryParameters: {
'service': Constants.WEB_MINISTORE_SERVICE
}
).then((value) {
setState(() {
stores = value['stores'];
service = value['service'];
group = Group.fromJson(value['group']);
print('stores: ${value}');
});
}).onError((error, stackTrace) {
Utils.showMessageDialog(context, error, onOk: () {
Routes.router.navigateTo(context, '/');
});
});
}
Future<void> checkDomainAvailability() async {
Utils.showLoadingDialog(context);
selectedDomain = null;
domainResult = [];
setState(() {});
HttpUtil.httpGet(
'v1/check-domain-availability',
queryParameters: {
'domain': domainController.text,
},
).then((value) {
Routes.router.pop(context);
print('value: $value');
if (value['status'] == 'OK') {
domainResult = (value['domain_check_result'] as List);
setState(() {});
} else if (value['status'] == 'ERROR') {
String errors = '';
for (int i = 0; i < (value['errors'] as List).length; i++) {
errors += value['errors'][i] + '\n';
}
Utils.showMessageDialog(context, errors);
}
}).onError((error, stackTrace) {
Routes.router.pop(context);
Utils.showMessageDialog(context, error);
});
}
Widget _getDomain(dynamic d) {
if ((d['available'] as bool)) {
return Container(
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
leading: Radio(
value: d['domain'],
groupValue: selectedDomain,
onChanged: (val) {
setState(() {
selectedDomain = val;
});
},
),
),
);
} else {
return Container(
padding: EdgeInsets.only(top: 1.0),
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
color: Colors.black45,
),
),
leading: Icon(Icons.clear, color: Colors.red,),
),
);
}
}
}

View File

@@ -39,7 +39,8 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).home,
'/',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/',
clearStack: true,
),
@@ -47,14 +48,16 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).download,
'/download',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/download',
),
SizedBox(width: 15.0,),
TextLink(
S.of(context).tutorials,
Constants.TUTORIAL_URL,
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/tutorials',
isLink: true,
),
@@ -62,21 +65,24 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).support,
'/my-support/${Constants.BUSINESS_ID}',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/my-support/${Constants.BUSINESS_ID}',
),
SizedBox(width: 15.0,),
TextLink(
S.of(context).shop,
'/shop',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/shop',
),
SizedBox(width: 15.0,),
TextLink(
S.of(context).blog,
'/blog/${Constants.BUSINESS_ID}',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/blog/${Constants.BUSINESS_ID}',
),
SizedBox(width: 15.0,),
@@ -126,7 +132,8 @@ class DesktopAppBarMenu extends StatelessWidget {
TextLink(
S.of(context).login,
'/login',
color: Colors.white,
color: Colors.white60,
hoverColor: Colors.white,
selected: currentRoute == '/login',
),
],

View File

@@ -85,7 +85,7 @@ class DesktopBlogState extends State<DesktopBlog> {
BuildContext mainContext = context;
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [
@@ -272,6 +272,7 @@ class DesktopBlogState extends State<DesktopBlog> {
'size': Constants.BLOG_PER_PAGE_DESKTOP.toString()
}
).then((value) {
print('value: $value');
if (mounted) {
if (isRefresh) {
_refreshController.refreshCompleted();

View File

@@ -72,6 +72,18 @@ class DesktopBuyServiceState extends State<DesktopBuyService> {
Utils.buildLine(S.of(context).your_group, widget.data['group']['name'], valueSize: 16),
);
if (widget.data['store']['id'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).store, widget.data['store']['name'], valueSize: 16),
);
}
if (widget.data['domain'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).domain_name, widget.data['domain'], valueSize: 16),
);
}
if (widget.data['exists_service'] == null) {
col1.children.add(
Utils.buildLine(S.of(context).current_plan, 'N/A', valueSize: 16),
@@ -171,7 +183,7 @@ class DesktopBuyServiceState extends State<DesktopBuyService> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -178,7 +178,7 @@ class DesktopCheckoutState extends State<DesktopCheckout> with SingleTickerProvi
Scaffold scaffold = Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [
@@ -355,6 +355,7 @@ class DesktopCheckoutState extends State<DesktopCheckout> with SingleTickerProvi
check();
},
initialLabelIndex: deliveryMethodIndex,
totalSwitches: shippingMethodLabels.length,
);
switch (position) {
case 0:

View File

@@ -329,7 +329,7 @@ class DesktopContactUsState extends State<DesktopContactUs> {
);
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -78,7 +78,7 @@ class DesktopCouponsState extends State<DesktopCoupons> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -399,7 +399,7 @@ class DesktopEditAddressState extends State<DesktopEditAddress> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).edit_address,
back: true,
breadCrumbs: [

View File

@@ -101,7 +101,8 @@ class DesktopIndexMainContent3State extends State<DesktopIndexMainContent3> {
TextLink(S.of(context).support_ticket, '/my-support/${Constants.BUSINESS_ID}', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0,)
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0,),
TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 10.0,)
],
),
),
@@ -250,7 +251,8 @@ class DesktopIndexMainContent3State extends State<DesktopIndexMainContent3> {
TextLink(S.of(context).support_ticket, '/my-support/${Constants.BUSINESS_ID}', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 0.0,)
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 0.0,),
TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 0.0,)
],
),
),

View File

@@ -63,7 +63,7 @@ class DesktopMyAddressesState extends State<DesktopMyAddresses> {
BuildContext mainContext = context;
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).my_addresses,
back: true,
breadCrumbs: [

View File

@@ -48,7 +48,7 @@ class MyCardsState extends State<DesktopMyCards> {
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -88,7 +88,7 @@ class DesktopMySupportState extends State<DesktopMySupport> {
BuildContext mainContext = context;
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).my_support,
back: true,
breadCrumbs: [

View File

@@ -2,28 +2,25 @@
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_wisetronic/widgets/desktop/desktop_appbar_menu.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../constants.dart';
import '../../dialog/logout_dialog.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/user.dart';
import '../../routes.dart';
import '../../store/store.dart';
import '../../utils/utils.dart';
import '../../widgets/general/navigationbar_logo.dart';
import '../../widgets/general/text_link.dart';
import '../../widgets/desktop/desktop_appbar_menu.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
class DesktopNavigationBar extends StatefulWidget {
final bool hasBack;
final List<BreadCrumb> breadCrumbs;
final Widget shoppingCart;
final OnBackPress onBackPress;
const DesktopNavigationBar({Key key, this.hasBack, this.breadCrumbs,
this.shoppingCart}) : super(key: key);
this.shoppingCart, this.onBackPress}) : super(key: key);
@override
State<StatefulWidget> createState() {
@@ -37,132 +34,6 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
@override
Widget build(BuildContext context) {
// String currentRoute = ModalRoute.of(context).settings.name;
// Stack stack = Stack(
// children: [
// Container(
// color: Colors.blue,
// height: 80.0,
// ),
// Container(
// height: 80.0,
// padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 5.0, bottom: 5.0),
// child: Row(
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
// children: [
// NavigationBarLogo(),
// Expanded(
// child: Container(
// alignment: Alignment.centerRight,
// padding: EdgeInsets.only(left: 8.0, right: 16.0),
// child: SingleChildScrollView(
// scrollDirection: Axis.horizontal,
// child: Row(
// mainAxisSize: MainAxisSize.min,
// children: [
// SizedBox(width: 20.0,),
// TextLink(
// S.of(context).home,
// '/',
// color: Colors.white,
// selected: currentRoute == '/',
// clearStack: true,
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).download,
// '/download',
// color: Colors.white,
// selected: currentRoute == '/download',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).tutorials,
// '/tutorials',
// color: Colors.white,
// selected: currentRoute == '/tutorials',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).support,
// '/my-support/${Constants.BUSINESS_ID}',
// color: Colors.white,
// selected: currentRoute == '/my-support/${Constants.BUSINESS_ID}',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).shop,
// '/shop',
// color: Colors.white,
// selected: currentRoute == '/shop',
// ),
// SizedBox(width: 15.0,),
// TextLink(
// S.of(context).blog,
// '/blog/${Constants.BUSINESS_ID}',
// color: Colors.white,
// selected: currentRoute == '/blog/${Constants.BUSINESS_ID}',
// ),
// SizedBox(width: 15.0,),
// _user != null ?
// (currentRoute == '/me') ?
// MouseRegion(
// cursor: SystemMouseCursors.click,
// child: GestureDetector(
// child: Row(
// mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.start,
// children: [
// Container(
// padding: EdgeInsets.only(right: 4.0),
// child: Text(
// S.of(context).logout,
// style: TextStyle(
// color: Colors.white,
// ),
// ),
// ),
// Icon(
// Icons.logout,
// color: Colors.white,
// size: 16.0,
// )
// ],
// ),
// onTap: () {
// showDialog(
// context: context,
// builder: (BuildContext context) {
// return logoutDialog(context);
// }
// );
// },
// ),
// ) : IconButton(
// icon: Icon(
// Icons.account_circle,
// color: Colors.white,
// ),
// onPressed: () {
// Routes.router.navigateTo(context, '/me');
// },
// ) :
// TextLink(
// S.of(context).login,
// '/login',
// color: Colors.white,
// selected: currentRoute == '/login',
// ),
// ],
// ),
// ),
// ),
// ),
// ],
// ),
// ),
// ],
// );
Widget sc = SizedBox.shrink();
if (widget.shoppingCart != null) {
sc = widget.shoppingCart;
@@ -171,8 +42,8 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
if (widget.breadCrumbs != null && widget.breadCrumbs.length > 0) {
breadCrumbBar = Container(
width: MediaQuery.of(context).size.width,
height: 38.0,
color: Color(0xFF4FB0C6),
height: Constants.BREADCRUMB_HEIGHT,
padding: EdgeInsets.only(top: 6.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -180,6 +51,7 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
Expanded(
child: BreadCrumbs(
widget.hasBack ?? false,
onBackPress: widget.onBackPress,
breadCrumbs: widget.breadCrumbs,
),
),
@@ -189,14 +61,18 @@ class DesktopNavigationBarState extends State<DesktopNavigationBar> {
),
],
),
decoration: BoxDecoration(
color: Colors.black12,
border: Border(
bottom: BorderSide(
width: 1.0,
color: Colors.black26,
),
),
),
);
}
// stack.children.add(
// Positioned(
// top: 90.0,
// child: breadCrumbBar,
// ),
// );
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -324,7 +324,7 @@ class DesktopNewAddressState extends State<DesktopNewAddress> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).new_address,
back: true,
breadCrumbs: [

View File

@@ -62,7 +62,7 @@ class DesktopNewCommentState extends State<DesktopNewComment> {
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).new_comment,
back: true,
breadCrumbs: [

View File

@@ -958,7 +958,7 @@ class DesktopOrderDetailState extends State<DesktopOrderDetail> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -98,7 +98,7 @@ class DesktopOrdersState extends State<DesktopOrders> with SingleTickerProviderS
return Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -345,7 +345,7 @@ class DesktopPayNowState extends State<DesktopPayNow> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -60,7 +60,7 @@ class DesktopPlainPageState extends State<DesktopPlainPage> {
));
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -79,7 +79,7 @@ class DesktopProductDetailPageState extends State<DesktopProductDetailPage>
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).shop,
back: true,
breadCrumbs: [

View File

@@ -167,7 +167,7 @@ class DesktopRenewLicenseState extends State<DesktopRenewLicense> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -136,7 +136,7 @@ class DesktopRenewMiniOfficeState extends State<DesktopRenewMiniOffice> {
);
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -45,7 +45,7 @@ class DesktopSearchPlaceState extends State<DesktopSearchPlace> {
}
return Scaffold(
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).search_place,
back: true,
breadCrumbs: [

View File

@@ -288,7 +288,7 @@ class DesktopSetPasswordState extends State<DesktopSetPassword> {
);
},
queryParameters: {
'action': 'reset_password',
'action': 'create_user',
},
isFormData: true,
body: {

View File

@@ -109,7 +109,7 @@ class DesktopStripePayWebState extends State<DesktopStripePayWeb> {
return Scaffold(
key: _scaffoldKey,
appBar: NavigationBar(
appBar: MiniNavigationBar(
title: S.of(context).blog,
back: true,
breadCrumbs: [

View File

@@ -1,127 +0,0 @@
import '../../constants.dart';
import '../../utils/iframe_web.dart' if (dart.library.io) '../../utils/fake_iframe_web.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class DesktopTutorials extends StatefulWidget {
const DesktopTutorials({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return DesktopTutorialsState();
}
}
class DesktopTutorialsState extends State<DesktopTutorials> {
double sideSpace = 0;
double mainSpace = 1200;
InAppWebViewController webView;
String url = "";
double progress = 0;
bool isLoadStop = false;
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
if (kIsWeb) {
return Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: IFrameWeb(
width: double.maxFinite.toString(),
height: double.maxFinite.toString(),
src: Constants.TUTORIAL_URL,
),
),
],
),
),
Container(
width: sideSpace,
),
],
);
} else {
print('progress: $progress');
return Stack(
children: [
Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse(Constants.TUTORIAL_URL)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (controller, url) {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = false;
});
}
},
onLoadStop: (controller, url) async {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = true;
});
}
},
onProgressChanged: (InAppWebViewController controller, int progress) {
if (mounted) {
setState(() {
if (this.progress < 1.0) {
this.isLoadStop = false;
} else {
this.isLoadStop = true;
}
this.progress = progress / 100;
});
}
},
),
),
Container(
width: sideSpace,
),
],
),
isLoadStop ? Container() :
Center(
child: CircularProgressIndicator(),
),
],
);
}
}
}

View File

@@ -13,6 +13,8 @@ import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
class DesktopViewBlog extends StatefulWidget {
final Key key;
final int bid;
@@ -172,11 +174,7 @@ class DesktopViewBlogState extends State<DesktopViewBlog> {
: Container(
width: mainSpace / 2 - 100.0,
height: mainSpace / 2 - 100.0,
child: PhotoView(
imageProvider: NetworkImage(
'https:${blog.imageUrl}',
),
),
child: Util.showImage('https:${blog.imageUrl}'),
),
),
],

View File

@@ -0,0 +1,280 @@
import 'package:flutter/material.dart';
import 'package:hovering/hovering.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/show_price.dart';
class ProductItem extends StatefulWidget {
final Business business;
final Product product;
final bool horizontal;
const ProductItem(this.product, this.business, {Key key, this.horizontal = false}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductItemState();
}
class ProductItemState extends State<ProductItem> {
@override
Widget build(BuildContext context) {
return HoverWidget(
child: Container(
width: 160.0,
height: widget.horizontal ? 160 : 268.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
bottom: new BorderSide(
color: new Color(0xFFEBEBEB),
),
),
),
child: new SizedBox.expand(
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0),
child: widget.horizontal ? getHorizontal(false) : getVertial(false),
),
),
),
hoverChild: Container(
width: 160.0,
height: widget.horizontal ? 160 : 268.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
top: new BorderSide(
color: new Color(0xFFEBEBEB),
),
left: new BorderSide(
color: new Color(0xFFEBEBEB),
),
right: new BorderSide(
color: new Color(0xFFEBEBEB),
),
bottom: new BorderSide(
color: new Color(0xFFBBBBBB),
),
),
),
child: new SizedBox.expand(
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0),
child: widget.horizontal ? getHorizontal(true) : getVertial(true),
),
),
),
onHover: (event) {
}
);
}
Widget getHorizontal(bool onHover) {
return Row(
children: [
Container(
margin: new EdgeInsets.all(10.0),
width: 110.0,
height: 110.0,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
),
),
],
);
}
Widget getVertial(bool onHover) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: new EdgeInsets.all(10.0),
width: 110.0,
height: 110.0,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Container(
child: Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
),
),
],
);
}
void _showProductDetail() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: widget.product,
business: widget.business,
)),
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
}
}

View File

@@ -0,0 +1,181 @@
import 'package:dio/dio.dart';
import 'package:flappy_search_bar/flappy_search_bar.dart';
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
import 'product_item.dart';
class ProductSearch extends StatefulWidget {
final Business business;
const ProductSearch(this.business, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductSearchState();
}
class ProductSearchState extends State<ProductSearch> {
double sideSpace = 0;
double mainSpace = 1200;
double rate = 1;
int page = 1;
int numPerPage = 10;
int lastResultSize = 0;
double lastBottomPosition = 0;
String lastKeyword = '';
SearchBarController _controller = SearchBarController<Product>();
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
rate = mainSpace / 1200;
return Scaffold(
appBar: MiniNavigationBar(
title: S.of(context).search_product,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).search_product, null),
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
),
drawer: null,
body: SafeArea(
child: Container(
child: Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: NotificationListener<ScrollNotification>(
child: SearchBar(
searchBarController: _controller,
minimumChars: 2,
hintText: S.of(context).enter_keyword,
cancellationWidget: Text(
S.of(context).cancel,
),
onSearch: search,
onItemFound: (Product searchProduct, int index) {
return ProductItem(
searchProduct,
widget.business,
horizontal: true,
);
},
onError: (error) {
return Center(
child: Text("$error"),
);
},
emptyWidget: Center(
child: Text(
S.of(context).empty_result_change_keyword,
),
),
),
onNotification: (notification) {
if (notification.metrics.atEdge) {
print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}');
if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) {
if (notification.metrics.pixels > lastBottomPosition) {
lastBottomPosition = notification.metrics.pixels;
page += 1;
_controller.replayLastSearch();
}
}
}
return true;
},
),
),
),
Container(
width: sideSpace,
),
],
),
),
),
bottomNavigationBar: BottomNav(),
);
}
Future<List<Product>> search(String keyword) async {
if (lastKeyword != keyword) {
page = 1;
}
lastKeyword = keyword;
var result = await HttpUtil.httpGet('v1/search-store-product2',
queryParameters: {
'store_id': widget.business.id,
'keyword': keyword,
'page': page,
'num_per_page': numPerPage,
},
returnError: true,
);
if (result is DioError) {
if (result.response != null) {
throw RuntimeError(result.response.data);
} else {
throw RuntimeError(result.message);
}
} else if (result != null && result is List) {
lastBottomPosition = 0;
var r = result.map((e) => Product.fromJson(e)).toList();
lastResultSize = r.length;
if (lastResultSize < numPerPage) {
page = 1;
}
return r;
}
return [];
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {});
}
});
}
void _showProductDetail(Product p) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: widget.business,
)),
);
}
}

View File

@@ -0,0 +1,297 @@
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import '../../utils/utils.dart';
import '../../widgets/desktop/shop_products.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
import '../../widgets/general/sliding_up_panel.dart';
import '../../widgets/mobile/shopping_cart_bar.dart';
import 'shop_bulletin.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/category_products.dart';
import 'product_search.dart';
import 'shop_promote.dart';
import 'shopping_cart_widget.dart';
class Shop extends StatefulWidget {
final int businessId;
const Shop({Key key, this.businessId}): super(key: key);
@override
State<StatefulWidget> createState() => ShopState();
}
class ShopState extends State<Shop> {
Business _business;
PanelController panelController = PanelController();
SlidingUpPanel _slidUpShoppingCart;
GlobalKey endKey = GlobalKey();
List<CategoryProducts> _categoryProducts;
bool displayProductByCategoryClick = false;
String displayProductByCategoryClickIndicator = '';
int categoryId = 0;
static int _productCurrentPage = 1;
int _categoryIndex = 0;
bool _categoryIndexChange = false;
bool _isLoading = false;
dynamic data;
@override
Widget build(BuildContext context) {
if (_business == null) {
return Scaffold(
body: Center(
child: SpinKitWave(
color: Colors.lightBlueAccent,
size: 40.0,
),
),
);
}
_slidUpShoppingCart = SlidingUpPanel(
controller: panelController,
minHeight: 0.0,
maxHeight: 250.0,
isDraggable: false,
backdropEnabled: true,
slideDirection: SlideDirection.DOWN,
panel: ShoppingCartBar(
business: _business,
endKey: endKey,
barAtBottom: true,
hasPicture: true,
onEmptyCartListener: () {
Future.delayed(Duration(seconds: 1), () {
panelController.close();
});
},
onPanelOpenCloseRequest: () {
if (panelController.isPanelOpen) {
panelController.close();
} else {
panelController.open();
}
},
),
);
Scaffold scaffold = Scaffold(
appBar: MiniNavigationBar(
title: S.of(context).shop,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).shop, null),
BreadCrumb(null, null,
item: Container(
margin: EdgeInsets.only(left: 20.0),
child: Row(
children: [
Container(
child: Icon(
Icons.search,
size: 24,
color: Colors.blue,
),
),
Container(
child: Text(
S.of(context).search_product,
),
),
],
),
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return ProductSearch(_business);
}));
},
),
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
shoppingCart: ShoppingCartWidget(
business: _business,
onTap: () {
if (panelController.isPanelClosed) {
panelController.open();
}
},
),
),
body: Scrollbar(
child: NotificationListener<ScrollNotification>(
onNotification: (scrollNotification) {
if (scrollNotification is ScrollEndNotification &&
scrollNotification.metrics.pixels == scrollNotification.metrics.maxScrollExtent) {
loadMoreProducts();
}
return false;
},
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
ShopPromote(data),
ShopBulletin(_business),
ShopProducts(data),
],
),
),
),
),
bottomNavigationBar: BottomNav(),
);
return Stack(
children: [
Positioned(
top: 0,
left: 0,
right: 0,
bottom: 0,
child: scaffold,
),
_slidUpShoppingCart,
],
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
eventBus.on<CategoryChangeEvent>().listen((event) {
if (mounted) {
// setState(() {
// categoryId = event.categoryId;
// _productCurrentPage = 1;
// });
categoryId = event.categoryId;
_productCurrentPage = 1;
_isLoading = true;
Utils.showLoadingDialog(context, message: S.of(context).loading);
loadProducts();
}
});
loadProducts();
}
void loadProducts() {
print('categoryId $categoryId');
if (categoryId < 0) {
return;
}
_productCurrentPage = 1;
Utils.loadProducts(
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
if (_business == null) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
if (categoryId == 0 && displayProductByCategoryClick) {
categoryId = _categoryProducts[0].id;
}
data = value;
});
} else {
eventBus.fire(GetCategoryProducts(value));
}
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {});
}
Utils.showMessageDialog(context, error);
}, featuredCount: 6, hotSaleCount: 0, keyword: ''
);
}
void loadMoreProducts() {
if (_productCurrentPage == 0 || categoryId <= 0) {
return;
}
_productCurrentPage += 1;
Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true, (value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
List<CategoryProducts> moreCategoryProducts = (value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
} else {
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
_productCurrentPage = 0;
}
}
eventBus.fire(MoreCategoryProducts(moreCategoryProducts));
}
}, (error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
);
}
int nextCategoryId(int currentCategoryId) {
if (_categoryProducts.length <= 0) {
return 0;
}
for (int i = 0; i < _categoryProducts.length; i++) {
if (_categoryProducts[i].id == currentCategoryId) {
try {
CategoryProducts cps = _categoryProducts[i + 1];
return cps.id;
} catch (error) {
print('Error $error');
}
}
}
return 0;
}
}

View File

@@ -1,14 +1,11 @@
import 'dart:async';
import 'dart:math';
import 'package:badges/badges.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_wisetronic/widgets/mobile/shopping_cart_bar.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
@@ -24,34 +21,31 @@ import '../../models/comment.dart';
import '../../models/product.dart';
import '../../models/product_image.dart';
import '../../pages/product_detail_page.dart';
import '../../pages/store_product_search.dart';
import '../../store/actions.dart';
import '../../store/store.dart';
import '../../utils/http_util.dart';
import '../../utils/shop_scroll_controller.dart';
import '../../utils/shop_scroll_coordinator.dart';
import '../../utils/util_web.dart'
if (dart.library.io) '../../utils/util_io.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import '../../utils/utils.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/bottom_nav.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/carousel.dart';
import '../../widgets/general/navigationbar.dart';
import '../../widgets/general/product_item.dart';
import '../../widgets/general/read_more_text.dart';
import '../../widgets/general/show_price.dart';
import '../../widgets/general/sliding_up_panel.dart';
import '../../widgets/general/style.dart';
import 'desktop_shopping_cart_widget.dart';
import '../../widgets/mobile/shopping_cart_bar.dart';
import 'product_item.dart';
import 'shopping_cart_widget.dart';
class DesktopShop extends StatefulWidget {
class Shop extends StatefulWidget {
final int businessId;
const DesktopShop({Key key, this.businessId}) : super(key: key);
const Shop({Key key, this.businessId}) : super(key: key);
@override
State<StatefulWidget> createState() => DesktopShopState();
State<StatefulWidget> createState() => ShopState();
}
MediaQueryData mediaQuery;
@@ -59,7 +53,7 @@ double statusBarHeight;
double screenWidth;
double screenHeight;
class DesktopShopState extends State<DesktopShop>
class ShopState extends State<Shop>
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
@@ -109,7 +103,7 @@ class DesktopShopState extends State<DesktopShop>
int _commentPageCount = 1;
bool _commentLoadingFinish = false;
RefreshController _commentRefreshController =
RefreshController(initialRefresh: true);
RefreshController(initialRefresh: true);
PanelController panelController = PanelController();
SlidingUpPanel _slidUpShoppingCart;
@@ -123,6 +117,44 @@ class DesktopShopState extends State<DesktopShop>
double lastProductListScrollPositionPixel = 0;
final TextEditingController _searchController = new TextEditingController();
Widget searchFieldPlaceHolder;
Icon searchIcon = new Icon(
Icons.search,
color: Colors.blue,
);
bool _isSearching = false;
String _searchText = "";
dynamic responseData;
ShopState() {
_searchController.addListener(() {
if (_searchController.text.isEmpty) {
setState(() {
// _isSearching = false;
_searchText = "";
if (responseData != null) {
_categoryProducts.clear();
_categoryProducts = (responseData['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
} else {
categoryId = 0;
loadProducts();
}
});
} else {
if (!displayProductByCategoryClick) {
setState(() {
_isSearching = true;
_searchText = _searchController.text;
});
}
}
});
}
void _onCommentRefresh() {
if (_commentPage - 1 > 1) {
_commentPage -= 1;
@@ -253,9 +285,33 @@ class DesktopShopState extends State<DesktopShop>
left: 10.0,
top: 10.0,
bottom: 10.0,
right: 10.0,
),
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
width: 220.0,
height: 220.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Colors.white,
border: Border(
top: BorderSide(
width: 1.0,
color: Colors.black12,
),
bottom: BorderSide(
width: 1.0,
color: Colors.black12,
),
left: BorderSide(
width: 1.0,
color: Colors.black12,
),
right: BorderSide(
width: 1.0,
color: Colors.black12,
),
),
),
width: 240.0,
height: 320.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
@@ -263,6 +319,7 @@ class DesktopShopState extends State<DesktopShop>
child: Container(
child: Util.showImage(
_business.promoProducts[i].imagePath,
width: 120.0,
),
),
onTap: () {
@@ -307,8 +364,8 @@ class DesktopShopState extends State<DesktopShop>
pinned: false,
floating: true,
delegate: _SliverAppBarDelegate2(
minHeight: 350.0,
maxHeight: 350.0,
minHeight: 260.0,
maxHeight: 260.0,
child: Row(
children: [
Container(
@@ -413,10 +470,24 @@ class DesktopShopState extends State<DesktopShop>
final newOffset = _pageScrollController.offset + ps.scrollDelta.dy;
if (ps.scrollDelta.dy.isNegative) {
_pageScrollController.jumpTo(max(0, newOffset));
if (max(0, newOffset) == 0) {
_listScrollController1.jumpTo(max(0, _listScrollController1.offset - 10));
}
} else {
_pageScrollController
.jumpTo(min(_pageScrollController.position.maxScrollExtent, newOffset));
if (newOffset > _pageScrollController.position.maxScrollExtent) {
_listScrollController1.jumpTo(min(_listScrollController1.position.maxScrollExtent, _listScrollController1.offset + 10));
}
}
// if (ps.scrollDelta.dy.isNegative) {
// _listScrollController2.jumpTo(max(0, newOffset));
// } else {
// _listScrollController2
// .jumpTo(min(_listScrollController2.position.maxScrollExtent, newOffset));
// }
}
},
child: CustomScrollView(
@@ -427,45 +498,86 @@ class DesktopShopState extends State<DesktopShop>
pinned: true,
floating: true,
delegate: _SliverAppBarDelegate2(
minHeight: 94,
maxHeight: 94,
minHeight: 98,
maxHeight: 98,
child: Column(
children: [
NavigationBar(
MiniNavigationBar(
title: S.of(context).shop,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).shop, null),
BreadCrumb(null, null,
// BreadCrumb(null, null,
// item: Container(
// margin: EdgeInsets.only(left: 20.0),
// child: Row(
// children: [
// Container(
// child: Icon(
// Icons.search,
// size: 24,
// color: Colors.blue,
// ),
// ),
// Container(
// child: Text(
// S.of(context).search_product,
// ),
// ),
// ],
// ),
// ),
// onTap: () {
// // Navigator.push(context,
// // MaterialPageRoute(builder: (BuildContext context) {
// // return ProductSearch(_business);
// // }));
// },
// ),
BreadCrumb(
null, null,
item: Container(
margin: EdgeInsets.only(left: 20.0),
width: 280.0,
padding: EdgeInsets.only(left: 20.0, right: 20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
child: Icon(
Icons.search,
size: 24,
color: Colors.blue,
MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Container(
padding: EdgeInsets.only(right: 10.0),
child: Icon(
searchIcon.icon,
size: 20.0,
color: Colors.blue,
),
),
onTap: () {
onSearchTap();
},
),
),
Container(
child: Text(
S.of(context).search_product,
Expanded(child: searchFieldPlaceHolder == null ? MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Text(
S.of(context).search_products,
style: new TextStyle(color: Colors.blue),
),
onTap: () {
onSearchTap();
},
),
),
) : searchFieldPlaceHolder),
],
),
),
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return StoreProductSearch(_business);
}));
},
),
)
],
breadCrumbHeight: Constants.BREADCRUMB_HEIGHT,
shoppingCart: DesktopShoppingCartWidget(
shoppingCart: ShoppingCartWidget(
business: _business,
onTap: () {
if (panelController.isPanelClosed) {
@@ -573,21 +685,20 @@ class DesktopShopState extends State<DesktopShop>
stack.children.addAll(children);
if (!_business.isPublic) {
/* todo */
// stack.children.add(
// Positioned(
// top: 0,
// right: 0,
// left: screenWidth - 100,
// bottom: screenHeight - 100,
// child: Image.asset(
// 'assets/images/under_renovation.png',
// width: 200.0,
// height: 200.0,
// fit: BoxFit.fill,
// ),
// ),
// );
stack.children.add(
Positioned(
top: 0,
right: 0,
left: screenWidth - 100,
bottom: screenHeight - 100,
child: Image.asset(
'assets/images/under_renovation.png',
width: 200.0,
height: 200.0,
fit: BoxFit.fill,
),
),
);
}
return stack;
@@ -626,7 +737,7 @@ class DesktopShopState extends State<DesktopShop>
cancelButton: CupertinoActionSheetAction(
child: Text(S.of(context).close),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
},
),
);
@@ -872,8 +983,8 @@ class DesktopShopState extends State<DesktopShop>
));
var duration = Duration(
seconds: (_business.distanceInfo.duration != null
? _business.distanceInfo.duration.value
: 30) +
? _business.distanceInfo.duration.value
: 30) +
_business.shippingTime * 60);
var hours = duration.inHours.remainder(60);
var minutes = duration.inMinutes.remainder(60);
@@ -1008,28 +1119,28 @@ class DesktopShopState extends State<DesktopShop>
children: <Widget>[
_business.bulletin.isNotEmpty ? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
children: <Widget>[
Container(
padding:
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
child: Icon(
Icons.announcement,
size: 14.0,
color: Colors.white,
)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
// overflow: TextOverflow.ellipsis,
),
),
],
) : SizedBox.shrink(),
),
],
) : SizedBox.shrink(),
_business.description.isNotEmpty ? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -1276,7 +1387,7 @@ class DesktopShopState extends State<DesktopShop>
height: 70.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
decoration: new BoxDecoration(
color: _categoryIndex == i ? Style.backgroundColor : null,
color: _categoryIndex == i ? Colors.white : null,
border: new Border(
bottom:
new BorderSide(color: new Color(0xFFEBEBEB)))),
@@ -1309,10 +1420,10 @@ class DesktopShopState extends State<DesktopShop>
_categoryIndexChange = true;
_listScrollController1
.animateTo(height,
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
.then((value) {
_categoryIndexChange = false;
});
@@ -1522,10 +1633,11 @@ class DesktopShopState extends State<DesktopShop>
if (it.moveNext()) {
r1.children.add(
Container(
width: (mainSpace - 200) / c,
width: (mainSpace - 200) / c - 4.0,
margin: EdgeInsets.only(top: 2.0, bottom: 2.0, left: 2.0, right: 2.0),
child: ProductItem(
product: it.current,
business: _business,
it.current,
_business,
),
),
);
@@ -1656,128 +1768,6 @@ class DesktopShopState extends State<DesktopShop>
}
});
// onProductWillAddToCartSubscription =
// eventBus.on<OnProductWillAddToCart>().listen((event) {
// if (mounted) {
//
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
//
// if (cartInfo == null || cartInfo.productList.length == 0) {
// cartInfo = CartInfo();
// cartInfo.id = 0;
// cartInfo.amountPaid = 0.0;
// cartInfo.businessInfo = event.business;
// cartInfo.extraFeeList = [];
// cartInfo.discountList = [];
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList = [lineItem];
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (event.product.productAttributes.length > 0) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// int found = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (event.product.id == cartInfo.productList[i].product.id) {
// found = i;
// break;
// }
// }
// if (found == -1) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (cartInfo.productList[found].quantity + 1.0 >
// event.product.leftNum) {
// Fluttertoast.showToast(
// msg: S.of(context).product_insufficient,
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
// backgroundColor: Colors.red,
// textColor: Colors.white);
// } else {
// cartInfo.productList[found].quantity += 1;
// store.dispatch(new UpdateCartInfo(
// Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// }
// }
// }
// });
// onProductWillRemoveFromCartSubscription =
// eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
// if (mounted) {
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
// if (cartInfo != null) {
// if (cartInfo.productList.length > 0) {
// if (event.productListIndex != -1) {
// if (cartInfo.productList[event.productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(event.productListIndex);
// } else {
// cartInfo.productList[event.productListIndex].quantity -= 1;
// }
// } else {
// int productListIndex = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (cartInfo.productList[i].product.id == event.product.id) {
// productListIndex = i;
// break;
// }
// }
// if (productListIndex != -1) {
// if (cartInfo.productList[productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(productListIndex);
// } else {
// cartInfo.productList[productListIndex].quantity -= 1;
// }
// }
// }
// }
//
// if (cartInfo.productList.length <= 0) {
// store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList(
// store.state.cartInfos, cartInfo)));
// } else {
// store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// }
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// });
loadProducts();
}
@@ -1792,68 +1782,80 @@ class DesktopShopState extends State<DesktopShop>
lastProductListScrollPositionPixel = 0;
_productCurrentPage = 1;
Utils.loadProducts(
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
_featuredProducts = (value['featured_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_hotSaleProducts = (value['hot_sale_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_prompts = value['prompt'] as List;
_isSearching = false;
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (_searchController.text.isEmpty) {
responseData = value;
}
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
// _featuredProducts = (value['featured_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
// _hotSaleProducts = (value['hot_sale_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
_featuredProducts = [];
_hotSaleProducts = [];
_prompts = value['prompt'] as List;
checkActionAndClose(context);
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
checkActionAndClose(context);
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
_isSearching = false;
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
if (mounted) {
setState(() {});
}
Utils.showMessageDialog(context, error);
}, featuredCount: 5, hotSaleCount: 0, keyword: _searchController.text
);
}
@@ -1863,59 +1865,59 @@ class DesktopShopState extends State<DesktopShop>
}
_productCurrentPage += 1;
Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
Utils.showMessageDialog(context, error);
}, keyword: _searchController.text
);
}
CartLineItem _newCartLineItem(
{int id,
double price,
Product product,
String name,
String description,
double quantity}) {
double price,
Product product,
String name,
String description,
double quantity}) {
CartLineItem lineItem = CartLineItem();
lineItem.unitPrice = price;
lineItem.product = product;
@@ -2087,10 +2089,10 @@ class DesktopShopState extends State<DesktopShop>
S.of(context).store_closed,
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -2143,10 +2145,10 @@ class DesktopShopState extends State<DesktopShop>
),
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -2169,7 +2171,7 @@ class DesktopShopState extends State<DesktopShop>
title: Text(_prompt['title']),
content: Text(_prompt['message']),
actions: [
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
@@ -2184,6 +2186,158 @@ class DesktopShopState extends State<DesktopShop>
@override
bool get wantKeepAlive => true;
void onSearchTap() {
setState(() {
if (searchIcon.icon == Icons.search) {
searchIcon = new Icon(
Icons.close,
color: Colors.white,
);
if (displayProductByCategoryClick) {
searchFieldPlaceHolder = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child:
TextField(
controller: _searchController,
textInputAction: TextInputAction.search,
onSubmitted: (value) {
onSearchButtonTap();
},
style: TextStyle(
color: Colors.black87,
),
decoration: new InputDecoration(
hintText: S
.of(context)
.enter_keyword,
hintStyle: TextStyle(color: Colors.black26)),
onChanged: searchOperation,
),
),
SizedBox(width: 5,),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: Colors.redAccent,
onPrimary: Colors.white,
padding: EdgeInsets.only(left: 5, right: 5, top: 5, bottom: 5),
elevation: 2.0,
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(5.0),
),
),
onPressed: onSearchButtonTap,
icon: Icon(
Icons.search,
size: 16,
color: Colors.green,
),
label: Text(
S.of(context).search,
style: TextStyle(
color: Colors.green,
),
),
),
],
);
} else {
searchFieldPlaceHolder = TextField(
controller: _searchController,
style: TextStyle(
color: Colors.black87,
),
decoration: new InputDecoration(
hintText: S
.of(context)
.enter_keyword,
hintStyle: TextStyle(color: Colors.black26)),
onChanged: searchOperation,
);
_handleSearchStart();
}
} else {
_handleSearchEnd();
}
});
}
void _handleSearchStart() {
setState(() {
_isSearching = true;
});
}
void _handleSearchEnd() {
setState(() {
searchIcon = new Icon(
Icons.search,
color: Colors.blue,
);
searchFieldPlaceHolder = MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Text(
S.of(context).search_products,
style: new TextStyle(color: Colors.blue),
),
onTap: () {
onSearchTap();
},
),
);
_isSearching = false;
_searchController.clear();
if (displayProductByCategoryClick) {
categoryId = 0;
loadProducts();
}
});
}
void searchOperation(String searchText) {
if (displayProductByCategoryClick) {
} else {
if (responseData != null) {
_categoryProducts.clear();
List<CategoryProducts> cps = (responseData['category_products'] as List)
.map((i) {
CategoryProducts cp = CategoryProducts.fromJson(i);
List<Product> ps = [];
for (Product p in cp.products) {
if (p.name.toLowerCase().contains(searchText.toLowerCase()) ||
p.description.toLowerCase().contains(searchText.toLowerCase()) ||
(p.detailDescription != null && p.detailDescription.toLowerCase().contains(searchText.toLowerCase()))) {
ps.add(p);
}
}
if (ps.length > 0) {
cp.products = ps;
return cp;
}
}).toList();
for (CategoryProducts cp in cps) {
if (cp != null) {
_categoryProducts.add(cp);
}
}
print('$searchText, count: ${_categoryProducts.length}');
setState(() {});
}
}
}
void onSearchButtonTap() {
String kw = _searchController.text;
if (kw.isNotEmpty) {
_handleSearchStart();
loadProducts();
}
}
}
class _SliverAppBarDelegate2 extends SliverPersistentHeaderDelegate {

View File

@@ -0,0 +1,70 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import '../../models/business.dart';
class ShopBulletin extends StatefulWidget {
final Business business;
const ShopBulletin(this.business, {Key key}): super(key: key);
@override
State<StatefulWidget> createState() => ShopBulletinState();
}
class ShopBulletinState extends State<ShopBulletin> {
double sideSpace = 0;
double mainSpace = 1200;
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
if (widget.business.bulletin != null && widget.business.bulletin.isNotEmpty) {
return Container(
margin: EdgeInsets.only(bottom: 12),
child: Row(
children: [
Container(
width: sideSpace,
),
Expanded(
child: Container(
padding: EdgeInsets.only(top: 10, left: 16.0, right: 16.0, bottom: 10.0),
child: Text(
'${widget.business.bulletin}',
overflow: TextOverflow.ellipsis,
maxLines: 3,
style: TextStyle(
color: Colors.white,
),
),
decoration: BoxDecoration(
color: Colors.orangeAccent,
border: Border.all(
color: Colors.red[500],
width: 1.0,
),
borderRadius: BorderRadius.all(Radius.circular(16)),
),
),
),
Container(
width: sideSpace,
),
],
),
);
}
return SizedBox.shrink();
}
}

View File

@@ -0,0 +1,431 @@
import 'package:badges/badges.dart';
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/cart_info.dart';
import '../../models/category_products.dart';
import '../../store/store.dart';
import '../../utils/utils.dart';
import '../../widgets/desktop/product_item.dart';
class ShopProducts extends StatefulWidget {
final dynamic data;
const ShopProducts(this.data, {Key key}): super(key: key);
@override
State<StatefulWidget> createState() => ShopProductsState();
}
class ShopProductsState extends State<ShopProducts> {
double sideSpace = 0;
double mainSpace = 1200;
dynamic data;
static const num _categoryHeight = 50.0;
static const num _categoryDescHeight = 50.0;
static const num _productHeight = 266.0;
bool displayProductByCategoryClick = false;
String displayProductByCategoryClickIndicator = '';
int categoryId = 0;
double leftSideMenuWidth = 0;
int _categoryIndex = 0;
List<CategoryProducts> _categoryProducts = [];
Business _business;
double menuPosition = 0;
ScrollController _menuScrollController = ScrollController();
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: sideSpace,
),
Expanded(
child: Container(
child:
// Row(
// mainAxisAlignment: MainAxisAlignment.start,
// crossAxisAlignment: CrossAxisAlignment.start,
// mainAxisSize: MainAxisSize.min,
// children: [
// _buildCategories(),
// Expanded(
// child: _buildProducts(),
// ),
// ],
// ),
IntrinsicHeight(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisSize: MainAxisSize.min,
children: [
_buildCategories(),
Expanded(
child: _buildProducts(),
),
],
),
),
),
),
Container(
width: sideSpace,
),
],
),
);
}
Widget _buildCategories() {
return new Container(
width: leftSideMenuWidth,
height: 500,
color: new Color(0xFFF5F5F5),
child: new SizedBox.expand(
child: ListView.builder(
physics: ClampingScrollPhysics(),
controller: _menuScrollController,
itemCount: _categoryProducts == null ? 0 : _categoryProducts.length,
itemBuilder: (BuildContext context, int i) {
CategoryProducts cp = _categoryProducts[i];
int qtyInCategory = 0;
CartInfo cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, _business);
if (cartInfo != null &&
cartInfo.businessInfo.id == _business.id &&
cartInfo.productList != null) {
for (var i = 0; i < cartInfo.productList.length; i++) {
if (cartInfo.productList[i].product.categoryId == cp.id) {
qtyInCategory += cartInfo.productList[i].quantity.ceil();
}
}
}
Row categoryRow = Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[],
);
categoryRow.children.add(
Expanded(
flex: 1,
child: Container(
margin: EdgeInsets.only(top: 5.0, bottom: 5.0),
child: Text(
cp.name,
style: TextStyle(
fontSize: 13.0,
fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id == Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
softWrap: true,
maxLines: 2,
),
),
),
);
if (qtyInCategory > 0) {
categoryRow.children.add(
Badge(
badgeContent: Text(
'$qtyInCategory',
style: TextStyle(
color: Colors.white,
fontSize: 11.0,
),
),
animationType: BadgeAnimationType.scale,
),
);
} else {
categoryRow.children.add(SizedBox.shrink());
}
return GestureDetector(
child: new Container(
height: 70.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
decoration: new BoxDecoration(
color: cp.id == categoryId ? Colors.white : null,
border: new Border(
bottom:
new BorderSide(color: new Color(0xFFEBEBEB)))),
child: categoryRow,
),
onTap: () => _selectCategory(cp.id),
);
}
),
),
);
}
void _selectCategory(int i) {
categoryId = i;
eventBus.fire(CategoryChangeEvent(i));
}
Widget _buildProducts() {
if (_categoryProducts == null) {
return SizedBox.shrink();
}
Column col = new Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[],
);
for (int i = 0; i < _categoryProducts.length; i++) {
CategoryProducts cp = _categoryProducts[i];
if (cp.products.length > 0) {
col.children.add(new Container(
height: _categoryDescHeight,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
color: new Color(0xFFF5F5F5),
child: new Row(
children: <Widget>[
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 5.0),
child: new Text(
cp.name,
style: new TextStyle(
fontSize: 16.0,
fontWeight:
(cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id ==
Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
overflow: TextOverflow.ellipsis,
),
),
new Visibility(
visible: cp.description.isNotEmpty,
child: new Text(
cp.description,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)),
),
replacement: const SizedBox.shrink()),
],
))
],
)));
var it = cp.products.iterator;
for (int i = 0; i < cp.products.length; i++) {
var r1 = Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [],
);
double d = getProductCountInRow();
int c = int.parse(d.toString());
while (d > 0) {
if (it.moveNext()) {
r1.children.add(
Container(
width: (mainSpace - leftSideMenuWidth) / c - 4.0,
margin: EdgeInsets.only(top: 2.0, bottom: 2.0, left: 2.0, right: 2.0),
child: ProductItem(
it.current,
_business,
),
),
);
}
d -= 1;
}
col.children.add(r1);
}
if (displayProductByCategoryClick) {
if (displayProductByCategoryClickIndicator.isNotEmpty) {
col.children.add(
Container(
padding: EdgeInsets.all(12.0),
child: Center(
child: Text(
displayProductByCategoryClickIndicator,
style: TextStyle(
color: Colors.black54,
),
),
),
),
);
} else if (categoryId > 0) {
if (cp.products.length < Constants.ORDERS_PER_PAGE) {
col.children.add(
Container(
padding: EdgeInsets.all(12.0),
child: Center(
child: Text(
S
.of(context)
.end_of_the_list,
style: TextStyle(
color: Colors.black54,
),
),
),
),
);
} else {
col.children.add(
Container(
padding: EdgeInsets.all(12.0),
child: Center(
child: Text(
S
.of(context)
.pull_up_to_load_more,
style: TextStyle(
color: Colors.black54,
),
),
),
),
);
}
}
}
}
}
return col;
}
void loadData() {
// _categoryProducts .clear();
_categoryProducts = (data['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
_business = Business.fromJson(data['business']);
displayProductByCategoryClick = data['display_product_by_category_click'];
if (displayProductByCategoryClick) {
leftSideMenuWidth = 200;
}
displayProductByCategoryClickIndicator = '';
if (categoryId == 0 && displayProductByCategoryClick) {
categoryId = _categoryProducts[0].id;
}
setState(() {
});
}
@override
void initState() {
super.initState();
data = widget.data;
loadData();
eventBus.on<GetCategoryProducts>().listen((event) {
if (mounted) {
data = event.data;
loadData();
}
});
eventBus.on<MoreCategoryProducts>().listen((event) {
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts = event.data;
if (moreCategoryProducts.isEmpty) {
displayProductByCategoryClickIndicator = S
.of(context)
.end_of_the_list;
} else {
if (moreCategoryProducts[0].products.length <
Constants.ORDERS_PER_PAGE) {
displayProductByCategoryClickIndicator = S
.of(context)
.end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S
.of(context)
.pull_up_to_load_more;
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
displayProductByCategoryClickIndicator = S
.of(context)
.end_of_the_list;
}
}
});
}
});
}
int numCategoriesHasProducts() {
int num = 0;
for (CategoryProducts cp in _categoryProducts) {
if (cp.products.length > 0) {
num += 1;
}
}
return num;
}
CategoryProducts getCategoryProductByCategoryId(int cid) {
for (CategoryProducts cp in _categoryProducts) {
if (cp.id == cid) {
return cp;
}
}
return null;
}
double getProductCountInRow() {
double d = 2;
if (mainSpace >= 800 && mainSpace < 1000) {
d = 3;
} else if (mainSpace >= 1000) {
d = 4;
}
return d;
}
}

View File

@@ -0,0 +1,185 @@
import 'package:flutter/material.dart';
import '../../generated/l10n.dart';
import '../../pages/product_detail_page.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/show_price.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
class ShopPromote extends StatefulWidget {
final dynamic data;
const ShopPromote(this.data, {Key key}): super(key: key);
@override
State<StatefulWidget> createState() => ShopPromoteState();
}
class ShopPromoteState extends State<ShopPromote> {
double sideSpace = 0;
double mainSpace = 1200;
Business _business;
@override
Widget build(BuildContext context) {
if (MediaQuery.of(context).size.width <= 1200) {
mainSpace = MediaQuery.of(context).size.width;
sideSpace = 0;
} else {
mainSpace = 1200;
sideSpace = (MediaQuery.of(context).size.width - 1200) / 2;
}
Row promoteRow = getPromoteRow();
if (promoteRow.children.length > 0) {
return Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: sideSpace,
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(top: 12, bottom: 6),
child: Text(
S.of(context).promotions,
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
),
Container(
padding: EdgeInsets.only(bottom: 10),
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: promoteRow,
),
),
],
),
),
Container(
width: sideSpace,
),
],
),
);
} else {
return SizedBox.shrink();
}
}
@override
void initState() {
super.initState();
_business = Business.fromJson(widget.data['business']);
}
Row getPromoteRow() {
Row promotRow = Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[],
);
for (var i = 0; i < _business.promoProducts.length; i++) {
promotRow.children.add(Container(
padding: EdgeInsets.only(
left: 10.0,
top: 10.0,
bottom: 10.0,
right: 10.0,
),
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
width: 220.0,
height: 220.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Colors.white,
border: Border(
top: BorderSide(
width: 1.0,
color: Colors.black12,
),
bottom: BorderSide(
width: 1.0,
color: Colors.black12,
),
left: BorderSide(
width: 1.0,
color: Colors.black12,
),
right: BorderSide(
width: 1.0,
color: Colors.black12,
),
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
GestureDetector(
child: Container(
child: Util.showImage(
_business.promoProducts[i].imagePath,
width: 120.0,
),
),
onTap: () {
_showProductDetail(_business.promoProducts[i]);
},
),
Container(
child: Text(
_business.promoProducts[i].name,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(fontSize: 14.0),
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
ShowPrice(
_business.promoProducts[i].price,
currencySign: '\$',
fontWeight: FontWeight.bold,
smallFontSize: 15,
largeFontSize: 24,
regularPrice: _business.promoProducts[i].regularPrice,
),
Container(
child: AddRemoveButton(
product: _business.promoProducts[i],
business: _business,
addOnly: true,
),
)
],
)
],
),
));
}
return promotRow;
}
void _showProductDetail(Product p) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: _business,
)),
);
}
}

View File

@@ -0,0 +1,79 @@
import 'package:flutter/material.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../models/business.dart';
import '../../models/cart_info.dart';
import '../../store/store.dart';
import '../../utils/utils.dart';
class ShoppingCartWidget extends StatefulWidget {
final Business business;
final Function onTap;
ShoppingCartWidget({@required this.business, this.onTap});
@override
State<StatefulWidget> createState() => ShoppingCartWidgetState();
}
class ShoppingCartWidgetState extends State<ShoppingCartWidget> {
CartInfo cartInfo;
double totalPrice = 0.0;
@override
Widget build(BuildContext context) {
totalPrice = 0.0;
cartInfo = Utils.getCartInfoByBusiness(store.state.cartInfos, widget.business);
if (cartInfo != null && cartInfo.businessInfo.id == widget.business.id) {
totalPrice = cartInfo.getTotalPrice();
}
Row row = Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
padding: EdgeInsets.only(left: 16.0, right: 4.0, top: 8.0),
child: Icon(
Icons.shopping_basket_outlined,
size: 24,
color: Colors.blue,
),
),
Container(
padding: EdgeInsets.only(left: 4.0, right: 16.0, top: 8.0),
child: Text(
'\$${totalPrice.toStringAsFixed(2)}',
style: TextStyle(
color: totalPrice > 0 ? Colors.red : Colors.black45,
fontWeight: totalPrice > 0 ? FontWeight.bold : FontWeight.normal,
),
),
),
],
);
return MouseRegion(
cursor: SystemMouseCursors.click,
child: GestureDetector(
child: Container(
child: row,
width: 160.0,
),
onTap: widget.onTap,
),
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
}
}

View File

@@ -4,11 +4,13 @@ import 'package:flutter/rendering.dart';
import '../../generated/l10n.dart';
import '../../routes.dart';
import 'navigationbar.dart';
class BreadCrumbs extends StatelessWidget {
final List<BreadCrumb> breadCrumbs;
final bool hasBack;
const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key}) : super(key: key);
final OnBackPress onBackPress;
const BreadCrumbs(this.hasBack, {this.breadCrumbs, Key key, this.onBackPress}) : super(key: key);
@override
Widget build(BuildContext context) {
@@ -39,8 +41,8 @@ class BreadCrumbs extends StatelessWidget {
),
],
),
onTap: () {
Routes.router.pop(context);
onTap: onBackPress != null ? onBackPress : () {
Navigator.of(context).maybePop();
},
),
),
@@ -72,7 +74,7 @@ class BreadCrumbs extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(top: 0.0),
padding: EdgeInsets.only(top: 6.0, left: 4.0, right: 4.0),
child: Icon(
Icons.circle,
size: 6.0,
@@ -123,7 +125,7 @@ class BreadCrumbs extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: EdgeInsets.only(top: 0.0),
padding: EdgeInsets.only(top: 6.0, left: 4.0, right: 4.0),
child: Icon(
Icons.circle,
size: 6.0,

View File

@@ -6,7 +6,9 @@ import '../../widgets/desktop/desktop_navigationbar.dart';
import '../../widgets/mobile/mobile_navigationbar.dart';
import 'breadcrumbs.dart';
class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
typedef OnBackPress();
class MiniNavigationBar extends StatefulWidget implements PreferredSizeWidget {
final Key key;
final String title;
final bool back;
@@ -16,7 +18,7 @@ class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
final double breadCrumbHeight;
final Widget shoppingCart;
NavigationBar({Key key, PreferredSizeWidget bottom, String title,
MiniNavigationBar({Key key, PreferredSizeWidget bottom, String title,
bool back, bool toHome, bool showMe, this.breadCrumbs,
this.breadCrumbHeight, this.shoppingCart})
: key = key,
@@ -32,12 +34,12 @@ class NavigationBar extends StatefulWidget implements PreferredSizeWidget {
@override
State<StatefulWidget> createState() {
return NavigationBarState();
return MiniNavigationBarState();
}
}
class NavigationBarState extends State<NavigationBar> {
class MiniNavigationBarState extends State<MiniNavigationBar> {
@override
Widget build(BuildContext context) {

View File

@@ -33,6 +33,9 @@ class PaymentVerificationCodeDialogState extends State<PaymentVerificationCodeDi
String getCodeText = '';
String paymentCodeEncrypt = '';
String verifyMethod;
String verifyName;
final TextEditingController _pinPutController = TextEditingController();
final FocusNode _pinPutFocusNode = FocusNode();
BoxDecoration get _pinPutDecoration {
@@ -53,12 +56,15 @@ class PaymentVerificationCodeDialogState extends State<PaymentVerificationCodeDi
Container(
padding: EdgeInsets.only(top: 0.0, bottom: 10.0, left: 0.0, right: 0.0),
child: Text(
S.of(context).payment_verification_sent(Utils.safePhoneNumber(widget.user.mobile)),
(verifyMethod != null) ? S.of(context).payment_verification_sent(
(verifyName == 'sms') ? S.of(context).mobile : S.of(context).email,
Utils.safePhoneNumber(verifyName)
) : '',
),
),
Container(
padding: EdgeInsets.only(top: 0.0, bottom: 10.0, left: 0.0, right: 0.0),
child: FlatButton(
child: TextButton(
child: Text(getCodeText),
onPressed: enableGetCode ? () {
getPaymentCode();
@@ -146,6 +152,8 @@ class PaymentVerificationCodeDialogState extends State<PaymentVerificationCodeDi
},
).then((data) {
paymentCodeEncrypt = data['payment_code_encrypt'];
verifyMethod = data['verify_method'];
verifyName = data['verify_name'];
print('data: $data');
startCountDown();
}).catchError((error) {

View File

@@ -1,27 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_wisetronic/models/business.dart';
import 'package:flutter_wisetronic/models/product.dart';
import 'package:flutter_wisetronic/widgets/desktop/desktop_product_item.dart';
import 'package:flutter_wisetronic/widgets/mobile/mobile_product_item.dart';
import 'package:responsive_builder/responsive_builder.dart';
class ProductItem extends StatelessWidget {
final Product product;
final Business business;
const ProductItem({Key key, this.product, this.business}) : super(key: key);
@override
Widget build(BuildContext context) {
return ResponsiveBuilder(
builder: (context, sizingInformation) =>
ScreenTypeLayout(
mobile: MobileProductItem(product: product, business: business,),
tablet: DesktopProductItem(product: product, business: business,),
desktop: DesktopProductItem(product: product, business: business,),
),
);
}
}

View File

@@ -3,6 +3,7 @@ import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_wisetronic/utils/utils.dart';
import 'package:hovering/hovering.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../routes.dart';
@@ -11,6 +12,7 @@ class TextLink extends StatelessWidget {
final String title;
final String url;
final Color color;
final Color hoverColor;
final double paddingHorizontal;
final double paddingVertical;
final FontWeight fontWeight;
@@ -24,8 +26,14 @@ class TextLink extends StatelessWidget {
final bool closeDrawer;
final bool isEmail;
final bool isPhone;
final double fontSize;
final bool isAddress;
final TextOverflow overflow;
final int maxLines;
TextLink(this.title, this.url, {
this.color,
this.hoverColor,
this.paddingHorizontal,
this.paddingVertical,
this.fontWeight,
@@ -39,6 +47,10 @@ class TextLink extends StatelessWidget {
bool closeDrawer,
bool isEmail,
bool isPhone,
double fontSize,
bool isAddress,
TextOverflow overflow,
int maxLines,
}) :
isLink = isLink ?? false,
replace = replace ?? false,
@@ -47,7 +59,11 @@ class TextLink extends StatelessWidget {
rootNavigator = rootNavigator ?? false,
closeDrawer = closeDrawer ?? false,
isEmail = isEmail ?? false,
isPhone = isPhone ?? false;
isPhone = isPhone ?? false,
fontSize = fontSize ?? null,
isAddress = isAddress ?? false,
overflow = overflow ?? TextOverflow.ellipsis,
maxLines = maxLines ?? 1;
@override
Widget build(BuildContext context) {
@@ -59,19 +75,37 @@ class TextLink extends StatelessWidget {
vertical: paddingVertical ?? 0.0,
horizontal: paddingHorizontal ?? 0.0
),
child: Text(
title,
style: TextStyle(
color: color ?? Colors.blue,
fontWeight: fontWeight ?? FontWeight.normal,
child: HoverWidget(
child: Text(
title,
style: TextStyle(
color: color ?? Colors.blue,
fontWeight: fontWeight ?? FontWeight.normal,
fontSize: fontSize,
),
overflow: overflow,
maxLines: maxLines,
),
hoverChild: Text(
title,
style: TextStyle(
color: hoverColor ?? Colors.grey,
fontSize: fontSize,
fontWeight: fontWeight ?? FontWeight.normal,
),
overflow: overflow,
maxLines: maxLines,
),
onHover: (event) {
},
),
decoration: BoxDecoration(
border: (selected != null && selected) ? Border(
bottom: BorderSide(
color: color ?? Colors.blue,
width: 3.0,
)
bottom: BorderSide(
color: color ?? Colors.blue,
width: 3.0,
)
) : null,
),
),
@@ -81,6 +115,8 @@ class TextLink extends StatelessWidget {
Utils.openEmail(url);
} else if (isPhone) {
Utils.callPhone(url);
} else if (isAddress) {
await launch('https://maps.google.com/?q=${url}');
} else if (!isLink) {
if (closeDrawer) {
Routes.router.pop(context);

View File

@@ -0,0 +1,411 @@
import 'package:flutter/material.dart';
import '/models/group.dart';
import '/pages/buy_service.dart';
import '../../constants.dart';
import '../../generated/l10n.dart';
import '../../routes.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
class CreateOnlineStore1 extends StatefulWidget {
final int businessId;
const CreateOnlineStore1(this.businessId, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return CreateOnlineStore1State();
}
}
class CreateOnlineStore1State extends State<CreateOnlineStore1> {
TextEditingController groupNumberController = TextEditingController();
TextEditingController domainController = TextEditingController();
bool canSubmit = false;
List<dynamic> stores = [];
Map<String, dynamic> service;
dynamic selectedStore;
Group group;
String selectedDomain;
List<dynamic> domainResult = [];
@override
Widget build(BuildContext context) {
Column col = Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 20, left: 16, right: 16, bottom: 10,),
child: Text(
S.of(context).open_online_store,
style: TextStyle(
fontSize: 28,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4, bottom: 4, left: 16.0, right: 16.0),
child: Text(
S.of(context)
.select_a_store,
style: TextStyle(
color: Colors.black45,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4, bottom: 4, left: 16.0, right: 16.0),
child: DropdownButton<dynamic>(
items: stores.map((e) => DropdownMenuItem<dynamic>(
value: e,
child: Text(e['name']),
)).toList(),
isExpanded: false,
hint: Text(S.of(context).select_a_store),
onChanged: (newValue) {
print('newValue $newValue');
setState(() {
selectedStore = newValue;
});
},
value: selectedStore,
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(
left: 16.0, right: 16.0, top: 20, bottom: 20),
child: Visibility(
child: getSearchDomainWidget(),
visible: selectedStore != null,
),
),
);
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_back_ios),
onPressed: (){
Navigator.of(context).pop();
},
),
title: Text(S.of(context).open_online_store),
backgroundColor: Theme.of(context).primaryColor,
),
body: SingleChildScrollView(
child: col,
),
);
}
Widget getSearchDomainWidget() {
if (selectedStore == null) {
return SizedBox.shrink();
}
Column col = Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [],
);
col.children.add(
Container(
padding: EdgeInsets.only(bottom: 4,),
child: Text(selectedStore == null ? '' : selectedStore['name'],
style: TextStyle(
fontSize: 28,
),
),
),
);
Map<String, dynamic> existing_web_svc;
if (selectedStore != null && (selectedStore['services'] as List).length > 0) {
for (Map<String, dynamic>svc in (selectedStore['services'] as List)) {
if (svc['code'] == Constants.WEB_MINISTORE_SERVICE) {
existing_web_svc = svc;
break;
}
}
}
if (existing_web_svc != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'${existing_web_svc['description']}',
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).expiration_date + ": "
+ Utils.utcDatetimeStringToLocalDatetimeString(context, existing_web_svc['expiration_date']),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).store + ": " + '${existing_web_svc['store']['name']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 4.0),
child: Text(
S.of(context).domain_name + ": " + '${existing_web_svc['domain']}'
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(S.of(context).renew_service_now),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: existing_web_svc['domain'],
sid: existing_web_svc['store']['id'],
),
));
},
),
),
);
} else {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(S.of(context).enter_desired_domain),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 0,),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
child: TextFormField(
controller: domainController,
decoration: new InputDecoration(
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.black12,
),
),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(
color: Colors.blue,
),
),
labelText: S.of(context).domains_separated_comma,
),
style: TextStyle(
fontSize: 18.0
),
autofocus: true,
validator: (String value) {
if (value.trim().isEmpty) {
return S.of(context).domains_separated_comma;
}
return null;
},
onChanged: (string) {
if (string.isNotEmpty) {
canSubmit = true;
} else {
canSubmit = false;
}
setState(() {});
},
),
),
Container(
padding: EdgeInsets.only(left: 8.0),
child: ElevatedButton(
child: Text(
S.of(context).check_domain_name,
),
onPressed: domainController.text.length > 0 ? checkDomainAvailability : null,
),
),
],
),
)
);
if (domainResult.length > 0) {
for (dynamic dr in domainResult) {
col.children.add(_getDomain(dr));
}
}
if (selectedDomain != null && service != null) {
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['description'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
service['options'][0]['name'],
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 8.0),
child: Text(
'\$${service['options'][0]['price']}',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Colors.orange,
),
),
),
);
col.children.add(
Container(
padding: EdgeInsets.only(top: 10.0),
child: ElevatedButton(
child: Text(
S.of(context).place_order_now,
),
onPressed: () {
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (BuildContext context) =>
BuyService(group.id, Constants.WEB_MINISTORE_SERVICE,
domain: selectedDomain,
sid: selectedStore['id'],
),
));
},
),
),
);
}
}
return Container(
padding: EdgeInsets.only(bottom: 4,),
child: col,
);
}
@override
void initState() {
super.initState();
HttpUtil.httpGet(
'v1/get-contact-stores',
queryParameters: {
'service': Constants.WEB_MINISTORE_SERVICE
}
).then((value) {
setState(() {
stores = value['stores'];
service = value['service'];
group = Group.fromJson(value['group']);
print('stores: ${value}');
});
}).onError((error, stackTrace) {
Utils.showMessageDialog(context, error, onOk: () {
Routes.router.navigateTo(context, '/');
});
});
}
Future<void> checkDomainAvailability() async {
Utils.showLoadingDialog(context);
selectedDomain = null;
domainResult = [];
setState(() {});
HttpUtil.httpGet(
'v1/check-domain-availability',
queryParameters: {
'domain': domainController.text,
},
).then((value) {
Routes.router.pop(context);
print('value: $value');
if (value['status'] == 'OK') {
domainResult = (value['domain_check_result'] as List);
setState(() {});
} else if (value['status'] == 'ERROR') {
String errors = '';
for (int i = 0; i < (value['errors'] as List).length; i++) {
errors += value['errors'][i] + '\n';
}
Utils.showMessageDialog(context, errors);
}
}).onError((error, stackTrace) {
Routes.router.pop(context);
Utils.showMessageDialog(context, error);
});
}
Widget _getDomain(dynamic d) {
if ((d['available'] as bool)) {
return Container(
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
leading: Radio(
value: d['domain'],
groupValue: selectedDomain,
onChanged: (val) {
setState(() {
selectedDomain = val;
});
},
),
),
);
} else {
return Container(
padding: EdgeInsets.only(top: 1.0),
child: ListTile(
title: Text(
d['domain'],
style: TextStyle(
color: Colors.black45,
),
),
leading: Icon(Icons.clear, color: Colors.red,),
),
);
}
}
}

View File

@@ -52,6 +52,18 @@ class MobileBuyServiceState extends State<MobileBuyService> {
Utils.buildLine(S.of(context).your_group, widget.data['group']['name'], valueSize: 16),
);
if (widget.data['store']['id'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).store, widget.data['store']['name'], valueSize: 16),
);
}
if (widget.data['domain'] != null) {
col1.children.add(
Utils.buildLine(S.of(context).domain_name, widget.data['domain'], valueSize: 16),
);
}
if (widget.data['exists_service'] == null) {
col1.children.add(
Utils.buildLine(S.of(context).current_plan, 'N/A', valueSize: 16),

View File

@@ -335,6 +335,7 @@ class MobileCheckoutState extends State<MobileCheckout> with SingleTickerProvide
check();
},
initialLabelIndex: deliveryMethodIndex,
totalSwitches: shippingMethodLabels.length,
);
switch (position) {
case 0:

View File

@@ -189,6 +189,7 @@ class MobileNavigationDrawerState extends State<MobileNavigationDrawer> {
TextLink(S.of(context).contact_us, '/contact-us', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,),
TextLink(S.of(context).about_us, '/about-us', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,),
TextLink(S.of(context).renew_license, '/renew-license', paddingVertical: 5.0, paddingHorizontal: 10.0, closeDrawer: true,),
TextLink(S.of(context).create_a_online_store, '/contact-stores', paddingVertical: 5.0, paddingHorizontal: 10.0,),
Container(
margin: EdgeInsets.only(top: 20.0, bottom: 10.0),
child: Text(

View File

@@ -1,92 +0,0 @@
import '../../constants.dart';
import '../../utils/iframe_web.dart' if (dart.library.io) '../../utils/fake_iframe_web.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class MobileTutorials extends StatefulWidget {
const MobileTutorials({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() {
return MobileTutorialsState();
}
}
class MobileTutorialsState extends State<MobileTutorials> {
InAppWebViewController webView;
String url = "";
double progress = 0;
bool isLoadStop = false;
@override
Widget build(BuildContext context) {
if (kIsWeb) {
return Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: IFrameWeb(
width: double.maxFinite.toString(),
height: double.maxFinite.toString(),
src: Constants.TUTORIAL_URL,
),
),
],
);
} else {
print('progress: $progress');
return Stack(
children: [
InAppWebView(
initialUrlRequest: URLRequest(url: Uri.parse(Constants.TUTORIAL_URL)),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (controller, url) {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = false;
});
}
},
onLoadStop: (controller, url) async {
if (mounted) {
setState(() {
this.url = url.toString();
this.isLoadStop = true;
});
}
},
onProgressChanged: (InAppWebViewController controller, int progress) {
if (mounted) {
setState(() {
if (this.progress < 1.0) {
this.isLoadStop = false;
} else {
this.isLoadStop = true;
}
this.progress = progress / 100;
});
}
},
),
isLoadStop ? Container() :
Center(
child: CircularProgressIndicator(),
),
],
);
}
}
}

View File

@@ -13,6 +13,8 @@ import '../../store/store.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
class MobileViewBlog extends StatefulWidget {
final Key key;
final int bid;
@@ -126,11 +128,7 @@ class MobileViewBlogState extends State<MobileViewBlog> {
Container(
width: min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) - 100.0,
height: min(MediaQuery.of(context).size.width, MediaQuery.of(context).size.height) - 100.0,
child: PhotoView(
imageProvider: NetworkImage(
'https:${blog.imageUrl}',
),
),
child: Util.showImage('https:${blog.imageUrl}'),
) : SizedBox.shrink(),
decoration: BoxDecoration(
border: Border(

View File

@@ -0,0 +1,261 @@
import 'package:flutter/material.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/show_price.dart';
class ProductItem extends StatefulWidget {
final Business business;
final Product product;
final bool horizontal;
final double imageWidth;
const ProductItem(this.product, this.business, {
Key key,
this.horizontal = false,
this.imageWidth = 110,
}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductItemState();
}
class ProductItemState extends State<ProductItem> {
@override
Widget build(BuildContext context) {
return Container(
// width: 160.0,
height: widget.horizontal ? Constants.PRODUCT_ITEM_HEIGHT_H : Constants.PRODUCT_ITEM_HEIGHT_V,
padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 15.0).copyWith(bottom: 5.0),
decoration: new BoxDecoration(
color: Colors.white,
border: new Border(
bottom: new BorderSide(
color: new Color(0xFFEBEBEB),
),
),
),
child: new SizedBox.expand(
child: Container(
padding: EdgeInsets.only(left: 10.0, right: 10.0, top: 10.0, bottom: 10.0),
child: widget.horizontal ? getHorizontal(true) : getVertial(true),
),
),
);
}
Widget getHorizontal(bool onHover) {
Row row1 = Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: new EdgeInsets.all(10.0),
width: widget.imageWidth,
height: widget.imageWidth,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
],
),
),
],
);
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
row1,
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
);
}
Widget getVertial(bool onHover) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
new Container(
margin: new EdgeInsets.all(10.0),
width: widget.imageWidth,
height: widget.imageWidth,
child: GestureDetector(
child: onHover && widget.product.secondImagePath.isNotEmpty ?
Util.showImage('${widget.product.secondImagePath}',
fit: BoxFit.fill,
) :
Util.showImage('${widget.product.imagePath}',
fit: BoxFit.fill,
),
onTap: (){
_showProductDetail();
},
),
),
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
child: GestureDetector(
child: Text(
'${widget.product.name}',
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
softWrap: true,
style: new TextStyle(
fontSize: 15.0,
),
),
onTap: (){
_showProductDetail();
},
),
),
Container(
child: Text(
widget.product.description,
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: new TextStyle(
fontSize: 12.0,
color: new Color(0xFF999999),
),
),
),
new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
child: widget.business.showMonthlySold ?
Text(
S.of(context).sold_per_month_token(widget.product.monthSales.toStringAsFixed(0)),
style: new TextStyle(
fontSize: 9.0
),
) : SizedBox.shrink(),
),
ShowPrice(
widget.product.price,
regularPrice: widget.product.regularPrice,
currencySign: '\$',
fontWeight: FontWeight.bold,
),
],
),
AddRemoveButton(product: widget.product, business: widget.business, addOnly: false, onHovor: onHover,),
],
),
],
),
),
],
);
}
void _showProductDetail() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: widget.product,
business: widget.business,
)),
);
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {
});
}
});
}
}

View File

@@ -0,0 +1,152 @@
import 'package:dio/dio.dart';
import 'package:flappy_search_bar/flappy_search_bar.dart';
import 'package:flutter/material.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/product.dart';
import '../../pages/product_detail_page.dart';
import '../../utils/http_util.dart';
import '../../utils/utils.dart';
import '../../widgets/general/breadcrumbs.dart';
import '../../widgets/general/navigationbar.dart';
import 'product_item.dart';
class ProductSearch extends StatefulWidget {
final Business business;
const ProductSearch(this.business, {Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => ProductSearchState();
}
class ProductSearchState extends State<ProductSearch> {
int page = 1;
int numPerPage = 10;
int lastResultSize = 0;
double lastBottomPosition = 0;
String lastKeyword = '';
SearchBarController _controller = SearchBarController<Product>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: MiniNavigationBar(
title: S.of(context).search_product,
back: true,
breadCrumbs: [
BreadCrumb(S.of(context).search_product, null),
],
),
drawer: null,
body: SafeArea(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: NotificationListener<ScrollNotification>(
child: SearchBar(
searchBarController: _controller,
minimumChars: 2,
hintText: S.of(context).enter_keyword,
cancellationWidget: Text(
S.of(context).cancel,
),
onSearch: search,
onItemFound: (Product searchProduct, int index) {
return ProductItem(
searchProduct,
widget.business,
horizontal: true,
imageWidth: 80.0,
);
},
onError: (error) {
return Center(
child: Text("$error"),
);
},
emptyWidget: Center(
child: Text(
S.of(context).empty_result_change_keyword,
),
),
),
onNotification: (notification) {
if (notification.metrics.atEdge) {
print('fff: $page, $lastBottomPosition, ${notification.metrics.pixels}');
if (page != 0 && lastResultSize >= numPerPage && notification.metrics.pixels != 0) {
if (notification.metrics.pixels > lastBottomPosition) {
lastBottomPosition = notification.metrics.pixels;
page += 1;
_controller.replayLastSearch();
}
}
}
return true;
},
),
),
),
bottomNavigationBar: null,
);
}
Future<List<Product>> search(String keyword) async {
if (lastKeyword != keyword) {
page = 1;
}
lastKeyword = keyword;
var result = await HttpUtil.httpGet('v1/search-store-product2',
queryParameters: {
'store_id': widget.business.id,
'keyword': keyword,
'page': page,
'num_per_page': numPerPage,
},
returnError: true,
);
if (result is DioError) {
if (result.response != null) {
throw RuntimeError(result.response.data);
} else {
throw RuntimeError(result.message);
}
} else if (result != null && result is List) {
lastBottomPosition = 0;
var r = result.map((e) => Product.fromJson(e)).toList();
lastResultSize = r.length;
if (lastResultSize < numPerPage) {
page = 1;
}
return r;
}
return [];
}
@override
void initState() {
super.initState();
eventBus.on<OnCartInfoUpdated>().listen((event) {
if (mounted) {
setState(() {});
}
});
}
void _showProductDetail(Product p) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: widget.business,
)),
);
}
}

View File

@@ -1,63 +1,59 @@
import 'dart:async';
import 'dart:math';
import 'package:badges/badges.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:flutter_wisetronic/events/eventbus.dart';
import 'package:flutter_wisetronic/events/events.dart';
import 'package:flutter_wisetronic/generated/l10n.dart';
import 'package:flutter_wisetronic/models/business.dart';
import 'package:flutter_wisetronic/models/cart_info.dart';
import 'package:flutter_wisetronic/models/cart_line_item.dart';
import 'package:flutter_wisetronic/models/category_products.dart';
import 'package:flutter_wisetronic/models/comment.dart';
import 'package:flutter_wisetronic/models/product.dart';
import 'package:flutter_wisetronic/models/product_image.dart';
import 'package:flutter_wisetronic/pages/product_detail_page.dart';
import 'package:flutter_wisetronic/store/store.dart';
import 'package:flutter_wisetronic/utils/http_util.dart';
import 'package:flutter_wisetronic/utils/shop_scroll_controller.dart';
import 'package:flutter_wisetronic/utils/shop_scroll_coordinator.dart';
import 'package:flutter_wisetronic/utils/utils.dart';
import 'package:flutter_wisetronic/widgets/general/add_remove_button.dart';
import 'package:flutter_wisetronic/widgets/general/animation_point_manager.dart';
import 'package:flutter_wisetronic/widgets/general/carousel.dart';
import 'package:flutter_wisetronic/widgets/general/read_more_text.dart';
import 'package:flutter_wisetronic/widgets/general/show_price.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_wisetronic/widgets/general/sliding_up_panel.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:smooth_star_rating/smooth_star_rating.dart';
import '../../constants.dart';
import '../../events/eventbus.dart';
import '../../events/events.dart';
import '../../generated/l10n.dart';
import '../../models/business.dart';
import '../../models/cart_info.dart';
import '../../models/cart_line_item.dart';
import '../../models/category_products.dart';
import '../../models/comment.dart';
import '../../models/product.dart';
import '../../models/product_image.dart';
import '../../pages/product_detail_page.dart';
import '../../pages/store_product_search.dart';
import '../../routes.dart';
import '../../store/actions.dart';
import '../../store/store.dart';
import '../../utils/http_util.dart';
import '../../utils/shop_scroll_controller.dart';
import '../../utils/shop_scroll_coordinator.dart';
import '../../utils/util_web.dart'
if (dart.library.io) '../../utils/util_io.dart';
import '../../utils/utils.dart';
import '../../widgets/general/add_remove_button.dart';
import '../../widgets/general/animation_point_manager.dart';
import '../../widgets/general/carousel.dart';
import '../../widgets/general/product_item.dart';
import '../../widgets/general/read_more_text.dart';
import '../../widgets/general/sliding_up_panel.dart';
import '../../widgets/general/style.dart';
import '../../utils/util_io.dart' if (dart.library.html) '../../utils/util_web.dart';
import 'product_item.dart';
import 'product_search.dart';
import 'shopping_cart_bar.dart';
class MobileShop extends StatefulWidget {
final int businessId;
const MobileShop({Key key, this.businessId}) : super(key: key);
@override
State<StatefulWidget> createState() => MobileShopState();
}
MediaQueryData mediaQuery;
double statusBarHeight;
double screenWidth;
double screenHeight;
class MobileShopState extends State<MobileShop>
class Shop extends StatefulWidget {
final int businessId;
const Shop({Key key, this.businessId}) : super(key: key);
@override
State<StatefulWidget> createState() => ShopState();
}
class ShopState extends State<Shop>
with TickerProviderStateMixin, AutomaticKeepAliveClientMixin {
GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
Business _business;
@@ -75,7 +71,7 @@ class MobileShopState extends State<MobileShop>
static const num _categoryHeight = 50.0;
static const num _categoryDescHeight = 50.0;
static const num _productHeight = 115.0;
static const num _productHeight = Constants.PRODUCT_ITEM_HEIGHT_H;
int _categoryIndex = 0;
bool _categoryIndexChange = false;
@@ -103,7 +99,7 @@ class MobileShopState extends State<MobileShop>
int _commentPageCount = 1;
bool _commentLoadingFinish = false;
RefreshController _commentRefreshController =
RefreshController(initialRefresh: true);
RefreshController(initialRefresh: true);
PanelController panelController = PanelController();
SlidingUpPanel _slidUpShoppingCart;
@@ -256,9 +252,33 @@ class MobileShopState extends State<MobileShop>
padding: EdgeInsets.only(
left: 10.0,
top: 10.0,
right: 10.0,
bottom: 10.0,
),
width: 150.0,
margin: EdgeInsets.symmetric(horizontal: 5.0, vertical: 5.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
color: Colors.white,
border: Border(
top: BorderSide(
width: 1.0,
color: Colors.black12,
),
bottom: BorderSide(
width: 1.0,
color: Colors.black12,
),
left: BorderSide(
width: 1.0,
color: Colors.black12,
),
right: BorderSide(
width: 1.0,
color: Colors.black12,
),
),
),
width: 160.0,
height: 220.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -267,6 +287,7 @@ class MobileShopState extends State<MobileShop>
child: Container(
child: Util.showImage(
_business.promoProducts[i].imagePath,
width: 110.0,
),
),
onTap: () {
@@ -308,7 +329,7 @@ class MobileShopState extends State<MobileShop>
pinned: false,
floating: true,
delegate: _SliverAppBarDelegate2(
minHeight: 250.0,
minHeight: 256.0,
maxHeight: 260.0,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
@@ -359,7 +380,7 @@ class MobileShopState extends State<MobileShop>
icon: Icon(Icons.arrow_back_ios),
onPressed: () {
if (_animationFinish) {
Routes.router.pop(context);
Navigator.of(context).maybePop();
}
}),
titleSpacing: 0.0,
@@ -371,8 +392,8 @@ class MobileShopState extends State<MobileShop>
onTap: () {
Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) {
return StoreProductSearch(_business);
}));
return ProductSearch(_business);
}));
},
),
),
@@ -540,7 +561,7 @@ class MobileShopState extends State<MobileShop>
cancelButton: CupertinoActionSheetAction(
child: Text(S.of(context).close),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
},
),
);
@@ -786,8 +807,8 @@ class MobileShopState extends State<MobileShop>
));
var duration = Duration(
seconds: (_business.distanceInfo.duration != null
? _business.distanceInfo.duration.value
: 30) +
? _business.distanceInfo.duration.value
: 30) +
_business.shippingTime * 60);
var hours = duration.inHours.remainder(60);
var minutes = duration.inMinutes.remainder(60);
@@ -922,28 +943,28 @@ class MobileShopState extends State<MobileShop>
children: <Widget>[
_business.bulletin.isNotEmpty ? Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
children: <Widget>[
Container(
padding:
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
EdgeInsets.only(left: 10.0, right: 5.0, bottom: 10.0),
child: Icon(
Icons.announcement,
size: 14.0,
color: Colors.white,
)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
Container(
width: mediaQuery.size.width - 30.0,
padding: EdgeInsets.only(right: 10.0, bottom: 10.0),
child: new Text(
_business.bulletin.isEmpty ? '' : _business.bulletin,
softWrap: true,
style: new TextStyle(
fontSize: 12.0, color: const Color(0xFFDDDDDD)),
// overflow: TextOverflow.ellipsis,
),
),
],
) : SizedBox.shrink(),
),
],
) : SizedBox.shrink(),
_business.description.isNotEmpty ? Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
@@ -1092,13 +1113,13 @@ class MobileShopState extends State<MobileShop>
}
Widget _buildMainContent() {
return new Row(
return Row(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
_buildCategories(),
Expanded(
child: _buildProducts(),
)
),
],
);
}
@@ -1116,7 +1137,7 @@ class MobileShopState extends State<MobileShop>
CategoryProducts cp = _categoryProducts[i];
int qtyInCategory = 0;
CartInfo cartInfo =
Utils.getCartInfoByBusiness(store.state.cartInfos, _business);
Utils.getCartInfoByBusiness(store.state.cartInfos, _business);
if (cartInfo != null &&
cartInfo.businessInfo.id == _business.id &&
cartInfo.productList != null) {
@@ -1141,14 +1162,14 @@ class MobileShopState extends State<MobileShop>
style: TextStyle(
fontSize: 13.0,
fontWeight: (cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id == Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
? Colors.lightGreen
: Colors.black87)),
// overflow: kIsWeb ? null : TextOverflow.ellipsis,
overflow: TextOverflow.ellipsis,
softWrap: true,
@@ -1178,10 +1199,10 @@ class MobileShopState extends State<MobileShop>
height: 70.0,
padding: new EdgeInsets.symmetric(horizontal: 10.0),
decoration: new BoxDecoration(
color: _categoryIndex == i ? Style.backgroundColor : null,
color: _categoryIndex == i ? Colors.white : null,
border: new Border(
bottom:
new BorderSide(color: new Color(0xFFEBEBEB)))),
new BorderSide(color: new Color(0xFFEBEBEB)))),
child: categoryRow,
),
onTap: () => _selectCategory(i),
@@ -1208,10 +1229,10 @@ class MobileShopState extends State<MobileShop>
_categoryIndexChange = true;
_listScrollController1
.animateTo(height,
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
duration: new Duration(
microseconds: 200,
),
curve: Curves.linear)
.then((value) {
_categoryIndexChange = false;
});
@@ -1316,7 +1337,7 @@ class MobileShopState extends State<MobileShop>
controller: _listScrollController1,
// itemCount: displayProductByCategoryClick ? 1 : (_categoryProducts == null ? 0 : _categoryProducts.length),
itemCount:
_categoryProducts == null ? 0 : numCategoriesHasProducts(),
_categoryProducts == null ? 0 : numCategoriesHasProducts(),
itemBuilder: (BuildContext context, int i) {
CategoryProducts cp;
cp = _categoryProducts[i];
@@ -1357,42 +1378,42 @@ class MobileShopState extends State<MobileShop>
children: <Widget>[
new Expanded(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 5.0),
child: new Text(
cp.name,
style: new TextStyle(
fontSize: 16.0,
fontWeight:
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
textBaseline: TextBaseline.alphabetic,
children: <Widget>[
new Padding(
padding: new EdgeInsets.only(right: 5.0),
child: new Text(
cp.name,
style: new TextStyle(
fontSize: 16.0,
fontWeight:
(cp.id == Constants.FEATURED_PRODUCT_ID ||
cp.id == Constants.HOT_SALE_ID)
cp.id == Constants.HOT_SALE_ID)
? FontWeight.bold
: FontWeight.normal,
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id ==
Constants.FEATURED_PRODUCT_ID)
color: (cp.id == Constants.HOT_SALE_ID)
? Colors.redAccent
: ((cp.id ==
Constants.FEATURED_PRODUCT_ID)
? Colors.lightGreen
: Colors.black87)),
overflow: TextOverflow.ellipsis,
),
),
new Visibility(
visible: cp.description.isNotEmpty,
child: new Text(
cp.description,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)),
overflow: TextOverflow.ellipsis,
),
),
replacement: const SizedBox.shrink()),
],
))
new Visibility(
visible: cp.description.isNotEmpty,
child: new Text(
cp.description,
overflow: TextOverflow.ellipsis,
style: new TextStyle(
fontSize: 10.0,
color: new Color(0xFF999999)),
),
replacement: const SizedBox.shrink()),
],
))
],
)));
for (var p in cp.products) {
@@ -1400,9 +1421,13 @@ class MobileShopState extends State<MobileShop>
children: <Widget>[],
);
pStack.children.add(new ProductItem(
product: p,
business: _business,
pStack.children.add(Container(
// width: MediaQuery.of(context).size.width - 100.0,
child: ProductItem(
p, _business,
horizontal: true,
imageWidth: 80.0,
),
));
col.children.add(pStack);
@@ -1494,129 +1519,6 @@ class MobileShopState extends State<MobileShop>
}
});
// onProductWillAddToCartSubscription =
// eventBus.on<OnProductWillAddToCart>().listen((event) {
// if (mounted) {
// itemAddToCart(event.buttonKey);
//
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
//
// if (cartInfo == null || cartInfo.productList.length == 0) {
// cartInfo = CartInfo();
// cartInfo.id = 0;
// cartInfo.amountPaid = 0.0;
// cartInfo.businessInfo = event.business;
// cartInfo.extraFeeList = [];
// cartInfo.discountList = [];
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList = [lineItem];
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (event.product.productAttributes.length > 0) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// int found = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (event.product.id == cartInfo.productList[i].product.id) {
// found = i;
// break;
// }
// }
// if (found == -1) {
// CartLineItem lineItem = _newCartLineItem(
// id: 0,
// price: event.price,
// product: event.product,
// name: event.product.name,
// description: event.description,
// quantity: 1.0);
// cartInfo.productList.add(lineItem);
// store.dispatch(new UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// } else {
// if (cartInfo.productList[found].quantity + 1.0 >
// event.product.leftNum) {
// Fluttertoast.showToast(
// msg: S.of(context).product_insufficient,
// toastLength: Toast.LENGTH_SHORT,
// gravity: ToastGravity.CENTER,
// backgroundColor: Colors.red,
// textColor: Colors.white);
// } else {
// cartInfo.productList[found].quantity += 1;
// store.dispatch(new UpdateCartInfo(
// Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// }
// }
// }
// });
// onProductWillRemoveFromCartSubscription =
// eventBus.on<OnProductWillRemoveFromCart>().listen((event) {
// if (mounted) {
// CartInfo cartInfo =
// Utils.getCartInfoByBusiness(store.state.cartInfos, event.business);
// if (cartInfo != null) {
// if (cartInfo.productList.length > 0) {
// if (event.productListIndex != -1) {
// if (cartInfo.productList[event.productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(event.productListIndex);
// } else {
// cartInfo.productList[event.productListIndex].quantity -= 1;
// }
// } else {
// int productListIndex = -1;
// for (var i = 0; i < cartInfo.productList.length; i++) {
// if (cartInfo.productList[i].product.id == event.product.id) {
// productListIndex = i;
// break;
// }
// }
// if (productListIndex != -1) {
// if (cartInfo.productList[productListIndex].quantity <= 1) {
// cartInfo.productList.removeAt(productListIndex);
// } else {
// cartInfo.productList[productListIndex].quantity -= 1;
// }
// }
// }
// }
//
// if (cartInfo.productList.length <= 0) {
// store.dispatch(UpdateCartInfo(Utils.removeCartInfoFromCartInfoList(
// store.state.cartInfos, cartInfo)));
// } else {
// store.dispatch(UpdateCartInfo(Utils.addCartInfoToCartInfoList(
// store.state.cartInfos, cartInfo)));
// }
// eventBus.fire(new OnCartInfoUpdated());
// }
// }
// });
loadProducts();
}
@@ -1630,67 +1532,71 @@ class MobileShopState extends State<MobileShop>
}
_productCurrentPage = 1;
Utils.loadProducts(
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
widget.businessId, categoryId, _productCurrentPage, false,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
// _featuredProducts = (value['featured_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
_featuredProducts = [];
// _hotSaleProducts = (value['hot_sale_products'] as List)
// .map((i) => Product.fromJson(i))
// .toList();
_hotSaleProducts = [];
_prompts = value['prompt'] as List;
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
checkActionAndClose(context);
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
Utils.showMessageDialog(context, error);
}
if (mounted) {
setState(() {
displayProductByCategoryClick =
value['display_product_by_category_click'];
displayProductByCategoryClickIndicator = '';
_business = Business.fromJson(value['business']);
_categoryProducts = (value['category_products'] as List)
.map((i) => CategoryProducts.fromJson(i))
.toList();
_featuredProducts = (value['featured_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_hotSaleProducts = (value['hot_sale_products'] as List)
.map((i) => Product.fromJson(i))
.toList();
_prompts = value['prompt'] as List;
if (_hotSaleProducts.length > 0) {
CategoryProducts hs = CategoryProducts(
Constants.HOT_SALE_ID,
widget.businessId,
S.of(context).hot_sale,
'',
'',
_hotSaleProducts);
_categoryProducts.insert(0, hs);
}
if (_featuredProducts.length > 0) {
CategoryProducts fe = CategoryProducts(
Constants.FEATURED_PRODUCT_ID,
widget.businessId,
S.of(context).featured_product,
'',
'',
_featuredProducts);
_categoryProducts.insert(0, fe);
}
checkActionAndClose(context);
if (displayProductByCategoryClick) {
_resetProductListScroll();
}
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
);
}
@@ -1700,59 +1606,59 @@ class MobileShopState extends State<MobileShop>
}
_productCurrentPage += 1;
Utils.loadProducts(widget.businessId, categoryId, _productCurrentPage, true,
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
(value) {
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
if (mounted) {
setState(() {
List<CategoryProducts> moreCategoryProducts =
(value as List).map((i) => CategoryProducts.fromJson(i)).toList();
if (moreCategoryProducts.isEmpty) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
if (moreCategoryProducts[0].products.length < Constants.ORDERS_PER_PAGE) {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
} else {
displayProductByCategoryClickIndicator =
S.of(context).pull_up_to_load_more;
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
CategoryProducts currentCp =
getCategoryProductByCategoryId(categoryId);
if (currentCp != null) {
currentCp.products.addAll(moreCategoryProducts[0].products);
} else {
_productCurrentPage = 0;
displayProductByCategoryClickIndicator =
S.of(context).end_of_the_list;
}
}
});
});
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).maybePop();
}
Utils.showMessageDialog(context, error);
}
},
(error) {
print('error: $error');
if (_isLoading) {
_isLoading = false;
Navigator.of(context).pop();
}
Utils.showMessageDialog(context, error);
}
);
}
CartLineItem _newCartLineItem(
{int id,
double price,
Product product,
String name,
String description,
double quantity}) {
double price,
Product product,
String name,
String description,
double quantity}) {
CartLineItem lineItem = CartLineItem();
lineItem.unitPrice = price;
lineItem.product = product;
@@ -1787,9 +1693,9 @@ class MobileShopState extends State<MobileShop>
context,
MaterialPageRoute(
builder: (context) => ProductDetailPage(
product: p,
business: _business,
)),
product: p,
business: _business,
)),
);
}
@@ -1925,10 +1831,10 @@ class MobileShopState extends State<MobileShop>
S.of(context).store_closed,
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -1981,10 +1887,10 @@ class MobileShopState extends State<MobileShop>
),
),
actions: <Widget>[
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(0);
},
)
@@ -2007,10 +1913,10 @@ class MobileShopState extends State<MobileShop>
title: Text(_prompt['title']),
content: Text(_prompt['message']),
actions: [
FlatButton(
TextButton(
child: Text(S.of(context).ok),
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).maybePop();
showPrompt(idx + 1);
},
),
@@ -2053,4 +1959,4 @@ class _SliverAppBarDelegate2 extends SliverPersistentHeaderDelegate {
minHeight != oldDelegate.minHeight ||
child != oldDelegate.child;
}
}
}