initial commit to gitea
This commit is contained in:
464
lib/widgets/desktop/create_online_store_1.dart
Normal file
464
lib/widgets/desktop/create_online_store_1.dart
Normal 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,),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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',
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -329,7 +329,7 @@ class DesktopContactUsState extends State<DesktopContactUs> {
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -78,7 +78,7 @@ class DesktopCouponsState extends State<DesktopCoupons> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -399,7 +399,7 @@ class DesktopEditAddressState extends State<DesktopEditAddress> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).edit_address,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -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,)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -48,7 +48,7 @@ class MyCardsState extends State<DesktopMyCards> {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -324,7 +324,7 @@ class DesktopNewAddressState extends State<DesktopNewAddress> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).new_address,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -62,7 +62,7 @@ class DesktopNewCommentState extends State<DesktopNewComment> {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).new_comment,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -958,7 +958,7 @@ class DesktopOrderDetailState extends State<DesktopOrderDetail> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -345,7 +345,7 @@ class DesktopPayNowState extends State<DesktopPayNow> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -60,7 +60,7 @@ class DesktopPlainPageState extends State<DesktopPlainPage> {
|
||||
));
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -79,7 +79,7 @@ class DesktopProductDetailPageState extends State<DesktopProductDetailPage>
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).shop,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -167,7 +167,7 @@ class DesktopRenewLicenseState extends State<DesktopRenewLicense> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -136,7 +136,7 @@ class DesktopRenewMiniOfficeState extends State<DesktopRenewMiniOffice> {
|
||||
);
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).blog,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -45,7 +45,7 @@ class DesktopSearchPlaceState extends State<DesktopSearchPlace> {
|
||||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: NavigationBar(
|
||||
appBar: MiniNavigationBar(
|
||||
title: S.of(context).search_place,
|
||||
back: true,
|
||||
breadCrumbs: [
|
||||
|
||||
@@ -288,7 +288,7 @@ class DesktopSetPasswordState extends State<DesktopSetPassword> {
|
||||
);
|
||||
},
|
||||
queryParameters: {
|
||||
'action': 'reset_password',
|
||||
'action': 'create_user',
|
||||
},
|
||||
isFormData: true,
|
||||
body: {
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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}'),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
280
lib/widgets/desktop/product_item.dart
Normal file
280
lib/widgets/desktop/product_item.dart
Normal 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(() {
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
181
lib/widgets/desktop/product_search.dart
Normal file
181
lib/widgets/desktop/product_search.dart
Normal 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,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
297
lib/widgets/desktop/shop.dart
Normal file
297
lib/widgets/desktop/shop.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
70
lib/widgets/desktop/shop_bulletin.dart
Normal file
70
lib/widgets/desktop/shop_bulletin.dart
Normal 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();
|
||||
}
|
||||
|
||||
}
|
||||
431
lib/widgets/desktop/shop_products.dart
Normal file
431
lib/widgets/desktop/shop_products.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
185
lib/widgets/desktop/shop_promote.dart
Normal file
185
lib/widgets/desktop/shop_promote.dart
Normal 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,
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
79
lib/widgets/desktop/shopping_cart_widget.dart
Normal file
79
lib/widgets/desktop/shopping_cart_widget.dart
Normal 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(() {
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user