Flutter : DropdownButtonFormField2 selected item changes to initial value on screen rotation - flutter

This bounty has ended. Answers to this question are eligible for a +50 reputation bounty. Bounty grace period ends in 11 hours.
KJEjava48 is looking for a canonical answer.
In my flutter application screen I have a DropdownButtonFormField2 which list various financial years, where after fetching the financial year list I set the current financial year as the initial(default) selected value in the dropdown as code below.The Problem comes when I change the financial year to a different year in dropdown, and it will change to the newly selected financial year in dropdown, but it will reset to the current(initial/default) financial year when I rotate the screen. How to solve this issue?
class AccountSetup extends StatelessWidget {
FinancialYear selFinancialPeriod = FinancialYear();
dynamic selFinancialValue;
List<dynamic>? financialYearList;
final Company selectedCompany;
AccountSetup({Key? key, required this.selectedCompany}) : super(key: key);
#override
Widget build(BuildContext context) {
context.read<MyAccountBloc>().add(FetchFinancialYearList(selectedCompany.id!));
return BlocBuilder<MyAccountBloc, MyAccountState>(
builder: (context, state) {
if(state is FinancialYearList) {
financialYearList = state.list;
if(financialYearList != null) {
for(dynamic itemFY in financialYearList!) {
if(DateTime.now().isBetween(yMdFormat.parse(itemFY['startDate']), yMdFormat.parse(itemFY['endDate']))) {
selFinancialPeriod = FinancialYear.fromJson(itemFY);
selFinancialValue = itemFY;
break;
}
}
}
getFinancialPeriodDropDown(context);
} else if(state is AccountTabChanged) {
....
} else if(state is UpdateDropDown) {
selFinancialValue = state.selValue;
selFinancialPeriod = FinancialYear.fromJson(selFinancialValue);
getFinancialPeriodDropDown(context);
}
return MaterialApp(
home: Scaffold(
body: SafeArea(
child: Stack(
children: [
Container(
child: Column(
children: [
SizedBox(height: 3,),
getFinancialPeriodDropDown(context),
SizedBox(height: 3,),
DefaultTabController(
length: 2, // length of tabs
initialIndex: 0,
child: Builder(
builder: (context) {
tabController = DefaultTabController.of(context);
tabController?.addListener(() {
selTab = tabController?.index;
context.read<MyAccountBloc>().add(ChangeTabEvent(tabIndex: tabController?.index));
});
return Column(
children: <Widget>[
....
],
);
},
),
),
],
),
),
Positioned(
bottom: 0,
left: 30,
right: 30,
child: getTabButtons(context),
),
],
)
),
),
);
}
);
}
getFinancialPeriodDropDown(BuildContext context) {
if(financialYearList == null) {
return SizedBox();
}
return setAcademicDropDown(context);
}
setFinancialPeriodDropDown(BuildContext context) {
return SizedBox(
height: 45,
child: DropdownButtonFormField2<dynamic>(
isExpanded: true,
hint: const Text('Select Financial Year',style: TextStyle(fontSize: 14),),
value: selFinancialValue,
items: financialYearList!.map((item) => DropdownMenuItem<dynamic>(
value: item,
child: Text('${dMyFormat.format(yMdFormat.parse(item['startDate']))} :: ${dMyFormat.format(yMdFormat.parse(item['endDate']))}',
style: const TextStyle(fontSize: 14,),
),)).toList(),
validator: (value) {
if (value == null) {
return 'Please select $txtAcaPer.';
}
},
onChanged: (value) {
context.read<MyAccountBloc>().add(UpdateDropDownEvent(selValue: value));
},
onSaved: (value) {},
),
);
}
}
One more thing I need to know is, how can i set the initial(default) value to nothing (ie, like 'Select Financial Year') when I open the page instead of the current financial year??
Edit :
I saw same kind of problem on the below question also
flutter dropdownbutton won't keep answer after scrolling

If you really don't want to lose the selection on orientation change then make the AccountSetup widget as StatefulWidget.
Then your code will be as following
class AccountSetup extends StatefulWidget {
final Company selectedCompany;
AccountSetup({Key? key, required this.selectedCompany}) : super(key: key);
#override
State<AccountSetup> createState() => _AccountSetupState();
}
class _AccountSetupState extends State<AccountSetup> {
FinancialYear selFinancialPeriod = FinancialYear();
dynamic selFinancialValue;
List<dynamic>? financialYearList;
#override
Widget build(BuildContext context) {
context.read<MyAccountBloc>().add(FetchFinancialYearList(widget.selectedCompany.id!));
return BlocBuilder<MyAccountBloc, MyAccountState>(
builder: (context, state) {
if(state is FinancialYearList) {
financialYearList = state.list;
if(financialYearList != null) {
for(dynamic itemFY in financialYearList!) {
if(DateTime.now().isBetween(yMdFormat.parse(itemFY['startDate']), yMdFormat.parse(itemFY['endDate']))) {
selFinancialPeriod = FinancialYear.fromJson(itemFY);
selFinancialValue = itemFY;
break;
}
}
}
getFinancialPeriodDropDown(context);
} else if(state is AccountTabChanged) {
selTab = state.tabIndex;
//tabController!.index = selTab!;
getTabButtons(context);
} else if(state is UpdateDropDown) {
selFinancialValue = state.selValue;
selFinancialPeriod = FinancialYear.fromJson(selFinancialValue);
getFinancialPeriodDropDown(context);
}
return MaterialApp(
scrollBehavior: MyCustomScrollBehavior(),
title: ....,
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSwatch().copyWith(
primary: primaryColor,
),),
home: Scaffold(
resizeToAvoidBottomInset: false,
appBar: sizedAppBar,
body: SafeArea(
child: Stack(
children: [
Container(
child: Column(
children: [
SizedBox(height: 3,),
getFinancialPeriodDropDown(context),
SizedBox(height: 3,),
DefaultTabController(
length: 2, // length of tabs
initialIndex: 0,
child: Builder(
builder: (context) {
tabController = DefaultTabController.of(context);
tabController?.addListener(() {
selTab = tabController?.index;
context.read<MyAccountBloc>().add(ChangeTabEvent(tabIndex: tabController?.index));
});
return Column(
children: <Widget>[
Container(
child: TabBar(
controller: tabController,
labelColor: textWhite1,
unselectedLabelColor: Colors.black,
indicatorWeight: 2,
isScrollable: true,
indicatorSize: TabBarIndicatorSize.tab,
indicatorColor: selColor1,
indicatorPadding: EdgeInsets.only(left: 2.0, right: 2.0,bottom: 3.0),
indicator: BoxDecoration(
borderRadius: BorderRadius.circular(5),color: highlightGrey10,shape: BoxShape.rectangle,
),
labelPadding: EdgeInsets.symmetric (horizontal: 1),
tabs: [
Container(
width: mainTabWidth,
height: mainTabHeight,
decoration: BoxDecoration(color: tab1Color,border: Border.all(color: border1Color,width: 2,style: BorderStyle.solid),borderRadius: BorderRadius.circular(5)),
child: Tab(child:Text(tabAccSt1,textAlign: TextAlign.center,style: TextStyle(fontSize: fontSize,fontWeight: FontWeight.bold,),),),
),
Container(
width: mainTabWidth,
height: mainTabHeight,
decoration: BoxDecoration(color: tab2Color,border: Border.all(color: border1Color,width: 2,style: BorderStyle.solid),borderRadius: BorderRadius.circular(5)),
child: Tab(child:Text(tabAccSt2,textAlign: TextAlign.center,style: TextStyle(fontSize: fontSize,fontWeight: FontWeight.bold,),),),
),
],
),
),
Container(
height: 400, //height of TabBarView
decoration: BoxDecoration(
border: Border(top: BorderSide(color: Colors.grey, width: 0.5))
),
child: TabBarView(
controller: tabController,
children: <Widget>[
Container(
child: Column(
children: [
getCompanySites(),
],
),
),
Container(
child: Center(
child: Text('Display Tab 2', style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold)),
),
),
],
),
),
],
);
},
),
),
],
),
),
Positioned(
bottom: 0,
left: 30,
right: 30,
child: getTabButtons(context),
),
],
)
),
),
);
}
);
}
getFinancialPeriodDropDown(BuildContext context) {
if(financialYearList == null) {
return SizedBox();
}
return setAcademicDropDown(context);
}
setFinancialPeriodDropDown(BuildContext context) {
return SizedBox(
height: 45,
child: DropdownButtonFormField2<dynamic>(
isExpanded: true,
hint: const Text('Select Financial Year',style: TextStyle(fontSize: 14),),
value: selFinancialValue,
icon: const Icon(Icons.arrow_drop_down,color: Colors.black45,),
iconSize: 30,
buttonHeight: 60,
buttonPadding: const EdgeInsets.only(left: 20, right: 10),
dropdownDecoration: BoxDecoration(borderRadius: BorderRadius.circular(15),),
items: financialYearList!.map((item) => DropdownMenuItem<dynamic>(
value: item,
child: Text('${dMyFormat.format(yMdFormat.parse(item['startDate']))} :: ${dMyFormat.format(yMdFormat.parse(item['endDate']))}',
style: const TextStyle(fontSize: 14,),
),)).toList(),
validator: (value) {
if (value == null) {
return 'Please select $txtAcaPer.';
}
},
onChanged: (value) {
context.read<MyAccountBloc>().add(UpdateDropDownEvent(selValue: value));
},
onSaved: (value) {},
),
);
}
}
If you not seeing any changes on UI then, you have to call setState method to refresh the UI.

Related

The dropdown_search library in flutter does not refresh my user list

Hello everyone and thank you for taking the time to try to help me.
I use this library in flutter on mobile only => pub.dev dropdown_search
When I click on the dropdown, I load with an API call a list of users. I want to call them 20 by 20. The first call is done well, I have my first 20 users displayed and when I get to the bottom of my list I have a new API call that goes to display the next 20. This part also works.
My problem is that the list view in the dropdown doesn't refresh and doesn't show me my next 20 users and yet in the console I have my request that leaves with my 20 new users showing. If I close and reopen the dropdown the list is updated.
I contacted the developer who told me first to try to use this => myKey.currentState.reassemble() with my scrollController but it did not work.
He then explained that to solve my problem he could only see the use of a streambuilder. I tried it but it didn't work.
Would you have some hints to give me or something else please?
Here is a bit of what I did in code. In this example I not use StreamBuilder.
final GlobalObjectKey<DropdownSearchState<ListValueOptionList>> myKey = new GlobalObjectKey<DropdownSearchState<ListValueOptionList>>(50);
bool isListValueModify = false;
List<delegationModele.Delegation> listDelegations = [];
int indexDelegationList;
int pageCounter = 0;
ScrollController _scrollController = ScrollController();
List<ListValueOptionList> listValueOptionListModule;
List<ListValueOptionList> listValueOptionListTypeOfDelegation;
List<ListValueOptionList> listValueOptionsUserDelegation;
List userAlreadyUse = [];
#override
void initState() {
super.initState();
_scrollController.addListener(() {
if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) {
print("Scroll event");
_loadValueOptionListSpecificPeople();
setState(() {});
myKey.currentState.reassemble();
}
});
}
#override
Widget build(BuildContext context) {
return Padding(
/// Allows resize when kerboard is open if
/// padding == MediaQuery.of(context).viewInsets
padding: padding,
child: Container(
decoration:BoxDecoration(
color: appStyleMode.primaryBackgroundColor,
borderRadius: BorderRadius.vertical(top: Radius.circular(25.0)),
),
height: modalHeight,
child: Padding(
padding: const EdgeInsets.only(left:30, top:30.0, right: 30, bottom: 20),
child: ListView(
shrinkWrap: false,
children: [
getModificationItemListDelegationBuilder(),
],
),
),
),
);
}
SingleChildScrollView getModificationItemListDelegationBuilder(){
final appStyleMode = Provider.of<AppStyleModeNotifier>(context);
return SingleChildScrollView(
child: Column(
children: [
///Add specific people
Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.only(bottom: 10, top: 10),
child: Text(
"${getTranslated(context, "my_delegation_specific_user")} : ",
style: TextStyle(
color: specificPeopleisEmpty ? Colors.red : appStyleMode.blackWhiteColor,
fontSize: 16,
),
textAlign: TextAlign.start,
),
),
Container(
child: ListView.builder(
shrinkWrap: true,
itemCount: delegation.userDelegationRecipients.length ?? 0,
itemBuilder: (context, index){
return specificPeople(listValueOptionsUserDelegation, index);
},
),
),
],
),
);
}
Widget specificPeople(List<ListValueOptionList> listValueOptionList, int index){
final appStyleMode = Provider.of<AppStyleModeNotifier>(context);
delegationModele.UserDelegationRecipients userDelegation = delegation.userDelegationRecipients[index];
String optionUserDescription;
if(listValueOptionList != null){
listValueOptionList.removeWhere((element) => userLoad.id.stringOf == element.idValue);
for(ListValueOptionList valueOption in listValueOptionList){
if(valueOption.idValue == userDelegation.delegationUserId){
optionUserDescription = valueOption.listValueDescription;
}
}
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
width: MediaQuery.of(context).size.width * 0.6,
child: DropdownSearch<ListValueOptionList>(
key: myKey,
dropdownButtonProps: DropdownButtonProps(
color: appStyleMode.blackWhiteColor
),
popupProps: PopupProps.menu(
showSelectedItems: true,
menuProps: MenuProps(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
elevation: 5.0,
backgroundColor: appStyleMode.primaryBackgroundColor,
),
textStyle: TextStyle(
color: appStyleMode.blackWhiteColor
),
scrollbarProps: ScrollbarProps(
thumbVisibility: true,
thumbColor: appStyleMode.categorySelectorSelectedBackgroundColor,
interactive: true
),
listViewProps: ListViewProps(
controller: _scrollController,
shrinkWrap: true,
),
interceptCallBacks: true,
itemBuilder: (context, list, isSelected){
return new Container(
child: ListTile(
selected: isSelected,
title: Text(
list?.listValueDescription,
style: TextStyle(
color: appStyleMode.blackWhiteColor
),
),
),
);
},
loadingBuilder: (context, loadingText){
return Align(
alignment: Alignment.topCenter,
child: CircularProgressIndicator(),
);
},
emptyBuilder: (context, text){
return Align(
alignment: Alignment.topCenter,
child: Text(
"${getTranslated(context, "my_delegation_empty_search_user")}",
style: TextStyle(
color: appStyleMode.blackWhiteColor,
),
),
);
},
showSearchBox: true,
searchDelay: Duration(seconds: 1),
searchFieldProps: TextFieldProps(
decoration: InputDecoration(
enabled: true,
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
color: appStyleMode.categorySelectorSelectedBackgroundColor,
style: BorderStyle.solid
)
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
borderSide: BorderSide(
style: BorderStyle.solid
)
),
prefixIcon: Icon(
Icons.search_rounded,
size: 20,
),
hintText: "${getTranslated(context, "my_delegation_search_hint_text")}",
hintStyle: TextStyle(
fontSize: 13
),
),
style: TextStyle(
color: appStyleMode.blackWhiteColor,
),
),
),
onChanged: (newValue){
//OnChanges is well used
},
compareFn: (value1, value2) => value1.idValue == value2.idValue,
dropdownDecoratorProps: DropDownDecoratorProps(
dropdownSearchDecoration: InputDecoration(
border: InputBorder.none
)
),
//items: listValueOptionsUserDelegation,
asyncItems: (filter) async{
return _loadValueOptionListSpecificPeople();
},
itemAsString: (ListValueOptionList list) => list.listValueDescription,
selectedItem: new ListValueOptionList(idValue: userDelegation.delegationUserId, listValueDescription: optionUserDescription),
dropdownBuilder: (context, selectedItem){
if(optionUserDescription == null || optionUserDescription.isEmpty){
return Container();
}else if(optionUserDescription == ""){
return Text("");
}else{
selectedItem.listValueDescription = optionUserDescription;
}
return textValueDescription(selectedItem.listValueDescription, appStyleMode, TextAlign.start);
},
),
),
],
);
}else{
return Container();
}
}
#override
void dispose() {
_scrollController.dispose();
super.dispose();
}
}
I've had a similar app. Maybe this code will help:
class PostsList extends StatefulWidget {
#override
State<PostsList> createState() => _PostsListState();
}
class _PostsListState extends State<PostsList> {
final _scrollController = ScrollController();
#override
void initState() {
super.initState();
_scrollController.addListener(_onScroll);
}
#override
Widget build(BuildContext context) {
return BlocBuilder<PostBloc, PostState>(
builder: (context, state) {
switch (state.status) {
case PostStatus.failure:
return const Center(child: Text('failed to fetch posts'));
case PostStatus.success:
if (state.posts.isEmpty) {
return const Center(child: Text('no posts'));
}
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return index >= state.posts.length
? const BottomLoader()
: PostListItem(post: state.posts[index]);
},
itemCount: state.hasReachedMax
? state.posts.length
: state.posts.length + 1,
controller: _scrollController,
);
default:
return const Center(child: CircularProgressIndicator());
}
},
);
}
#override
void dispose() {
_scrollController
..removeListener(_onScroll)
..dispose();
super.dispose();
}
void _onScroll() {
if (_isBottom) context.read<PostBloc>().add(PostFetched());
}
bool get _isBottom {
if (!_scrollController.hasClients) return false;
final maxScroll = _scrollController.position.maxScrollExtent;
final currentScroll = _scrollController.offset;
return currentScroll >= (maxScroll * 0.9);
}
}
I've used bloc for this but it should work as well with future builder and using snapshot. Basically user scrolls down, and if scrolled more than 90% of the list another getter is send to get more items from api. If you want to replicate the whole bloc (which I strongly recommend) take look at this documentation.

Flutter API request is called multiple times

Flutter keeps firing the api request, 200+ x sometimes and this makes the app really slow. I have tried async memorizer already, but this doesn't work. Do you have any idea how I can prevent multiple api requests with this code?
I'm getting an redscreen also when the page is loading. The error says Null check operator used on a null value.
I don't understand what I'm doing wrong. Tips & ideas are welcome.
class ProfileScreen extends StatefulWidget {
// ignore: deprecated_member_use_from_same_package
final ProfileNavigationEnum profileNavigationEnum;
final String? otherUserId;
final String? profileUrl;
final String? coverUrl;
const ProfileScreen({
Key? key,
this.otherUserId,
this.profileUrl,
this.coverUrl,
this.profileNavigationEnum = ProfileNavigationEnum.FROM_FEED,
}) : super(key: key);
#override
_ProfileScreenState createState() => _ProfileScreenState();
}
class _ProfileScreenState extends State<ProfileScreen>
with SingleTickerProviderStateMixin {
ProfileCubit? _profileCubit;
UserPostCubit? userPostCubit;
UserMediaCubit? userMediaCubit;
UserLikesCubit? userLikesCubit;
TabController? tabController;
Size? size;
#override
void initState() {
_profileCubit = BlocProvider.of<ProfileCubit>(context);
tabController = TabController(length: 3, vsync: this);
userPostCubit = getIt<UserPostCubit>();
userMediaCubit = getIt<UserMediaCubit>();
userLikesCubit = getIt<UserLikesCubit>();
_profileCubit!.profileEntity.listen((event) {
userLikesCubit!.userId = event.id;
userMediaCubit!.userId = event.id;
userPostCubit!.userId = event.id;
});
super.initState();
_profileCubit!
.getUserProfile(widget.otherUserId, widget.coverUrl, widget.profileUrl);
}
double textSizePred = 0.0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: BlocConsumer<ProfileCubit, CommonUIState>(
listener: (context, state) => state.maybeWhen(
orElse: () => null,
success: (state) => ProfileListener.success(state, context),
error: (e) => ProfileListener.error(e!, context),
),
builder: (_, state) {
return state.when(
initial: () => LoadingBar(),
success: (s) => getHomeWidget(),
loading: () => LoadingBar(),
error: (e) => Center(
child: NoDataFoundScreen(
onTapButton: context.router.root.pop,
icon: AppIcons.personOption(
color: AppColors.colorPrimary, size: 40),
title: 'Profile Not found',
message: e!.contains("invalid")
? LocaleKeys
.sorry_we_cannot_find_the_page_you_are_looking_for_if_you_still_ne
.tr()
: e,
buttonText: LocaleKeys.go_back.tr(),
),
),
);
},
),
);
}
Widget getHomeWidget() {
return StreamBuilder<ProfileEntity>(
stream: _profileCubit!.profileEntity,
builder: (context, snapshot) {
return DefaultTabController(
length: 3,
child: SafeArea(
child: NestedScrollView(
headerSliverBuilder: (context, value) {
return [
SliverAppBar(
automaticallyImplyLeading: false,
leading: null,
systemOverlayStyle: SystemUiOverlayStyle.light,
elevation: 0.0,
expandedHeight: calculateHeight(
context: context,
item: snapshot.data!,
) as double?,
floating: true,
pinned: true,
actions: [
IconButton(
icon: const Icon(Icons.edit),
onPressed: () async {
await openMediaPicker(
context,
(media) async {
_profileCubit!.changeProfileEntity(
snapshot.data!
.copyWith(backgroundImage: media),
);
await _profileCubit!
.updateProfileCover(media);
},
mediaType: MediaTypeEnum.IMAGE,
allowCropping: true,
);
}).toVisibility(widget.otherUserId == null)
],
// title: Text('Profile'),
backgroundColor: Colors.white,
flexibleSpace: FlexibleSpaceBar(
collapseMode: CollapseMode.pin,
background: snapshot.data == null
? Container()
: TopAppBar(
otherUserId: snapshot.data!.id,
otherUser: widget.otherUserId != null,
profileEntity: snapshot.data,
profileNavigationEnum:
widget.profileNavigationEnum,
onSizeAborted: (size) {
setState(() {
textSizePred = size;
});
},
),
),
// posts,media,likes row
bottom: PreferredSize(
child: Stack(
children: [
Positioned.fill(
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
),
TabBar(
indicatorWeight: 1,
indicatorSize: TabBarIndicatorSize.label,
labelPadding: const EdgeInsets.all(0),
labelStyle: TextStyle(
fontFamily: 'CeraPro',
fontWeight: FontWeight.w500,
),
unselectedLabelStyle: TextStyle(
fontFamily: 'CeraPro',
fontWeight: FontWeight.bold,
),
tabs: [
Tab(
text: LocaleKeys.posts.tr(),
).toContainer(
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
Tab(
text: LocaleKeys.media.tr(),
).toContainer(
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
Tab(
text: LocaleKeys.likes.tr(),
).toContainer(
alignment: Alignment.center,
decoration: const BoxDecoration(
color: Colors.white,
border: Border(
top: BorderSide(
color: Colors.grey,
width: 0.2,
),
),
),
),
],
)
],
),
preferredSize: const Size(500, 56),
),
),
];
},
body: TabBarView(
children: [
/// Add the block widget here thhree times
Container(
child: RefreshIndicator(
onRefresh: () {
userPostCubit!.onRefresh();
return Future.value();
},
child: PostPaginationWidget(
isComeHome: false,
isFromProfileSearch: true,
isPrivateAccount: (value) {
_profileCubit!.isPrivateUser = value;
},
isSliverList: false,
noDataFoundScreen: NoDataFoundScreen(
buttonText: LocaleKeys.go_to_the_homepage.tr(),
title: LocaleKeys.no_posts_yet.tr(),
message: "",
onTapButton: () {
context.router.root.pop();
},
),
pagingController: userPostCubit!.pagingController,
onTapLike: userPostCubit!.likeUnlikePost,
onOptionItemTap:
(PostOptionsEnum postOptionsEnum, int index) =>
userPostCubit!.onOptionItemSelected(
context, postOptionsEnum, index),
onTapRepost: userPostCubit!.repost,
),
),
),
Container(
child: RefreshIndicator(
onRefresh: () {
userMediaCubit!.onRefresh();
return Future.value();
},
child: PostPaginationWidget(
isComeHome: false,
isPrivateAccount: (value) {
_profileCubit!.isPrivateUser = value;
},
isSliverList: false,
noDataFoundScreen: NoDataFoundScreen(
title: LocaleKeys.no_media_yet.tr(),
icon: AppIcons.imageIcon(height: 35, width: 35),
buttonText: LocaleKeys.go_to_the_homepage.tr(),
message: "",
onTapButton: () {
context.router.root.pop();
// BlocProvider.of<FeedCubit>(context).changeCurrentPage(ScreenType.home());
// context.router.root.push(Routes.createPost);
},
),
pagingController: userMediaCubit!.pagingController,
onTapLike: userMediaCubit!.likeUnlikePost,
onOptionItemTap: (PostOptionsEnum postOptionsEnum,
int index) async =>
await userMediaCubit!.onOptionItemSelected(
context, postOptionsEnum, index),
onTapRepost: userMediaCubit!.repost,
),
)),
Container(
child: RefreshIndicator(
onRefresh: () {
userLikesCubit!.onRefresh();
return Future.value();
},
child: PostPaginationWidget(
isComeHome: false,
isPrivateAccount: (value) {
_profileCubit!.isPrivateUser = value;
},
isSliverList: false,
noDataFoundScreen: NoDataFoundScreen(
title: LocaleKeys.no_likes_yet.tr(),
icon: AppIcons.likeOption(
size: 35, color: AppColors.colorPrimary),
buttonText: LocaleKeys.go_to_the_homepage.tr(),
message: LocaleKeys
.you_don_t_have_any_favorite_posts_yet_all_posts_that_you_like_wil
.tr(),
onTapButton: () {
context.router.root.pop();
// BlocProvider.of<FeedCubit>(context).changeCurrentPage(ScreenType.home());
// context.router.root.push(Routes.createPost);
},
),
pagingController: userLikesCubit!.pagingController,
onTapLike: userLikesCubit!.likeUnlikePost,
onOptionItemTap:
(PostOptionsEnum postOptionsEnum, int index) =>
userLikesCubit!.onOptionItemSelected(
context,
postOptionsEnum,
index,
),
onTapRepost: userLikesCubit!.repost,
),
)),
],
),
),
),
);
});
}
num calculateHeight({
required BuildContext context,
required ProfileEntity item,
}) {
print('INCHES: ${context.diagonalInches}');
bool isSmallInches = context.diagonalInches <= 4.7;
bool hasWebsite = item.website != null && item.website!.isNotEmpty;
final height = context.getScreenHeight;
final defaultHeight = isSmallInches ? height * .6 : height * .47;
final websiteHeight = hasWebsite ? height * .03 : 0;
final sizeBoxHeight = textSizePred != 0.0 ? 10.h : 0;
return textSizePred + defaultHeight + websiteHeight + sizeBoxHeight;
}
}
/// helps to determine from where user navigated to profile
/// so that on back press of the profile screen we can go back the correct page
/// we're using this because according to the UI we will have the keep the bottom navigation bar under the profile page
enum ProfileNavigationEnum {
FROM_BOOKMARKS,
FROM_FEED,
FROM_SEARCH,
FROM_VIEW_POST,
FROM_MY_PROFILE,
FROM_OTHER_PROFILE,
FROM_MESSAGES,
FROM_NOTIFICATION
} ```

How to update state within a custom tab bar with flutter

I'm trying to create a custom TabBar which navigates only forward with a button click.
im using an enum to manage the state and couple of class objects to manage items for Tabs.
What result I expected
VS
What result I've got
The code I worked out is as follows. I am still trying to figure out a way of managing the expected outcome with my code implementation. if anyone can help out will be amazing.
Object classes
class CategoryModel {
final String? title;
final eCategory category;
// final eCategoryState? catState;
CategoryModel({this.title, required this.category});
}
class CategoryStateModel {
final CategoryModel? tItem;
late eTabState? tState;
CategoryStateModel({this.tItem, this.tState});
}
The code portion
class _ContributeTabScreenState extends State<ContributeTabScreen>
with SingleTickerProviderStateMixin {
eButtonState _submitBtnState = eButtonState.bActive;
eButtonState _continueBtnState = eButtonState.bActive;
int pageNo = 0;
TabController? _tabController;
late List<eTabState>? _tabState = [];
late List<CategoryModel>? _categoryModelList = [];
late List<Tab>? _tabList = [];
late List<CategoryStateModel>? _catStateList = [];
#override
void initState() {
_categoryModelList = widget.catList;
_assignTabs();
_tabController = new TabController(
vsync: this,
length: _categoryModelList!.length, //3,
);
super.initState();
// print(_categoryModelList![0].title.toString());
}
List<Tab> _assignTabs() {
for (var item = 0; item < _categoryModelList!.length; item++) {
//
if (item != 0) {
for (var t in _categoryModelList!) {
_catStateList!.add(
new CategoryStateModel(tItem: t, tState: eTabState.tUnSelected));
}
} else {
for (var t in _categoryModelList!) {
_catStateList!.add(
new CategoryStateModel(tItem: t, tState: eTabState.tSelected));
}
}
//
_tabList!.add(
new Tab(
child: _tabItem(_catStateList![item]),
// child: _tabItem(_categoryModelList![item]),
),
);
}
return _tabList!;
}
void _goBack() {
Navigator.of(context).pop();
}
//the onPressed call back I manage the forward move of a tabbar item + tabview
void forwardTabPage() {
if (pageNo >= 0 && pageNo < _categoryModelList!.length) {
setState(() {
// });
// setState(() {
pageNo = pageNo + 1;
// _catStateList![pageNo - 1].tState = eTabState.tCompleted;
// _tabState![pageNo - 1] = _catStateList![pageNo - 1].tState!;
});
_tabController!.animateTo(pageNo);
}
}
...rest of the code
//the Tabbar item
_tabItem(CategoryStateModel item) => Container(
width: 140.0,
alignment: Alignment.center,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
item.tItem!.title!,
style: tBody4.copyWith(color: CustomColors.mDarkBlue),
),
item.tState == _catStateList![pageNo].tState //eTabState.tCompleted
? SizedBox(
width: 8.0,
)
: SizedBox(
width: 0.0,
),
item.tState == _catStateList![pageNo].tState //eTabState.tCompleted
? CircleAvatar(
radius: 12.0,
backgroundColor: CustomColors.green600,
child: Icon(
Icons.check_outlined,
size: 20.0,
),
)
: SizedBox(
width: 0.0,
),
],
),
);
continueBtn() => ButtonWidget(
btnColor: CustomColors.green600,
borderColor: CustomColors.green600,
textColor: CustomColors.mWhite,
text: "Continue",
eButtonType: eButtonType.bText,
eButtonState: _continueBtnState,
onPressed: () {
forwardTabPage();
// _tabState = eTabState.tCompleted;
},
);
submitBtn() => ButtonWidget(
btnColor: CustomColors.green600,
borderColor: CustomColors.green600,
textColor: CustomColors.mWhite,
text: "Submit",
eButtonType: eButtonType.bText,
eButtonState: _submitBtnState,
onPressed: () {},
);
#override
Widget build(BuildContext context) {
return DefaultTabController(
length: _categoryModelList!.length,
child: Scaffold(
appBar: AppBar(
toolbarHeight: 60.0,
leadingWidth: 100.0,
leading: GestureDetector(
onTap: _goBack,
child: Container(
child: Row(
children: [
SizedBox(
width: 16.0,
),
const Icon(
Icons.arrow_back_ios,
color: CustomColors.grey700,
size: 24.0,
),
Flexible(
child: Text(
"Back",
style: tButtonSmall,
),
),
],
),
),
),
backgroundColor: Colors.white,
elevation: 0.0,
bottom: PreferredSize(
preferredSize: Size.fromHeight(50.0),
child: IgnorePointer(
child: TabBar(
controller: _tabController,
isScrollable: false,
enableFeedback: false,
padding: EdgeInsets.only(bottom: 8.0),
indicatorSize: TabBarIndicatorSize.label,
indicator:
// _tabState == eTabState.tSelected
// ?
BoxDecoration(
borderRadius: BorderRadius.circular(40.0),
color: CustomColors.green300,
border: Border.all(color: CustomColors.mGreen, width: 2),
),
tabs: _tabList!
),
),
),
),
body: Container(
child: TabBarView(
controller: _tabController,
physics: NeverScrollableScrollPhysics(),
children: [
Container(
color: CustomColors.grey600.withOpacity(0.2),
child: Center(
child: Text("Home Tab View"),
),
),
Center(
child: Text("Map Tab View"),
),
],
),
),
persistentFooterButtons: [
Container(
width: MediaQuery.of(context).size.width,
// height: 40,
padding: EdgeInsets.symmetric(horizontal: 24.0),
margin: EdgeInsets.symmetric(vertical: 16.0),
child: (_categoryModelList!.length == 1 ||
pageNo == _categoryModelList!.length - 1)
? submitBtn()
: continueBtn(),
)
],
),
);
}
enum classes
enum eCategoryState {
cSelected,
cUnSelected,
cEnded,
}
enum eTabState {
tSelected,
tUnSelected,
tCompleted,
}
enum eCategory {
cAccess,
cAmenities,
}
I don't know if I understand what you mean or not. but try this. TabBar has a isScrollable property. set it to true

GlobalKey<FormState>().currentState.save() is falling when I submit a form in Flutter

Using bloc from rxdart: ^0.24.1
I am trying to save object on mysql. The first try the object get saved succefully, the second try, with a new object, it falling on formKey.currentState.save(). I am using GlobalKey<FormState>() in order to validate the form with Stream
My code is
class DetailGamePage extends StatefulWidget {
#override
_DetailGameState createState() => _DetailGameState();
}
class _DetailGameState extends State<DetailGamePage> {
final formKey = GlobalKey<FormState>();
GameBloc gameBloc;
#override
void didChangeDependencies() {
super.didChangeDependencies();
if (gameBloc == null) {
gameBloc = Provider.gameBloc(context);
}
}
#override
Widget build(BuildContext context) {
Game _game = ModalRoute.of(context).settings.arguments;
if (_game == null) {
_game = Game(
color: "#000000",
description: "",
env: "",
isBuyIt: false,
isOnBacklog: false);
}
return Scaffold(
appBar: AppBar(
iconTheme: IconThemeData(color: Colors.black),
backgroundColor: Colors.white,
title: Text(
"Add Game",
style: TextStyle(color: Colors.black),
),
actions: [
FlatButton(
onPressed: () {
if (formKey.currentState.validate()) {
formKey.currentState.save();
Fluttertoast.showToast(msg: "Game saved");
setState(() {
gameBloc.saveOrUpdate(_game, gameBloc.name,
gameBloc.description, "listGame");
});
Navigator.pushReplacementNamed(context, "home");
}
},
child: Text(
(StringUtils.isNullOrEmpty(_game.id)) ? "Add" : "Update",
style: TextStyle(color: HexColor(_game.color), fontSize: 20),
))
],
),
body: Form(
key: formKey,
child: Stack(children: <Widget>[
_createBackground(context, _game),
_createFormGame(context, _game, gameBloc)
]),
));
}
Widget _createBackground(BuildContext context, Game game) {
final size = MediaQuery.of(context).size;
final gradientTop = Container(
height: size.height, //* 0.4,
width: double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
colors: <Color>[HexColor(game.color), Colors.white])),
);
final circule = Container(
width: 100.0,
height: 100.0,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100.0),
color: Color.fromRGBO(255, 255, 255, 0.1)),
);
return Stack(
children: <Widget>[
gradientTop,
Positioned(
child: circule,
top: 90,
left: 50,
),
Positioned(
child: circule,
top: -40,
right: -30,
),
Container(
padding: EdgeInsets.only(top: 80),
child: Column(
children: <Widget>[
SizedBox(
height: 10.0,
width: double.infinity,
),
],
),
)
],
);
}
Widget _createFormGame(BuildContext context, Game game, GameBloc gameBloc) {
final size = MediaQuery.of(context).size;
return SingleChildScrollView(
child: Column(
children: <Widget>[
SafeArea(
child: Container(
height: 80.0,
)),
Container(
width: size.width * 0.85,
padding: EdgeInsets.symmetric(vertical: 50.0),
margin: EdgeInsets.symmetric(vertical: 30.0),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(5.0),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.black26,
blurRadius: 3.0,
offset: Offset(0.0, 5.0),
spreadRadius: 3.0)
]),
child: Column(
children: <Widget>[
Text("Foto", style: TextStyle(fontSize: 20.0)),
SizedBox(
height: 50.0,
),
_createNameImput(gameBloc, game),
_createDescriptionImput(gameBloc, game),
Divider(
height: 30,
color: HexColor(game.color),
indent: 30,
endIndent: 20,
),
_createWasGameImput(gameBloc, game),
Divider(
height: 30,
color: HexColor(game.color),
indent: 30,
endIndent: 20,
),
_createToTheBacklogImput(gameBloc, game),
SizedBox(height: 60),
_createDeleteButton(gameBloc, game),
SizedBox(height: 60),
],
))
],
),
);
}
#override
void dispose() {
gameBloc?.dispose();
super.dispose();
}
Widget _createWasGameImput(GameBloc gameBloc, Game game) {
return StreamBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: SwitchListTile(
activeColor: HexColor(game.color),
title: Text("Do you have it?"),
value: game.isBuyIt,
onChanged: (bool value) {
setState(() {
game.isBuyIt = value;
});
},
secondary: IconButton(
icon: Icon(Icons.shopping_cart),
onPressed: null,
color: HexColor(game.color),
),
));
},
);
}
Widget _createToTheBacklogImput(GameBloc gameBloc, Game game) {
return StreamBuilder(
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: SwitchListTile(
activeColor: HexColor(game.color),
title: Text("To the backlog?"),
value: game.isOnBacklog,
onChanged: (bool value) {
setState(() {
game.isOnBacklog = true;
});
},
secondary: IconButton(
icon: Icon(Icons.list),
onPressed: null,
color: HexColor(game.color),
),
));
},
);
}
Widget _createNameImput(GameBloc gamebloc, Game game) {
return Column(children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: TextFormField(
textCapitalization: TextCapitalization.sentences,
initialValue: game.name,
onSaved: (value) {
gameBloc.setName(value);
},
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: "Name",
icon: Icon(
Icons.games,
color: HexColor(game.color),
)),
),
),
Divider(
height: 30,
color: HexColor(game.color),
indent: 30,
endIndent: 20,
),
]);
}
Widget _createDescriptionImput(GameBloc gameBloc, Game game) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 20.0),
child: TextFormField(
textCapitalization: TextCapitalization.sentences,
initialValue: game.description,
onSaved: (value) {
gameBloc.setDescription(value);
},
keyboardType: TextInputType.text,
decoration: InputDecoration(
labelText: "Description",
icon: Icon(
Icons.description,
color: HexColor(game.color),
)),
),
);
}
Widget _createDeleteButton(GameBloc gameBloc, Game game) {
if (StringUtils.isNotNullOrEmpty(game.id)) {
return FlatButton(
onPressed: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: Text("Do you wan to remove the game"),
actions: <Widget>[
FlatButton(
onPressed: () {
setState(() {
gameBloc.remove(game, "listGame");
});
Navigator.pop(context);
Navigator.pop(context);
},
child: Text("Yes")),
FlatButton(
onPressed: () => Navigator.of(context).pop(),
child: Text("No"))
],
);
});
},
child: Text("Remove Game"));
} else {
return Container();
}
}
}
This is the bloc
class GameBloc extends Validators {
//Controller
final _allDataGames = BehaviorSubject<List<Game>>();
final _descriptionController = BehaviorSubject<String>();
final _nameController = BehaviorSubject<String>();
final _allMyListGamesByNameController = BehaviorSubject<List<Game>>();
//Services
GameService gameService = GameService();
//get Data from streams
Stream<List<Game>> get allGameData => _allDataGames.stream;
Stream<List<Game>> get allGameByNameList =>
_allMyListGamesByNameController.stream;
Stream<String> get getDescriptionStream =>
_descriptionController.stream.transform(validateDescription);
Stream<String> get getNameStream =>
_nameController.stream.transform(validName);
//Observable
Stream<bool> get validateDescriptionStream =>
Rx.combineLatest([getDescriptionStream], (description) => true);
Stream<bool> get validateNameStream =>
Rx.combineLatest([getNameStream], (name) => true);
//Set Stream
Function(String) get setDescription => _descriptionController.sink.add;
Function(String) get setName => _nameController.sink.add;
//Get Stream
//From repo
void allGames() async {
List<Game> games = await gameService.getAllDataGames();
_allDataGames.sink.add(games);
}
//From my setting
void allMyListGamesByName(String listName) async {
List<Game> games = await gameService.allMyListGamesByName(listName);
_allMyListGamesByNameController.sink.add(games);
}
void saveOrUpdate(
Game game, String name, String description, String listGame) {
game.name = name;
game.description = description;
if (StringUtils.isNullOrEmpty(game.id)) {
game.id = Uuid().v1();
gameService.add(game, listGame);
} else {
gameService.update(game);
}
}
void remove(Game game, String listGame) {
gameService.remove(game, listGame);
}
//Get Lastest stream value
String get name => _nameController.value;
String get description => _descriptionController.value;
dispose() {
_descriptionController?.close();
_allMyListGamesByNameController?.close();
_allDataGames?.close();
_nameController?.close();
}
}
The provider:
class Provider extends InheritedWidget {
static Provider _imstance;
final _gameBloc = GameBloc();
factory Provider({Key key, Widget child}) {
if (_imstance == null) {
_imstance = new Provider._internal(key: key, child: child);
}
return _imstance;
}
Provider._internal({Key key, Widget child}) : super(key: key, child: child);
static GameBloc gameBloc(BuildContext context) {
return (context.inheritFromWidgetOfExactType(Provider) as Provider)
._gameBloc;
}
#override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
}
The error is:
════════ Exception caught by gesture ═══════════════════════════════════════════
Bad state: Cannot add new events after calling close
When I evaluate formKey.currentState.save(); I got:
formKey.currentState.save()
Unhandled exception:
Bad state: Cannot add new events after calling close
#0 _BroadcastStreamController.add (dart:async/broadcast_stream_controller.dart:249:24)
#1 Subject._add (package:rxdart/src/subjects/subject.dart:141:17)
#2 Subject.add (package:rxdart/src/subjects/subject.dart:135:5)
#3 _StreamSinkWrapper.add (package:rxdart/src/subjects/subject.dart:167:13)
I was reading about this error, it mention the error is on Bloc singleston scope or dispose method.
What is happen?
When you navigate to home with Navigator.pushReplacementNamed(context, "home"), the _DetailGamePage<State> is being disposed, calling gameBloc?.dispose. This leaves _gameBloc instantiated with all streams closed.
As you are using a Singleton Provider, when you navigate back to DetailGamePage, your save is trying to write to the closed streams.
What you need to do is move the closure of the streams farther up the widget tree so as not to close them before you are done with them, perhaps at the app level OR re-instantiate _gameBloc if the streams are closed, loading the data from the repo again.

Flutter curved navigation bar does not switch between pages

I have encountered a problem which I cannot move between pages when I click on the icons, but I am setting the default page is the home page and when the application is running it only appears and I cannot move to other pages using the navigation bar.
Navigation Bar File:
class NavigationBar extends StatefulWidget {
#override
_NavigationBarState createState() => _NavigationBarState();
}
class _NavigationBarState extends State<NavigationBar> {
int pageIndex = 0;
final Search _search = Search();
final UserNoti _userNoti = UserNoti();
final HomePage _homePage = HomePage();
final MyProfile _myProfile = MyProfile();
final MyMajor _mymajor = MyMajor();
Widget _showPage = new HomePage();
Widget _pageChooser(int page)
{
switch (page)
{
case 0:
return _search;
break;
case 1:
return _userNoti;
break;
case 2:
return _homePage;
break;
case 3:
return _myProfile;
break;
case 4:
return _mymajor;
break;
default:
return _homePage;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
bottomNavigationBar: Container(
decoration: new BoxDecoration(
// borderRadius: BorderRadius.circular(28.0),
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [Colors.deepPurple, Colors.purple]),
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 25.0, // soften the shadow
spreadRadius: -10.0, //extend the shadow
)
],
),
child: CurvedNavigationBar(
index: 2,
color: Color.fromRGBO(58, 66, 86, 1.0),
buttonBackgroundColor: Colors.purple.withOpacity(0.6),
backgroundColor: Colors.transparent,
animationDuration: Duration(milliseconds: 200),
animationCurve: Curves.bounceInOut,
items: <Widget>[
Icon(Icons.search, size: 32, color: Colors.white,),
Icon(Icons.notifications_active, size: 32, color: Colors.white,),
Icon(Icons.home, size: 40, color: Colors.white,),
Icon(Icons.chat, size: 32, color: Colors.white,),
Icon(Icons.school, size: 32, color: Colors.white,),
],
onTap: (int tappedPage){
_showPage = _pageChooser(tappedPage);
},),
),
body: Container(
color: Colors.transparent,
child: Center(
child: _showPage,
),
));
}
}
Now I will put one code for one of those pages for example User Notification Page:
class UserNoti extends StatefulWidget {
final String myuid,majname,uniname;
UserNoti({Key key, this.myuid,this.majname,this.uniname}) : super(key: key);
#override
_UserNotiState createState() => _UserNotiState();
}
class _UserNotiState extends State<UserNoti> {
String myapplang = null;
var my_uid;
var myDoc;
bool loading = false;
#override
void initState() {
super.initState();
checkLang();
}
#override
Widget build(BuildContext context) {
return loading
? LoadingMain()
: Directionality(
textDirection: myapplang == 'ar' ? TextDirection.rtl : TextDirection.ltr,
child: Scaffold(
backgroundColor: Color.fromRGBO(58, 66, 86, 1.0),
appBar: GradientAppBar(
backgroundColorStart: Colors.deepPurple,
backgroundColorEnd: Colors.purple,
title: Text(
myapplang == 'ar' ? "الإشعارات" : "Notifications" ,
style: TextStyle(fontSize: 16,fontWeight: FontWeight.bold,fontFamily: myapplang == 'ar' ? 'Tajawal' : 'BalooDa2' ),),
),
body: ListView(
children: <Widget>[
Column(
children: <Widget>[
SizedBox(height: 30.0,),
Container(
width: MediaQuery.of(context).size.width*0.85,
child: Stack(
children: <Widget>[
StreamBuilder(
stream: Firestore.instance.collection('users').document(myDoc).collection('Notifications').orderBy('date',descending: true).snapshots(),
builder: (context, snapshot){
if(!snapshot.hasData)
{
const Text('Loading...');
}
else{
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index)
{
DocumentSnapshot mypost = snapshot.data.documents[index];
return Stack(
children: <Widget>[
FadeAnimation(0.2,Column(
children: <Widget>[
Container(
decoration: BoxDecoration(borderRadius:
BorderRadius.circular(15.0),color: Color.fromRGBO(64, 75, 96, .9),
boxShadow: [
BoxShadow(
color: Colors.black,
blurRadius: 30.0, // soften the shadow
spreadRadius: -25.0, //extend the shadow
)
],),
child:InkWell(
onTap: () {
// setState(() => loading = true);
if(mypost['type'] == 'comment'){
if(mypost['location'] == 'Majors'){
Firestore.instance
.document('/Majors/${widget.majname}/Posts/${mypost['pdoc']}')
.get()
.then((val) {
if(val.data['pid'] != null && val.data['text'] != null && val.data['uid'] != null && val.data['uimg'] != null && val.data['uname'] != null && val.data['uname'] != null)
{
Navigator.push(context, new MaterialPageRoute(builder: (context) => new Comments(pid: val.data['pid'], text: val.data['text'],img: val.data['img'],uid: val.data['uid'], uimg: val.data['uimg'],uname: val.data['uname'],majname: widget.majname,pdoc:mypost['pdoc'] )));
}
else {
showWraning(context,myapplang == 'ar' ? "حدثت مشكلة، قد يكون الإشعار محذوف أو مشكلة بالإنترنت، حاول لاحقًا." : "There is a problem, maybe notification has been deleted or problem with internet connection, try again later.");
}
/*
*/
}).catchError((e) {
print(e);
});
}
else {
Firestore.instance
.document('/Universities/${widget.uniname}/Posts/${mypost['pdoc']}')
.get()
.then((val) {
if(val.data['pid'] != null && val.data['text'] != null && val.data['uid'] != null && val.data['uimg'] != null && val.data['uname'] != null && val.data['uname'] != null)
{
Navigator.push(context, new MaterialPageRoute(builder: (context) => new U_Comments(pid: val.data['pid'], text: val.data['text'],img: val.data['img'],uid: val.data['uid'], uimg: val.data['uimg'],uname: val.data['uname'],uniname: widget.uniname,pdoc:mypost['pdoc'] )));
}
else {
showWraning(context,myapplang == 'ar' ? "حدثت مشكلة، قد يكون الإشعار محذوف أو مشكلة بالإنترنت، حاول لاحقًا." : "There is a problem, maybe notification has been deleted or problem with internet connection, try again later.");
}
/*
*/
}).catchError((e) {
print(e);
});
}
}
else {
print('not comment!');
}
},
child: ListTile(
contentPadding: EdgeInsets.symmetric(horizontal: 20.0, vertical: 10.0),
leading: ClipRRect(
borderRadius: BorderRadius.circular(35.0),
child: Icon(Icons.insert_comment,color: Colors.deepPurple,size: 40,),
),
title: Column(
children: <Widget>[
Text(
"${mypost['text']}",
style: TextStyle(color: Colors.white, fontWeight: FontWeight.bold,fontFamily: 'BalooDa2'),
textAlign: TextAlign.left,
),
SizedBox(height: 10.0,),
],
),
// subtitle: Text("Intermediate", style: TextStyle(color: Colors.white)),
trailing:
Icon(Icons.keyboard_arrow_right, color: Colors.white, size: 30.0)),
),
),
SizedBox(height: 20.0,),
],
),),
],
);
}
);
}
return Container(
height: 0.0,
width: 0.0,
);
},
),
],
),
),
],
),
],
),
),
);
}
I removed a few codes that had no need.
Note when running the application the active page is Homepage()
Right now you are setting your _showPage variable with a new page, but not in a way that will force your app to re-render the widget tree. Try using SetState in your tap function to do this.
onTap: (int tappedPage){
setState(() {
_showPage = _pageChooser(tappedPage);
});
}),