Closed Kimsoer closed 1 month ago
Hi @Kimsoer , I was not able to try your code because we are very busy this week with some work but I think you need to use the AppLifecycleState of the app to do what you want after the app is back on the foreground. Take a look at following article where @FilledStacks explains how to do it.
https://www.filledstacks.com/post/flutter-application-life-cycle-management/
Thank you so much @ferrarafer , I used to try it already like your mention, what my problem is not the cycle because the real time data is trigger and data log is coming what the issue , the state is not re-build the new data trigger from real time rabbit mq
@Kimsoer can you please show the full code of the view and the viewmodel ? Because the code you above is very difficult to read and also I'm seeing things I don't like.
Why are you doing this ?
setBusy(true);
rebuildUi();
When you execute setBusy(true) the view is rebuild.
@ferrarafer this case, i want to have loading, and rebuildUi(), I am not sure , is it wrong way?
import 'dart:convert';
import 'package:custom_pop_up_menu/custom_pop_up_menu.dart';
import 'package:flutter/material.dart';
import 'package:kds_flutter/core/enums/local_storage.dart';
import 'package:kds_flutter/core/extension/extension.dart';
import 'package:kds_flutter/core/models/requests/order_request.dart';
import 'package:kds_flutter/core/models/responses/group_channel_product_entity.dart';
import 'package:kds_flutter/core/models/responses/group_product_detail_response_entity.dart';
import 'package:kds_flutter/core/models/responses/group_products_response.dart';
import 'package:kds_flutter/core/models/responses/receipt_data_response_entity.dart' as dataPrint;
import 'package:kds_flutter/core/models/responses/table_order_detail_entity.dart';
import 'package:kds_flutter/core/models/responses/table_orders_response_entity.dart';
import 'package:kds_flutter/core/models/responses/table_orders_response_entity.dart' as tblOrder;
import 'package:kds_flutter/core/models/responses/timer_setting_entity.dart';
import 'package:kds_flutter/core/models/responses/verify_pin_code_response_entity.dart';
import 'package:kds_flutter/core/utils/global_function.dart';
import 'package:kds_flutter/services/api_service_provider.dart';
import 'package:kds_flutter/services/local_service.dart';
import 'package:kds_flutter/services/rabbit_mq_service.dart';
import 'package:kds_flutter/services/stomp_client_service.dart';
import 'package:kds_flutter/ui/common/app_colors.dart';
import 'package:kds_flutter/ui/common/app_strings.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:stacked/stacked.dart';
import 'package:stacked_services/stacked_services.dart';
import 'package:stacked_themes/stacked_themes.dart';
import '../../../app/app.locator.dart';
import '../../../core/models/popup_filter_model.dart';
class HomeViewModel extends BaseViewModel {
final GlobalKey<ScaffoldState> scaffoldKey = GlobalKey<ScaffoldState>();
final _dialogService = locator<DialogService>();
final _navigationService = locator<NavigationService>();
BuildContext context;
HomeViewModel(this.context);
int segmentFilter = 1;
bool isVisibleSidebar = true;
bool isVisibleLayout = true;
bool isVisibleDetailProduct = false;
bool isMode = true;
bool isFilterStatus = false;
bool networkConnection = true;
bool openInfoConnection = false;
List<PopupFilterModel> selectedFilter = [];
bool isEdit = false;
String? tableOrderGid = "";
int currentPage = 0;
CustomPopupMenuController menuController = CustomPopupMenuController();
String selectGroupProduct = "";
var verifyPinCodeResponse = VerifyPinCodeResponseEntity();
var tableOrdersResponse = TableOrdersResponseEntity();
var groupProductResponse = GroupProductsResponse();
GroupChannelProductEntity groupChannelProductEntity = GroupChannelProductEntity();
bool isUpdateStatus = false;
GroupProductDetailResponseEntity groupProductDetailResponse = GroupProductDetailResponseEntity();
dataPrint.ReceiptDataResponseEntity receiptDataResponse = dataPrint.ReceiptDataResponseEntity();
var tableOrderDetail = TableOrderDetailEntity();
int currentSubIndex = 0;
int currentIndex = 0;
var repositoryService = ApiProviderService().getRestClient();
var filterOpenOrClose = "OPEN";
var refreshController = RefreshController(initialRefresh: false, initialLoadStatus: LoadStatus.idle);
var timerSetting = TimerSettingEntity();
var rabbitMqService = RabbitMqService();
bool isLogout = false;
getInstance() async {
setBusy(false);
clearErrors();
getTheme();
currentPage = 1;
await getTableOrderData(isRefresh: true);
await listGroupProductQty();
var dataResponse = await LocalService().getSavedValue(LocalDataFieldName.pinCodeInfo);
verifyPinCodeResponse = VerifyPinCodeResponseEntity.fromJson(dataResponse);
///Loading data real time
await getDataRealTimeStomp();
setInitialised(true);
rebuildUi();
}
/// stomp server
getDataRealTimeStomp() async {
await StompClientService(onMessageReceived: (message) async {
var data = jsonDecode(message);
if (data["action"] == "kds-newdata" && data["service"] == "UPDATE_GROUP_SUM_PRODUCT") {
await listGroupProductQty();
}
if (data["action"] == "kds-newdata" && data["service"] == "GET_NEW_ORDER") {
await getTableOrderData();
}
}).connectStompServer();
rebuildUi();
}
/// get theme mode
getTheme() async {
var mode = getThemeManager(context).selectedThemeMode;
if (mode == ThemeMode.dark) {
isMode = false;
} else {
isMode = true;
}
rebuildUi();
}
/// get order list
bool isRefreshTableOrder = false;
getTableOrderData({bool? isRefresh}) async {
try {
isRefreshTableOrder = isRefresh ?? false;
rebuildUi();
if (isRefresh ?? false) {
setBusyForObject(tableOrdersResponse, true);
rebuildUi();
}
/// set filter to order request
List<String> filters = [];
for (var item in selectedFilter) {
filters.add("${item.value}");
}
currentPage = 1;
OrderRequest orderRequest = OrderRequest(
perPage: 10,
currentPage: 1,
option: filterOpenOrClose,
filters: filters,
);
var response = await ApiProviderService().getRestClient().getOrder(orderRequest);
if (response.response.statusCode == 200 && response.response.data != null) {
if (tableOrdersResponse.data?.tableOrders?.isNotEmpty ?? false) {
tableOrdersResponse.data?.tableOrders?.clear();
}
tableOrdersResponse = TableOrdersResponseEntity.fromJson(response.data);
}
} catch (error) {
GlobalFunction.onHttpRequestFail(error, this);
} finally {
if (isRefresh ?? false) {
setBusyForObject(tableOrdersResponse, false);
rebuildUi();
}
isRefreshTableOrder = true;
rebuildUi();
}
}
/// get list order more
getTableOrderDataMore() async {
try {
if (currentPage < (tableOrdersResponse.data?.meta?.lastPage ?? 0)) {
currentPage++;
/// set filter to order request
List<String> filters = [];
for (var item in selectedFilter) {
filters.add("${item.value}");
}
OrderRequest orderRequest = OrderRequest(
perPage: 10,
currentPage: currentPage,
option: filterOpenOrClose,
filters: filters,
);
var response = await ApiProviderService().getRestClient().getOrder(orderRequest);
if (response.response.statusCode == 200) {
tableOrdersResponse.data?.meta = tblOrder.TableOrdersResponseDataMeta.fromJson(response.response.data['data']['meta']);
for (var element in (response.response.data['data']['table_orders'] ?? [])) {
tableOrdersResponse.data?.tableOrders?.add(tblOrder.TableOrdersResponseDataTableOrders.fromJson(element));
}
}
}
} catch (error) {
GlobalFunction.onHttpRequestFail(error, this);
} finally {
rebuildUi();
refreshController.loadComplete();
}
}
/// list sidebar group product quantity
listGroupProductQty() async {
try {
setBusyForObject(groupProductResponse, true);
rebuildUi();
var response = await ApiProviderService().getRestClient().getGroupProductQty();
if (response.response.statusCode == 200 && response.response.data != null) {
groupProductResponse = GroupProductsResponse.fromJson(response.data);
}
} catch (error) {
GlobalFunction.onHttpRequestFail(error, this);
} finally {
setBusyForObject(groupProductResponse, false);
rebuildUi();
}
}
statusColor(String status) {
var color = color50;
if (status == pending) {
color = colorAF;
} else if (status == reCooking || status == cooking) {
color = bgColor4D;
}
return color;
}
statusTextColor(String status) {
var color = Theme.of(context).color54E0(context);
if (status == dispatch) {
color = Theme.of(context).color80A0(context);
} else if (status == cancelled) {
color = color6A.withOpacity(0.75);
}
return color;
}
statusOptionTextColor(String status) {
var color = Theme.of(context).color54E0(context);
if (status == dispatch) {
color = Theme.of(context).color80A0(context);
} else if (status == cancelled) {
color = color6A.withOpacity(0.75);
} else {
color = colorC7;
}
return color;
}
bool isClosed(String status) {
return status == dispatch;
}
}
import 'package:flutter/material.dart';
import 'package:kds_flutter/core/extension/extension.dart';
import 'package:kds_flutter/ui/views/home/home_viewmodel.dart';
import 'package:kds_flutter/ui/views/home/widget/list_layout_widget.dart';
import 'package:kds_flutter/ui/views/home/widget/sidebar_widget.dart';
import 'package:stacked/stacked.dart';
class HomeView extends StatefulWidget {
const HomeView({Key? key}) : super(key: key);
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
@override
Widget build(BuildContext context) {
return ViewModelBuilder<HomeViewModel>.reactive(
viewModelBuilder: () => HomeViewModel(context),
disposeViewModel: false,
onViewModelReady: (viewModel) => viewModel.getInstance(),
builder: (context, viewModel, child) {
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: Stack(
alignment: Alignment.center,
children: [
Column(
children: [
/// main contents
Expanded(
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
/// side bar
Visibility(
visible: viewModel.isVisibleSidebar,
maintainAnimation: true,
maintainState: true,
child: const SideBarWidget(),
),
/// content
Expanded(
child: Stack(
children: [
/// list layout
if (viewModel.isVisibleLayout && !viewModel.isVisibleDetailProduct)
AnimatedOpacity(
opacity: viewModel.isVisibleLayout ? 1.0 : 0.0,
duration: const Duration(milliseconds: 500),
child: const ListLayoutWidget(),
),
],
),
)
],
),
),
],
),
/// loading when logout
if (viewModel.isLogout || viewModel.isRefreshTableOrder == false)
Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
color: Theme.of(context).bgColorFF1E(context).withOpacity(0.5),
child: Center(
child: CircularProgressIndicator.adaptive(
valueColor: AlwaysStoppedAnimation<Color>(Theme.of(context).primaryColor),
),
),
),
],
),
),
);
});
}
}
import 'package:badges/badges.dart' as badges;
import 'package:flutter/material.dart';
import 'package:kds_flutter/core/extension/extension.dart';
import 'package:kds_flutter/ui/common/app_constant.dart';
import 'package:kds_flutter/ui/components/cache_network_image_component.dart';
import 'package:kds_flutter/ui/views/home/home_viewmodel.dart';
import 'package:kds_flutter/ui/views/home/shimmers/sidebar_shimmer.dart';
import 'package:stacked/stacked.dart';
class SideBarWidget extends ViewModelWidget<HomeViewModel> {
const SideBarWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, HomeViewModel viewModel) {
var data = viewModel.groupProductResponse.data?.products;
return (viewModel.groupProductResponse.data?.products?.isNotEmpty ?? false)
? Container(
width: 120,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(color: Theme.of(context).bgColorFF1E(context)),
child: ListView.builder(
itemCount: data?.length ?? 0,
shrinkWrap: true,
padding: const EdgeInsets.all(0),
itemBuilder: (BuildContext context, int index) {
var item = data?.elementAt(index);
return GestureDetector(
onTap: () {},
child: Container(
color: viewModel.selectGroupProduct == (item?.globalId ?? "") ? Theme.of(context).bgColorEF12(context) : Colors.transparent,
padding: const EdgeInsets.symmetric(vertical: 20),
alignment: Alignment.center,
child: badges.Badge(
ignorePointer: false,
badgeAnimation: const badges.BadgeAnimation.slide(toAnimate: false),
position: badges.BadgePosition.topEnd(end: -5, top: -10),
badgeContent: Container(
width: 28,
height: 28,
alignment: Alignment.center,
child: Text(
"${item?.quantity}",
style: text14(context).copyWith(
color: Colors.white,
),
textAlign: TextAlign.center,
),
),
child: ClipRRect(
borderRadius: BorderRadius.circular(80),
child: CacheNetworkImageComponent(
height: 80,
width: 80,
radius: 80,
boxFix: BoxFit.cover,
imageUrl: item?.imageUrl,
),
),
),
),
);
},
),
)
: FutureBuilder(
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
/// loading
if (snapshot.connectionState == ConnectionState.waiting || viewModel.busy(viewModel.groupProductResponse)) {
return Container(
width: 120,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(color: Theme.of(context).bgColorFF1E(context)),
child: const SideBarShimmer(),
);
}
/// empty
return Container(
width: 120,
height: MediaQuery.of(context).size.height,
decoration: BoxDecoration(color: Theme.of(context).bgColorFF1E(context)),
);
},
future: Future.delayed(const Duration(seconds: 0)),
);
}
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:kds_flutter/core/extension/extension.dart';
import 'package:kds_flutter/generated/locale_keys.g.dart';
import 'package:kds_flutter/ui/common/app_colors.dart';
import 'package:kds_flutter/ui/common/app_constant.dart';
import 'package:kds_flutter/ui/common/app_strings.dart';
import 'package:kds_flutter/ui/components/cache_network_image_component.dart';
import 'package:kds_flutter/ui/components/empty_component.dart';
import 'package:kds_flutter/ui/views/home/home_viewmodel.dart';
import 'package:kds_flutter/ui/views/home/shimmers/list_layout_shimmer.dart';
import 'package:kds_flutter/ui/views/home/widget/popup_increase_timer.dart';
import 'package:kds_flutter/ui/views/widget/loading_widget.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:stacked/stacked.dart';
class ListLayoutWidget extends ViewModelWidget<HomeViewModel> {
const ListLayoutWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, HomeViewModel viewModel) {
var theme = Theme.of(context);
var orderLists = viewModel.tableOrdersResponse.data?.tableOrders ?? [];
if (viewModel.busy(viewModel.tableOrdersResponse)) {
return const ListLayoutShimmer();
}
return SmartRefresher(
key: viewModel.scaffoldKey,
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
controller: viewModel.refreshController,
enablePullUp: true,
scrollDirection: Axis.horizontal,
onRefresh: () {
viewModel.getTableOrderData(isRefresh: true);
viewModel.listGroupProductQty();
viewModel.refreshController.refreshCompleted();
},
header: CustomHeader(
builder: (BuildContext context, RefreshStatus? mode) {
return Center(child: Container());
},
),
footer: CustomFooter(builder: (BuildContext? context, LoadStatus? mode) {
return Center(child: Container());
}),
onLoading: () {
viewModel.getTableOrderDataMore();
},
child: orderLists.isNotEmpty
? ListView.separated(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
padding: const EdgeInsets.all(10),
physics: const BouncingScrollPhysics(),
itemCount: orderLists.length,
itemBuilder: (context, index) {
var data = orderLists.elementAt(index);
return Container(
width: MediaQuery.of(context).size.width / 4,
decoration: BoxDecoration(
color: theme.bgColorFF1E(context),
borderRadius: BorderRadius.circular(10),
),
child: Stack(
children: [
Column(
children: [
Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 10),
decoration: BoxDecoration(
color: theme.bgColorF927(context),
borderRadius: const BorderRadius.only(topLeft: Radius.circular(10), topRight: Radius.circular(10)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
CacheNetworkImageComponent(
imageUrl: data.imageChannel,
radius: 5,
),
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
data.tableName ?? '',
style: text12(context).copyWith(fontWeight: FontWeight.w400),
),
Text(
data.orderNumber ?? '',
style: text14(context).copyWith(color: Theme.of(context).color54E0(context), fontWeight: FontWeight.bold),
),
],
),
const Spacer(),
Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
if ((data.extraCookingTime ?? 0) > 0 && viewModel.segmentFilter == 1)
Text("+${data.extraCookingTime}min", style: text12(context).copyWith(fontWeight: FontWeight.w600, color: bgColor9A)),
],
),
if (viewModel.segmentFilter == 1)
PopupIncreaseTimer(
data: data,
onChanged: (value) {
if (value != "custom") {}
},
state: MyStatePopupIncreaseTimer(),
),
],
),
const SizedBox(height: 4),
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
LocaleKeys.global_client.tr(),
style: text12(context).copyWith(
color: Theme.of(context).color80A0(context),
fontWeight: FontWeight.w400,
fontSize: 10,
),
),
Text(data.clientName?.split(",").first ?? '', style: text14(context)),
],
),
const Spacer(),
if ((viewModel.segmentFilter == 2 && data.isPriority == 1) || viewModel.segmentFilter == 1)
GestureDetector(
onTap: viewModel.segmentFilter == 2 ? null : () {},
child: Icon(
Icons.flag,
color: data.isPriority == 1 ? bgColor4D : bgColorB3,
),
),
const SizedBox(width: 10),
],
)
],
),
),
Expanded(
child: ListView.builder(
itemCount: data.orderItems?.length ?? 0,
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
addAutomaticKeepAlives: true,
itemBuilder: (context, subIndex) {
var item = data.orderItems?.elementAt(subIndex);
return Padding(
padding: const EdgeInsets.only(top: 6),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 8, right: 10, top: 10),
child: Text(
'${item?.quantity}',
style: text14(context).copyWith(color: viewModel.statusTextColor(item?.status ?? '')),
),
),
const SizedBox(width: 8),
Expanded(
child: Container(
padding: const EdgeInsets.only(top: 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
item?.productName ?? '',
style: text14(context).copyWith(color: viewModel.statusTextColor(item?.status ?? ''), fontWeight: FontWeight.w400),
),
if (item?.options?.isNotEmpty ?? false)
...List.generate(
item?.options?.length ?? 0,
(indexOption) => Row(
children: [
const SizedBox(width: 5),
CircleAvatar(
radius: 3,
backgroundColor: viewModel.statusOptionTextColor(item?.status ?? ''),
),
const SizedBox(width: 10),
Expanded(
child: Text(
"${item?.options?.elementAt(indexOption).toString()}",
style: text14(context).copyWith(color: viewModel.statusOptionTextColor(item?.status ?? '')),
),
),
],
),
),
],
),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: viewModel.isClosed(item?.status ?? '')
? Icon(
Icons.check,
size: 24,
color: theme.bgColorB356(context),
)
: item?.status == cancelled
? Container()
: TextButton(
onPressed: () {},
style: TextButton.styleFrom(backgroundColor: viewModel.statusColor(item?.status ?? '')),
child: viewModel.busy(viewModel.tableOrderDetail) && subIndex == viewModel.currentSubIndex && viewModel.currentIndex == index
? const Padding(
padding: EdgeInsets.only(right: 9, left: 9),
child: LoadingWidget(
isTreeBounceLoading: true,
color: Colors.white,
),
)
: Text(
item?.status ?? '',
style: text14(context).copyWith(color: Colors.white),
),
),
)
],
),
if (item?.status == cancelled && item?.cancelReason != null)
Container(
padding: const EdgeInsets.only(left: 5, top: 5),
alignment: Alignment.centerLeft,
child: Text(
item?.cancelReason ?? '',
style: text14(context).copyWith(color: color6A),
textAlign: TextAlign.right,
),
),
if (viewModel.isEdit && viewModel.tableOrderGid == data.mealGid && item?.status == pending)
Align(
alignment: Alignment.centerLeft,
child: TextButton(
onPressed: () {},
child: Text(
LocaleKeys.home_cancel.tr(),
style: text14(context).copyWith(color: Theme.of(context).primaryColor, fontWeight: FontWeight.w500),
),
),
),
],
),
);
},
),
),
const SizedBox(height: 60)
],
),
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.all(10),
width: MediaQuery.of(context).size.width / 4,
decoration: BoxDecoration(
color: theme.bgColorF927(context),
borderRadius: const BorderRadius.only(bottomRight: Radius.circular(10), bottomLeft: Radius.circular(10)),
),
child: viewModel.segmentFilter == 1
? Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.print),
label: Text(LocaleKeys.home_print.tr()),
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xff94BBE9)),
),
),
const SizedBox(width: 10),
Expanded(
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xFF5CD79A)),
child: Text(LocaleKeys.home_dispatch_all.tr()),
),
)
],
)
: ElevatedButton.icon(
onPressed: data.isPrintable == 1 //disable printer (data.isPrintable = 0)
? () {}
: null,
icon: const Icon(Icons.print),
label: Text(LocaleKeys.home_print.tr()),
style: ElevatedButton.styleFrom(backgroundColor: const Color(0xff94BBE9)),
)),
),
if (viewModel.isEdit && viewModel.tableOrderGid == data.mealGid && viewModel.segmentFilter == 1)
Align(
alignment: Alignment.bottomCenter,
child: Container(
padding: const EdgeInsets.all(10),
width: MediaQuery.of(context).size.width / 4.2,
decoration: BoxDecoration(
color: theme.bgColorF927(context),
borderRadius: const BorderRadius.only(bottomRight: Radius.circular(10), bottomLeft: Radius.circular(10)),
),
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(backgroundColor: Theme.of(context).primaryColor),
child: Text(LocaleKeys.home_finish_edit.tr()),
),
),
),
],
),
);
},
separatorBuilder: (context, index) {
return const SizedBox(width: 10);
},
)
: const Center(
child: AnimatedOpacity(
opacity: 1,
curve: Curves.fastLinearToSlowEaseIn,
duration: Duration(milliseconds: 1000),
child: EmptyComponent(),
),
),
);
}
}
Was this reolved?
Still not resloved with Stacked but I try other state management , it working fine, I am not sure why.
Closing this. Please provide an example of the issue and we'll relook at this.
Describe the bug
Dear be love team, Thank you so much for your good library,
And now I have one issue , my app is working with real time when keep app open a bit long time then the ui is not re-render the data. as the function request to api
Code in ViewModel : fetchData() async { try { setBusy(true); rebuildUi(); var response = await ApiProviderService().getRestClient().getGroupProductQty(); if (response.response.statusCode == 200 && response.response.data != null) { groupProductResponse = GroupProductsResponse.fromJson(response.data); } } catch (error) { GlobalFunction.onHttpRequestFail(error, this); } finally { setBusy(false); rebuildUi(); } }
To reproduce
Code in ViewModel : fetchData() async { try { setBusy(true); rebuildUi();
}
Code in View class SideBarWidget extends ViewModelWidget {
const SideBarWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, HomeViewModel viewModel) {
var data = viewModel.groupProductResponse.data?.products;
---------------------------------------------etc
Expected behavior
It happened sometime.
Screenshots
No response
Additional Context
No response