commit
e0a57dafb7
@ -1,3 +1,11 @@
|
|||||||
|
## [5.7.1] - 2022-02-07
|
||||||
|
|
||||||
|
* Refactor account order detail page
|
||||||
|
* Fix continuous loading if users has no orders
|
||||||
|
* New styling for tabs in the account order detail page
|
||||||
|
* Small refactor to controller loading
|
||||||
|
* Pubspec.yaml dependency updates
|
||||||
|
|
||||||
## [5.7.0] - 2022-01-29
|
## [5.7.0] - 2022-01-29
|
||||||
|
|
||||||
* Refactor product detail page
|
* Refactor product detail page
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
# WooCommerce App: Label StoreMax
|
# WooCommerce App: Label StoreMax
|
||||||
|
|
||||||
### Label StoreMax - v5.7.0
|
### Label StoreMax - v5.7.1
|
||||||
|
|
||||||
|
|
||||||
[Official WooSignal WooCommerce App](https://woosignal.com)
|
[Official WooSignal WooCommerce App](https://woosignal.com)
|
||||||
@ -45,7 +45,7 @@ Full documentation this available [here](https://woosignal.com/docs/app/label-st
|
|||||||
- Change app name, logo, customize default language, currency + more
|
- Change app name, logo, customize default language, currency + more
|
||||||
- Light and dark mode
|
- Light and dark mode
|
||||||
- Stripe, Cash On Delivery, PayPal
|
- Stripe, Cash On Delivery, PayPal
|
||||||
- Localized for en, es, pt, it, hi, fr, zh, tr, nl
|
- Localized for en, es, pt, it, hi, fr, zh, tr, nl, de
|
||||||
- Orders show as normal in WooCommerce
|
- Orders show as normal in WooCommerce
|
||||||
|
|
||||||
## Security Vulnerabilities
|
## Security Vulnerabilities
|
||||||
|
|||||||
@ -29,6 +29,8 @@ class ProductCategorySearchLoaderController
|
|||||||
category: productCategory.id.toString(),
|
category: productCategory.id.toString(),
|
||||||
page: page,
|
page: page,
|
||||||
status: "publish",
|
status: "publish",
|
||||||
stockStatus: "instock"));
|
stockStatus: "instock",
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,17 +9,15 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
||||||
import 'package:bubble_tab_indicator/bubble_tab_indicator.dart';
|
import 'package:bubble_tab_indicator/bubble_tab_indicator.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_app/app/controllers/customer_orders_loader_controller.dart';
|
|
||||||
import 'package:flutter_app/bootstrap/helpers.dart';
|
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||||
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||||
|
import 'package:flutter_app/resources/widgets/account_detail_orders_widget.dart';
|
||||||
|
import 'package:flutter_app/resources/widgets/account_detail_settings_widget.dart';
|
||||||
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||||
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
import 'package:flutter_app/resources/widgets/safearea_widget.dart';
|
||||||
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
import 'package:flutter_app/resources/widgets/woosignal_ui.dart';
|
||||||
import 'package:nylo_framework/nylo_framework.dart';
|
import 'package:nylo_framework/nylo_framework.dart';
|
||||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
|
||||||
import 'package:woosignal/models/response/order.dart';
|
|
||||||
import 'package:wp_json_api/models/responses/wc_customer_info_response.dart';
|
import 'package:wp_json_api/models/responses/wc_customer_info_response.dart';
|
||||||
import 'package:wp_json_api/wp_json_api.dart';
|
import 'package:wp_json_api/wp_json_api.dart';
|
||||||
|
|
||||||
@ -32,35 +30,16 @@ class AccountDetailPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _AccountDetailPageState extends State<AccountDetailPage>
|
class _AccountDetailPageState extends State<AccountDetailPage>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
final RefreshController _refreshController =
|
TabController _tabController;
|
||||||
RefreshController(initialRefresh: false);
|
bool _isLoading = true;
|
||||||
final CustomerOrdersLoaderController _customerOrdersLoaderController =
|
|
||||||
CustomerOrdersLoaderController();
|
|
||||||
|
|
||||||
bool _shouldStopRequests = false, _isLoading = true, _isLoadingOrders = true;
|
|
||||||
|
|
||||||
int _currentTabIndex = 0;
|
int _currentTabIndex = 0;
|
||||||
WCCustomerInfoResponse _wcCustomerInfoResponse;
|
WCCustomerInfoResponse _wcCustomerInfoResponse;
|
||||||
Widget _activeBody;
|
|
||||||
|
|
||||||
TabController _tabController;
|
|
||||||
List<Tab> _tabs = [];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_tabs = [
|
_tabController = TabController(vsync: this, length: 2);
|
||||||
Tab(text: ""),
|
_fetchWpUserData();
|
||||||
Tab(text: ""),
|
|
||||||
];
|
|
||||||
_tabController = TabController(vsync: this, length: _tabs.length);
|
|
||||||
_activeBody = AppLoaderWidget();
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
init() async {
|
|
||||||
await _fetchWpUserData();
|
|
||||||
await fetchOrders();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_fetchWpUserData() async {
|
_fetchWpUserData() async {
|
||||||
@ -93,10 +72,23 @@ class _AccountDetailPageState extends State<AccountDetailPage>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
_tabs = [
|
Widget activeBody;
|
||||||
Tab(text: trans("Orders")),
|
if (_currentTabIndex == 0) {
|
||||||
Tab(text: trans("Settings")),
|
activeBody = AccountDetailOrdersWidget();
|
||||||
];
|
} else if (_currentTabIndex == 1) {
|
||||||
|
activeBody = AccountDetailSettingsWidget(
|
||||||
|
refreshAccount: () {
|
||||||
|
setState(() {
|
||||||
|
_isLoading = true;
|
||||||
|
});
|
||||||
|
_fetchWpUserData();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeBody == null) {
|
||||||
|
return SizedBox.shrink();
|
||||||
|
}
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@ -182,13 +174,17 @@ class _AccountDetailPageState extends State<AccountDetailPage>
|
|||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
child: TabBar(
|
child: TabBar(
|
||||||
tabs: _tabs,
|
tabs: [
|
||||||
|
Tab(text: trans("Orders")),
|
||||||
|
Tab(text: trans("Settings")),
|
||||||
|
],
|
||||||
controller: _tabController,
|
controller: _tabController,
|
||||||
indicatorSize: TabBarIndicatorSize.tab,
|
indicatorSize: TabBarIndicatorSize.tab,
|
||||||
labelColor: Colors.white,
|
labelColor: Colors.white,
|
||||||
unselectedLabelColor: Colors.black87,
|
unselectedLabelColor: Colors.black87,
|
||||||
indicator: BubbleTabIndicator(
|
indicator: BubbleTabIndicator(
|
||||||
indicatorHeight: 25.0,
|
indicatorHeight: 30.0,
|
||||||
|
indicatorRadius: 5,
|
||||||
indicatorColor: Colors.black87,
|
indicatorColor: Colors.black87,
|
||||||
tabBarIndicatorSize: TabBarIndicatorSize.tab,
|
tabBarIndicatorSize: TabBarIndicatorSize.tab,
|
||||||
),
|
),
|
||||||
@ -207,7 +203,7 @@ class _AccountDetailPageState extends State<AccountDetailPage>
|
|||||||
color: ThemeColor.get(context).backgroundContainer,
|
color: ThemeColor.get(context).backgroundContainer,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(child: _activeBody),
|
Expanded(child: activeBody),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -221,259 +217,8 @@ class _AccountDetailPageState extends State<AccountDetailPage>
|
|||||||
}
|
}
|
||||||
|
|
||||||
_tabsTapped(int i) {
|
_tabsTapped(int i) {
|
||||||
|
setState(() {
|
||||||
_currentTabIndex = i;
|
_currentTabIndex = i;
|
||||||
setState(() {
|
|
||||||
if (_currentTabIndex == 0) {
|
|
||||||
_activeBody = _widgetOrders();
|
|
||||||
} else {
|
|
||||||
_activeBody = _widgetSettings();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ListView _widgetSettings() {
|
|
||||||
return ListView(
|
|
||||||
children: <Widget>[
|
|
||||||
Card(
|
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(Icons.account_circle),
|
|
||||||
title: Text(trans("Update details")),
|
|
||||||
onTap: () =>
|
|
||||||
Navigator.pushNamed(context, "/account-update").then((onValue) {
|
|
||||||
setState(() {
|
|
||||||
_isLoading = true;
|
|
||||||
});
|
|
||||||
_fetchWpUserData();
|
|
||||||
}),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Card(
|
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(Icons.local_shipping),
|
|
||||||
title: Text(trans("Shipping Details")),
|
|
||||||
onTap: () =>
|
|
||||||
Navigator.pushNamed(context, "/account-shipping-details"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Card(
|
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(Icons.credit_card),
|
|
||||||
title: Text(trans("Billing Details")),
|
|
||||||
onTap: () =>
|
|
||||||
Navigator.pushNamed(context, "/account-billing-details"),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Card(
|
|
||||||
child: ListTile(
|
|
||||||
leading: Icon(Icons.exit_to_app),
|
|
||||||
title: Text(trans("Logout")),
|
|
||||||
onTap: () => authLogout(context),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchOrders() async {
|
|
||||||
String userId = await readUserId();
|
|
||||||
if (userId == null) {
|
|
||||||
setState(() {
|
|
||||||
_isLoadingOrders = false;
|
|
||||||
_activeBody = _widgetOrders();
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
await _customerOrdersLoaderController.loadOrders(
|
|
||||||
hasResults: (result) {
|
|
||||||
if (result == false) {
|
|
||||||
_isLoadingOrders = false;
|
|
||||||
_shouldStopRequests = true;
|
|
||||||
_activeBody = _widgetOrders();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
didFinish: () => setState(() {
|
|
||||||
_isLoadingOrders = false;
|
|
||||||
_activeBody = _widgetOrders();
|
|
||||||
}),
|
|
||||||
userId: userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _widgetOrders() {
|
|
||||||
List<Order> orders = _customerOrdersLoaderController.getResults();
|
|
||||||
return _isLoadingOrders
|
|
||||||
? AppLoaderWidget()
|
|
||||||
: SmartRefresher(
|
|
||||||
enablePullDown: true,
|
|
||||||
enablePullUp: true,
|
|
||||||
footer: CustomFooter(
|
|
||||||
builder: (BuildContext context, LoadStatus mode) {
|
|
||||||
Widget body;
|
|
||||||
if (mode == LoadStatus.idle) {
|
|
||||||
body = Text(trans("pull up load"));
|
|
||||||
} else if (mode == LoadStatus.loading) {
|
|
||||||
body = CupertinoActivityIndicator();
|
|
||||||
} else if (mode == LoadStatus.failed) {
|
|
||||||
body = Text(trans("Load Failed! Click retry!"));
|
|
||||||
} else if (mode == LoadStatus.canLoading) {
|
|
||||||
body = Text(trans("release to load more"));
|
|
||||||
} else {
|
|
||||||
body = Text(trans("No more orders"));
|
|
||||||
}
|
|
||||||
return Container(
|
|
||||||
height: 55.0,
|
|
||||||
child: Center(child: body),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
controller: _refreshController,
|
|
||||||
onRefresh: _onRefresh,
|
|
||||||
onLoading: _onLoading,
|
|
||||||
child: (orders.isNotEmpty
|
|
||||||
? ListView.builder(
|
|
||||||
itemBuilder: (cxt, i) {
|
|
||||||
Order order = orders[i];
|
|
||||||
return Card(
|
|
||||||
child: ListTile(
|
|
||||||
contentPadding: EdgeInsets.only(
|
|
||||||
top: 5, bottom: 5, left: 8, right: 6),
|
|
||||||
title: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
border: Border(
|
|
||||||
bottom: BorderSide(
|
|
||||||
color: Color(0xFFFCFCFC),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
"#${order.id.toString()}",
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
order.status.capitalize(),
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
subtitle: Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 10),
|
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: <Widget>[
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Text(
|
|
||||||
formatStringCurrency(total: order.total),
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyText2
|
|
||||||
.copyWith(
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
order.lineItems.length.toString() +
|
|
||||||
" " +
|
|
||||||
trans("items"),
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyText1
|
|
||||||
.copyWith(
|
|
||||||
fontWeight: FontWeight.w600),
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
dateFormatted(
|
|
||||||
date: order.dateCreated,
|
|
||||||
formatType:
|
|
||||||
formatForDateTime(FormatType.date),
|
|
||||||
) +
|
|
||||||
"\n" +
|
|
||||||
dateFormatted(
|
|
||||||
date: order.dateCreated,
|
|
||||||
formatType:
|
|
||||||
formatForDateTime(FormatType.time),
|
|
||||||
),
|
|
||||||
textAlign: TextAlign.right,
|
|
||||||
style: Theme.of(context)
|
|
||||||
.textTheme
|
|
||||||
.bodyText1
|
|
||||||
.copyWith(
|
|
||||||
fontWeight: FontWeight.w400,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
trailing: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(Icons.chevron_right),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
onTap: () => _viewProfileDetail(i),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
itemCount: orders.length,
|
|
||||||
)
|
|
||||||
: Center(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
Icon(
|
|
||||||
Icons.shopping_cart,
|
|
||||||
color: Colors.black54,
|
|
||||||
size: 40,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
trans("No orders found"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onRefresh() async {
|
|
||||||
_customerOrdersLoaderController.clear();
|
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchOrders();
|
|
||||||
_refreshController.refreshCompleted();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _onLoading() async {
|
|
||||||
await fetchOrders();
|
|
||||||
|
|
||||||
if (mounted) {
|
|
||||||
setState(() {});
|
|
||||||
if (_shouldStopRequests) {
|
|
||||||
_refreshController.loadNoData();
|
|
||||||
} else {
|
|
||||||
_refreshController.loadComplete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_viewProfileDetail(int i) => Navigator.pushNamed(
|
|
||||||
context,
|
|
||||||
"/account-order-detail",
|
|
||||||
arguments: _customerOrdersLoaderController.getResults()[i].id,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,10 +94,12 @@ class _BrowseCategoryPageState extends NyState<BrowseCategoryPage> {
|
|||||||
|
|
||||||
void _onRefresh() async {
|
void _onRefresh() async {
|
||||||
_productCategorySearchLoaderController.clear();
|
_productCategorySearchLoaderController.clear();
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchProducts();
|
await fetchProducts();
|
||||||
_refreshController.refreshCompleted();
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onLoading() async {
|
void _onLoading() async {
|
||||||
|
|||||||
@ -83,10 +83,12 @@ class _BrowseSearchState extends NyState<BrowseSearchPage> {
|
|||||||
|
|
||||||
void _onRefresh() async {
|
void _onRefresh() async {
|
||||||
_productSearchLoaderController.clear();
|
_productSearchLoaderController.clear();
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchProducts();
|
await fetchProducts();
|
||||||
_refreshController.refreshCompleted();
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onLoading() async {
|
void _onLoading() async {
|
||||||
|
|||||||
@ -175,10 +175,12 @@ class _ProductReviewsPageState extends NyState<ProductReviewsPage> {
|
|||||||
|
|
||||||
_onRefresh() async {
|
_onRefresh() async {
|
||||||
_productReviewsLoaderController.clear();
|
_productReviewsLoaderController.clear();
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchProductReviews();
|
await fetchProductReviews();
|
||||||
_refreshController.refreshCompleted();
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLoading() async {
|
_onLoading() async {
|
||||||
|
|||||||
@ -0,0 +1,246 @@
|
|||||||
|
// Label StoreMax
|
||||||
|
//
|
||||||
|
// Created by Anthony Gordon.
|
||||||
|
// 2022, WooSignal Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_app/app/controllers/customer_orders_loader_controller.dart';
|
||||||
|
import 'package:flutter_app/bootstrap/helpers.dart';
|
||||||
|
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||||
|
import 'package:flutter_app/resources/widgets/app_loader_widget.dart';
|
||||||
|
import 'package:nylo_framework/nylo_framework.dart';
|
||||||
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||||
|
import 'package:woosignal/models/response/order.dart';
|
||||||
|
|
||||||
|
class AccountDetailOrdersWidget extends StatefulWidget {
|
||||||
|
@override
|
||||||
|
_AccountDetailOrdersWidgetState createState() =>
|
||||||
|
_AccountDetailOrdersWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AccountDetailOrdersWidgetState extends State<AccountDetailOrdersWidget> {
|
||||||
|
bool _isLoadingOrders = true, _shouldStopRequests = false;
|
||||||
|
final RefreshController _refreshController =
|
||||||
|
RefreshController(initialRefresh: false);
|
||||||
|
final CustomerOrdersLoaderController _customerOrdersLoaderController =
|
||||||
|
CustomerOrdersLoaderController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
fetchOrders();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
List<Order> orders = _customerOrdersLoaderController.getResults();
|
||||||
|
|
||||||
|
if (_isLoadingOrders == true) {
|
||||||
|
return AppLoaderWidget();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orders.isEmpty) {
|
||||||
|
return Center(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(
|
||||||
|
Icons.shopping_cart,
|
||||||
|
color: Colors.black54,
|
||||||
|
size: 40,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
trans("No orders found"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SmartRefresher(
|
||||||
|
enablePullDown: true,
|
||||||
|
enablePullUp: true,
|
||||||
|
footer: CustomFooter(
|
||||||
|
builder: (BuildContext context, LoadStatus mode) {
|
||||||
|
Widget body;
|
||||||
|
if (mode == LoadStatus.idle) {
|
||||||
|
body = Text(trans("pull up load"));
|
||||||
|
} else if (mode == LoadStatus.loading) {
|
||||||
|
body = CupertinoActivityIndicator();
|
||||||
|
} else if (mode == LoadStatus.failed) {
|
||||||
|
body = Text(trans("Load Failed! Click retry!"));
|
||||||
|
} else if (mode == LoadStatus.canLoading) {
|
||||||
|
body = Text(trans("release to load more"));
|
||||||
|
} else {
|
||||||
|
body = Text(trans("No more orders"));
|
||||||
|
}
|
||||||
|
return Container(
|
||||||
|
height: 55.0,
|
||||||
|
child: Center(child: body),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
controller: _refreshController,
|
||||||
|
onRefresh: _onRefresh,
|
||||||
|
onLoading: _onLoading,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (context, i) {
|
||||||
|
Order order = orders[i];
|
||||||
|
return Card(
|
||||||
|
child: ListTile(
|
||||||
|
contentPadding: EdgeInsets.only(
|
||||||
|
top: 5,
|
||||||
|
bottom: 5,
|
||||||
|
left: 8,
|
||||||
|
right: 6,
|
||||||
|
),
|
||||||
|
title: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
border: Border(
|
||||||
|
bottom: BorderSide(
|
||||||
|
color: Color(0xFFFCFCFC),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
"#${order.id.toString()}",
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
order.status.capitalize(),
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 10),
|
||||||
|
child: Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: <Widget>[
|
||||||
|
Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Text(
|
||||||
|
formatStringCurrency(total: order.total),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyText2
|
||||||
|
.copyWith(fontWeight: FontWeight.w600),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
order.lineItems.length.toString() +
|
||||||
|
" " +
|
||||||
|
trans("items"),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodyText1
|
||||||
|
.copyWith(fontWeight: FontWeight.w600),
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
dateFormatted(
|
||||||
|
date: order.dateCreated,
|
||||||
|
formatType: formatForDateTime(FormatType.date),
|
||||||
|
) +
|
||||||
|
"\n" +
|
||||||
|
dateFormatted(
|
||||||
|
date: order.dateCreated,
|
||||||
|
formatType: formatForDateTime(FormatType.time),
|
||||||
|
),
|
||||||
|
textAlign: TextAlign.right,
|
||||||
|
style: Theme.of(context).textTheme.bodyText1.copyWith(
|
||||||
|
fontWeight: FontWeight.w400,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
trailing: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: <Widget>[
|
||||||
|
Icon(Icons.chevron_right),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => _viewOrderDetail(i, order.id),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
itemCount: orders.length,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onRefresh() async {
|
||||||
|
_customerOrdersLoaderController.clear();
|
||||||
|
await fetchOrders();
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onLoading() async {
|
||||||
|
await fetchOrders();
|
||||||
|
|
||||||
|
if (mounted) {
|
||||||
|
setState(() {});
|
||||||
|
if (_shouldStopRequests) {
|
||||||
|
_refreshController.loadNoData();
|
||||||
|
} else {
|
||||||
|
_refreshController.loadComplete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchOrders() async {
|
||||||
|
String userId = await readUserId();
|
||||||
|
if (userId == null) {
|
||||||
|
setState(() {
|
||||||
|
_isLoadingOrders = false;
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await _customerOrdersLoaderController.loadOrders(
|
||||||
|
hasResults: (result) {
|
||||||
|
if (result == false) {
|
||||||
|
setState(() {
|
||||||
|
_isLoadingOrders = false;
|
||||||
|
_shouldStopRequests = true;
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
didFinish: () => setState(() {
|
||||||
|
_isLoadingOrders = false;
|
||||||
|
}),
|
||||||
|
userId: userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
_viewOrderDetail(int i, int orderId) => Navigator.pushNamed(
|
||||||
|
context,
|
||||||
|
"/account-order-detail",
|
||||||
|
arguments: orderId,
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
// Label StoreMax
|
||||||
|
//
|
||||||
|
// Created by Anthony Gordon.
|
||||||
|
// 2022, WooSignal Ltd. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_app/bootstrap/shared_pref/sp_auth.dart';
|
||||||
|
import 'package:nylo_framework/nylo_framework.dart';
|
||||||
|
|
||||||
|
class AccountDetailSettingsWidget extends StatelessWidget {
|
||||||
|
const AccountDetailSettingsWidget({Key key, @required this.refreshAccount})
|
||||||
|
: super(key: key);
|
||||||
|
final Function refreshAccount;
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ListView(
|
||||||
|
children: <Widget>[
|
||||||
|
Card(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.account_circle),
|
||||||
|
title: Text(trans("Update details")),
|
||||||
|
onTap: () =>
|
||||||
|
Navigator.pushNamed(context, "/account-update").then((onValue) {
|
||||||
|
refreshAccount();
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Card(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.local_shipping),
|
||||||
|
title: Text(trans("Shipping Details")),
|
||||||
|
onTap: () =>
|
||||||
|
Navigator.pushNamed(context, "/account-shipping-details"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Card(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.credit_card),
|
||||||
|
title: Text(trans("Billing Details")),
|
||||||
|
onTap: () =>
|
||||||
|
Navigator.pushNamed(context, "/account-billing-details"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Card(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Icon(Icons.exit_to_app),
|
||||||
|
title: Text(trans("Logout")),
|
||||||
|
onTap: () => authLogout(context),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -18,6 +18,7 @@ class AppLoaderWidget extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool isDark = (Theme.of(context).brightness == Brightness.dark);
|
bool isDark = (Theme.of(context).brightness == Brightness.dark);
|
||||||
return SpinKitDoubleBounce(
|
return SpinKitDoubleBounce(
|
||||||
color: Color(!isDark ? 0xFF424242 : 0xFFC7C7C7));
|
color: Color(!isDark ? 0xFF424242 : 0xFFC7C7C7),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -122,10 +122,12 @@ class _MelloThemeWidgetState extends State<MelloThemeWidget> {
|
|||||||
|
|
||||||
_onRefresh() async {
|
_onRefresh() async {
|
||||||
_productLoaderController.clear();
|
_productLoaderController.clear();
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchProducts();
|
await fetchProducts();
|
||||||
_refreshController.refreshCompleted();
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLoading() async {
|
_onLoading() async {
|
||||||
|
|||||||
@ -209,10 +209,12 @@ class _NoticHomeWidgetState extends State<NoticHomeWidget> {
|
|||||||
|
|
||||||
_onRefresh() async {
|
_onRefresh() async {
|
||||||
_productLoaderController.clear();
|
_productLoaderController.clear();
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchProducts();
|
await fetchProducts();
|
||||||
_refreshController.refreshCompleted();
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshController.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLoading() async {
|
_onLoading() async {
|
||||||
|
|||||||
@ -132,10 +132,12 @@ class _ProductDetailUpsellWidgetState extends State<ProductDetailUpsellWidget> {
|
|||||||
|
|
||||||
_onRefresh() async {
|
_onRefresh() async {
|
||||||
_productLoaderController.clear();
|
_productLoaderController.clear();
|
||||||
_shouldStopRequests = false;
|
|
||||||
|
|
||||||
await fetchProducts();
|
await fetchProducts();
|
||||||
_refreshControllerUpsell.refreshCompleted();
|
|
||||||
|
setState(() {
|
||||||
|
_shouldStopRequests = false;
|
||||||
|
_refreshControllerUpsell.refreshCompleted(resetFooterState: true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_onLoading() async {
|
_onLoading() async {
|
||||||
|
|||||||
@ -377,7 +377,7 @@ packages:
|
|||||||
name: flutter_widget_from_html
|
name: flutter_widget_from_html
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.8.4"
|
version: "0.8.5"
|
||||||
flutter_widget_from_html_core:
|
flutter_widget_from_html_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -447,7 +447,7 @@ packages:
|
|||||||
name: fwfh_webview
|
name: fwfh_webview
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.2+1"
|
version: "0.6.2+2"
|
||||||
glob:
|
glob:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
# Official WooSignal App Template for WooCommerce
|
# Official WooSignal App Template for WooCommerce
|
||||||
|
|
||||||
# Label StoreMax
|
# Label StoreMax
|
||||||
# Version: 5.7.0
|
# Version: 5.7.1
|
||||||
# Author: Anthony Gordon
|
# Author: Anthony Gordon
|
||||||
# Homepage: https://woosignal.com
|
# Homepage: https://woosignal.com
|
||||||
# Documentation: https://woosignal.com/docs/app/label-storemax
|
# Documentation: https://woosignal.com/docs/app/label-storemax
|
||||||
@ -25,7 +25,7 @@ environment:
|
|||||||
sdk: ">=2.7.0 <3.0.0"
|
sdk: ">=2.7.0 <3.0.0"
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
google_fonts: ^2.2.0
|
google_fonts: 2.2.0
|
||||||
analyzer: ^1.5.0
|
analyzer: ^1.5.0
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
page_transition: ^2.0.5
|
page_transition: ^2.0.5
|
||||||
@ -51,7 +51,7 @@ dependencies:
|
|||||||
flutter_spinkit: ^5.1.0
|
flutter_spinkit: ^5.1.0
|
||||||
auto_size_text: ^3.0.0
|
auto_size_text: ^3.0.0
|
||||||
html: ^0.15.0
|
html: ^0.15.0
|
||||||
flutter_widget_from_html: ^0.8.4
|
flutter_widget_from_html: ^0.8.5
|
||||||
flutter_rating_bar: ^4.0.0
|
flutter_rating_bar: ^4.0.0
|
||||||
flutter_staggered_grid_view: ^0.4.1
|
flutter_staggered_grid_view: ^0.4.1
|
||||||
# firebase_messaging: ^11.2.3
|
# firebase_messaging: ^11.2.3
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user