how to make flutter searchDelagate a separate screen that can be navigated to independently? - flutter

i have a page called searchUsersSCreen which is this:
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:myApp/models/otherUser.dart';
import 'package:myApp/ui/widgets/user_profile.dart';
import 'database.dart';
class SearchUsersScreen extends StatefulWidget {
#override
_SearchUsersScreenState createState() => _SearchUsersScreenState();
}
class _SearchUsersScreenState extends State<SearchUsersScreen> {
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => showSearch(
context: context,
delegate: SearchUsers(
DatabaseService().fetchUsersInSearch(),
),
));
}
#override
Widget build(BuildContext context) {
return Container(
color: Theme.of(context).primaryColor,
);
}
}
and inside the same dart file is have this searchDelegate :
//Search delegate
class SearchUsers extends SearchDelegate<OtherUser> {
final Stream<QuerySnapshot> otherUser;
final String hashtagSymbol = 'assets/svgs/flaticon/hashtag_symbol.svg';
SearchUsers(this.otherUser);
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
),
];
}
#override
Widget buildLeading(BuildContext context) {
return Container(
width: 0,
height: 0,
);
}
#override
Widget buildResults(BuildContext context) {
return Container(
width: 0,
height: 0,
color: Theme.of(context).primaryColor,
);
}
#override
Widget buildSuggestions(BuildContext context) {
showUserProfile(String userId) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserProfileView(
userUid: userId,
)));
}
return StreamBuilder<QuerySnapshot>(
stream: DatabaseService().fetchUsersInSearch(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
final handlesResults = snapshot.data.documents
.where((u) => u['username'].contains(query));
if (!snapshot.hasData) {
return Container(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(
'',
style: TextStyle(
fontSize: 16, color: Theme.of(context).primaryColor),
),
),
);
}
if (handlesResults.length > 0) {
return Container(
color: Theme.of(context).primaryColor,
child: ListView(
children: handlesResults
.map<Widget>((u) => GestureDetector(
child: Padding(
padding: const EdgeInsets.all(0.1),
child: Container(
padding: EdgeInsets.symmetric(vertical: 5),
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
border: Border(
bottom: BorderSide(
width: 0.3, color: Colors.grey[50]))),
child: ListTile(
leading: CircleAvatar(
backgroundColor:
Theme.of(context).primaryColor,
backgroundImage:
NetworkImage(u['userAvatarUrl']),
radius: 20,
),
title: Container(
padding: EdgeInsets.only(left: 10),
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(u['username'],
style: TextStyle(
fontSize: 16,
color: Theme.of(context)
.accentColor),
overflow: TextOverflow.ellipsis),
SizedBox(
height: 5,
),
Text(u['name'],
style: TextStyle(
fontSize: 16,
color: Colors.grey[500],
),
overflow: TextOverflow.ellipsis),
],
),
),
trailing: Container(
padding: EdgeInsets.only(left: 10),
height: 43.0,
width: MediaQuery.of(context).size.width / 2,
),
),
),
),
onTap: () {
showUserProfile(u['id']);
},
))
.toList(),
),
);
} else {
return Container(
color: Theme.of(context).primaryColor,
child: Center(
child: Text(
'No results found',
style: TextStyle(
fontSize: 16,
color: Theme.of(context).accentColor,
),
),
),
);
}
});
}
}
i wanted to user the class SearchUsers as a separate screen that i can navigate to independently...but couldn't achieve that as SearchUsers doesn't evaluate to a widget.
so i built SearchUsersScreen statefulWidget and inside it's initState() i called this:
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) => showSearch(
context: context,
delegate: SearchUsers(
DatabaseService().fetchUsersInSearch(),
),
));
}
as to make the search feature starts automatically when the user navigates to SearchUsersScreen.
and i ended up into two problems:
SearchUsers is being displayed in full screen ontop of SearchUsersSCreen (which i don't want this behavior), i want it to be displayed inside of it.
actually its covering the BottomNavigationBar i built for navigation between screens.
after SearchUsers is being displayed (and its doing its job well), when i tap the device back button...i leave SearchUsers and get back to SearchUsersScreen....which is indeed a blank screen.
so to wrap it up...all i want is to use SearchUsers class as a widget that i can navigate to and navigate from independently...thats it.
any help would be much appreciated.
thanks for your time reading.

Instead of trying to create a separate widget SearchUsers, try to create a dialog and show it when anyone wants to search users. You can also use the navigator and the back button in this case and get arguments passed from the next screen to the previous screen.

Related

How to create multi select CheckboxListTile perfectly in flutter?

I have a Bottom sheet which shows the list of Cities from which I have to select multiple Cities and if I open the bottomSheet second time previous selected cities should be pre selected but only if user press the save button after selecting Cities and if bottomSheet is dismissed then dont include the new selected cities. I am able to select the multiple cities and show previous selected cities in second time. also I am getting null as returned value if bottomSheet is dismissed. but also I am getting upated data in case of dismiss I dont know how it is gettting initialized with new selected values.
below is my code.
This is my bottom sheet.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../../../business_logic/app/app_event_and_state.dart';
import '../bloc/city_bloc.dart';
import '../bloc/city_event.dart';
import '../bloc/city_state.dart';
import '../model/city_model.dart';
class MultiSelectCity extends StatefulWidget {
const MultiSelectCity({Key? key, this.selectedCitiesList}) : super(key: key);
final List<City>? selectedCitiesList;
#override
State<MultiSelectCity> createState() => _MultiSelectCityState();
}
class _MultiSelectCityState extends State<MultiSelectCity> {
bool _isInit = true;
List<City>? selectedCities = [];
List<City> filteredCities = [];
#override
void didChangeDependencies() {
print('didChangeDependencies');
if (_isInit) {
BlocProvider.of<CityBloc>(context)
.add(const AppEventLoadCitiesWithFilter(isActive: true));
}
_isInit = false;
selectedCities = widget.selectedCitiesList;
super.didChangeDependencies();
}
#override
Widget build(BuildContext context) {
return BlocConsumer<CityBloc, AppState>(
builder: (context, state) {
return DraggableScrollableSheet(
initialChildSize: 0.6,
minChildSize: 0.4,
maxChildSize: 0.75,
expand: false,
builder: (context, scrollController) => Container(
color: Colors.white,
child: Column(children: [
Container(
color: Theme.of(context).colorScheme.background,
padding: EdgeInsets.symmetric(vertical: 25.h, horizontal: 45.w),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
height: 15.h,
width: 140.w,
decoration: BoxDecoration(
shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(25.r),
color: Colors.grey.shade400,
),
),
Padding(
padding:
EdgeInsets.only(top: 20.h, left: 10.w, bottom: 2.h),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 25.h),
Text('Select City',
style: TextStyle(
fontWeight: FontWeight.w900,
fontSize: 65.sp)),
],
),
),
],
),
),
Expanded(
child: state.isLoading
? const Center(
child: CircularProgressIndicator(),
)
: filteredCities.isNotEmpty
? ListView.builder(
controller: scrollController,
itemBuilder: (context, index) {
return CheckboxListTile(
title: Text(
'${filteredCities[index].cityName},'
' ${filteredCities[index].stateCode}, '
'${filteredCities[index].countryName}',
style:
Theme.of(context).textTheme.bodyLarge,
),
value: selectedCities?.contains(
filteredCities[index]) ,
onChanged: (bool? value) {
setState(() {
if (selectedCities?.contains(
filteredCities[index]) ==
true) {
selectedCities?.removeWhere((element) =>
element ==
filteredCities[index]);
} else {
selectedCities
?.add(filteredCities[index]);
}
print(value);
});
},
);
},
itemCount: filteredCities.length,
)
: const Center(
child: Text("No cities found"),
),),
Container(
width: double.infinity,
height: 50,
margin: EdgeInsets.all(20),
child: ElevatedButton(
onPressed: () {
return Navigator.of(context).pop(selectedCities); // if save pressed then pass selected cities else if bottomsheet is dismissed it returns null.
},
child: Text(
'Save',
style: TextStyle(
fontWeight: FontWeight.w700, fontSize: 45.sp),
)),
)
]),
),
);
},
listener: (context, state) {
if (state is AppStateActiveCities) {
print(state.activeCities.length.toString());
filteredCities = state.activeCities;
}
},
);
}
}
This is how I am calling it.
Future<void> _showMultiSelectCityOptions() async {
returnedSelectedCities = await showModalBottomSheet<List<City>>(
isScrollControlled: true,
isDismissible: false,
context: context,
builder: (context) => Padding(
padding:
EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
child: MultiSelectCity(selectedCitiesList: selectedCities),
),
);
// here i am getting null as expected if bottomSheet is dismissed but also seletedCites are getting updated I dont know how. can some explain it.
if (returnedSelectedCities != null) {
setState(() {
selectedCities = returnedSelectedCities;
});
}
}

flutter Problem: How to update number of items count in cart?

I implement to add to cart functionality items added into cart successfully but the number of count in the cart badge is not updated when I reload dart page than the number of count updates.can anyone help me?
I implement to add to cart functionality items added into cart successfully but the number of count in the cart badge is not updated when I reload dart page than the number of count updates.can anyone help me?
This is my Homepage.dart
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:badges/badges.dart';
import 'package:hospital/BestDeatProducts/best_deal_product_page.dart';
import 'package:hospital/CartPage/pages/cartPage.dart';
import 'package:hospital/Drawer/dropdown_menu.dart';
import 'package:hospital/FirstSection/carousel.dart';
import 'package:hospital/Drawer/drawercontent.dart';
import 'package:hospital/FloatingActionButton/ConsultWithDoctor/consult_with_doctor.dart';
import 'package:hospital/MedicineCateory/medicine_category_page.dart';
import 'package:hospital/SecondSection/second_page.dart';
import 'package:hospital/ThirdSection/third_page.dart';
import 'package:hospital/TrendingProducts/trending_product_page.dart';
import 'package:hospital/constant.dart';
import 'package:hospital/customApiVariable.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'No Internet/connectivity_provider.dart';
import 'No Internet/no_internet.dart';
import 'package:http/http.dart' as http;
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
SharedPreferences loginData;
// late String username;
Future getUsername() async {
loginData = await SharedPreferences.getInstance();
setState(() {
// print("uname" + uname.toString());
print("dddpppuu1 : responceData_un" +
loginData.getString('responceData_un').toString());
print("dddpppuu2 : responceData_ue" +
loginData.getString('responceData_ue').toString());
print("dddpppuu3 : responceData_status" +
loginData.getString('responceData_status').toString());
String responceData_uid =
loginData.getString('responceData_uid').toString();
fetchData(responceData_uid);
});
}
var response;
var addToCartApi;
#override
void initState() {
// TODO: implement initState
//
super.initState();
Provider.of<ConnectivityProvider>(context, listen: false).startMonitering();
// for loading
getUsername();
}
fetchData(String argResponceData_uid) async {
var api = Uri.parse(
'$ecommerceBaseUrl/addToCartApi.php?a2rTokenKey=$a2rTokenKey&action=addToCartList&uid=${argResponceData_uid}');
print('cartpage' + api.toString());
response = await http.get(api);
print("Carousel" + response.body);
addToCartApi = jsonDecode(response.body);
print('addToCartApi' + addToCartApi['total'].toString());
print('totalPriceAfterOffer' + totalPriceAfterOffer.toString());
setState(() {});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: kGreen,
title: Text(
"BK Arogyam",
style: TextStyle(fontStyle: FontStyle.italic),
),
actions: [
response != null
? Badge(
position: BadgePosition.topEnd(top: 3, end: 18),
animationDuration: Duration(milliseconds: 300),
animationType: BadgeAnimationType.slide,
badgeContent: Text(
addToCartApi['total']['num'].toString(),
style: TextStyle(color: Colors.white),
),
child: IconButton(
icon: Icon(Icons.shopping_cart),
padding: EdgeInsets.only(right: 30.0),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
}),
)
: IconButton(
icon: Icon(Icons.shopping_cart),
// onPressed: () => print("open cart"),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => Cartpage()),
);
},
),
DropDownMenu(),
],
),
floatingActionButton: FloatingActionButton(
backgroundColor: kGreen,
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (context) => ConsultWithDoctor())),
tooltip: 'Consult With Doctor',
child: Container(
child: Image(
image: AssetImage(
"assets/icons/cwd.png",
),
color: Colors.white,
width: 40,
height: 40,
),
),
),
drawer: Drawer(
child: DrawerContent(),
),
body: pageUI());
}
Widget pageUI() {
return Consumer<ConnectivityProvider>(
builder: (consumerContext, model, child) {
if (model.isOnline != null) {
return model.isOnline
? ListView(
children: [
Carousel(),
SizedBox(
height: 10.0,
),
MedicineCategoryPage(),
SizedBox(
height: 10.0,
),
SecondPage(),
SizedBox(
height: 10.0,
),
ThirdPage(),
SizedBox(
height: 10.0,
),
TrendingProductPage(),
SizedBox(
height: 16.0,
),
BestDealProductPage(),
SizedBox(
height: 10.0,
),
],
)
: NoInternet();
}
return Container(
child: Center(
child: CircularProgressIndicator(),
),
);
},
);
}
}
You can use the change notifier provide by provider package.
And watch the video on how to use, exactly for ur use case search YouTube change notifier provider by the growing developer
Hope it helps 🙂
You can use provider(provider: ^5.0.0) or Getx(get: ^4.1.4) to handle this kind of case.
There are lots of examples are available for GetX and Provider.
If you don't want to use any of them, Then store your cart/badge count to tempCartCount variable(Example: int cartCount = 0) and set it to the badge count instead of "addToCartApi['total']['num'].toString()" , Make sure to setState on update/addCart Item.
Here I provide a simple example of how to update count on appBar.
if you want to change from any other screen make cartCount to global otherwise you can set it local/private.
import 'package:badges/badges.dart';
import 'package:flutter/material.dart';
class UpdateCountExample extends StatefulWidget {
#override
_UpdateCountExampleState createState() => _UpdateCountExampleState();
}
int cartCount = 0;
class _UpdateCountExampleState extends State<UpdateCountExample> {
List<String> cartArray = [];
#override
void initState() {
WidgetsBinding.instance!.addPostFrameCallback((timeStamp) {
setState(() {
cartCount = 0;
});
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App Bar"),
actions: [
Padding(
padding: const EdgeInsets.only(right: 18.0, top: 5.0),
child: Badge(
badgeContent: Text(cartCount.toString()),
child: Icon(Icons.add_shopping_cart),
),
)
],
),
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Add item in cart",
textAlign: TextAlign.center,
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18, decoration: TextDecoration.none, color: Colors.black),
),
SizedBox(
height: 20,
),
InkWell(
onTap: () {
setState(() {
cartArray.add("value ${cartArray.length}");
cartCount = cartArray.length;
});
},
child: Container(
padding: const EdgeInsets.all(10.0),
color: Colors.amber,
child: Text(
"Add Item",
textAlign: TextAlign.center,
style: TextStyle(fontSize: 15, decoration: TextDecoration.none, color: Colors.black),
),
),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: cartArray.length,
itemBuilder: (context, index) {
return Text(
cartArray[index],
style: TextStyle(fontSize: 20, color: Colors.black),
);
}),
)
],
),
),
);
}
}
I have used StreamBuilder to update cart items instantly.
You can use the code from this post
How to use Streambuilder in flutter

Flutter Unhandled Exception: NoSuchMethodError: The getter 'uid' was called on null

First of all, I would like to say I have seen all the previous posts on this error but none of them resolved my issue and that's why I am posting it.
Actually, I have understood the problem but unable to resolve it. So, the below dart file is my HomeScreen().
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:mukti/authentication/firestore_service.dart';
import 'package:mukti/schedule/task.dart';
import 'package:mukti/schedule/taskdata.dart';
import 'package:provider/provider.dart';
import 'add_class.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
class HomeScreen extends StatefulWidget {
static final String routeName = 'homeScreen';
final auth.User firebaseUser;
HomeScreen({this.firebaseUser});
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
final FirestoreService firestoreService = FirestoreService();
#override
Widget build(BuildContext context) {
print("HomeScreen");
print(widget.firebaseUser);
return Scaffold(
body: SafeArea(
child: SizedBox.expand(
child: Padding(
padding: const EdgeInsets.all(48.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleChildScrollView(
child: Container(
width: MediaQuery.of(context).size.width,
height: 450,
color: Colors.yellow[100],
child: generateTaskList(),
),
),
SizedBox(height: 45),
/* Add Class Button */
Center(
child: GestureDetector(
onTap: () {
Navigator.push(
context, MaterialPageRoute(
builder: (context) => AddClass(),
),
);
},
child: Container(
height: 75,
width: 75,
decoration: BoxDecoration(
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: Colors.grey,
offset: Offset(0, 4), //(x,y)
blurRadius: 1.0,
),
],
color: Color(0xFFF9A826),
),
child: Icon(
Icons.add,
size: 35,
color: Colors.white,
),
),
),
),
],
),
),
),
),
);
}
Widget generateTaskList() {
//print("Firebase User : ${widget.firebaseUser.uid}");
Provider.of<TaskData>(context, listen: false).loadTaskList(widget.firebaseUser);
print('List Generated');
var taskListLength = Provider.of<TaskData>(context, listen: false).getTaskListCount();
return Consumer<TaskData>(
builder: (context, taskData, child) => ListView.builder(
itemCount: taskData.taskList.length,
itemBuilder: (context, index) {
print("TaskList");
return Container(
padding: EdgeInsets.all(16.0),
decoration: new BoxDecoration (
borderRadius: BorderRadius.circular(10),
color: Color(0xFFF9A826),
),
child: ListTile(
title: Text(
taskData.taskList[index].description ?? 'default',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
),
),
subtitle: Text(
"${Util.getFormattedDate(taskData.taskList[index].scheduledDateTime)}" ?? 'default',
style: TextStyle(
color: Colors.white54,
),
),
),
);
}
)
);
}
}
class Util {
static String getFormattedDate(DateTime dateTime) {
return new DateFormat("EEE, MMM d, y").format(dateTime);
}
}
Initially, firebaseUser is not null, I have crossed checked it and it is printing the data in the app but when I add more entries from AddClass() and returns to HomeScreen() again, firebaseUser becomes null and no data is shown in the app anymore.
The below code is my AddClass() code:
import 'package:flutter/material.dart';
import 'package:mukti/authentication/authService.dart';
import 'package:mukti/authentication/firestore_service.dart';
import 'package:mukti/schedule/scheduled_date.dart';
import 'package:mukti/schedule/task.dart';
import 'package:mukti/ui_pages/main_screen/timepicker.dart';
import 'package:provider/provider.dart';
import 'package:table_calendar/table_calendar.dart';
import 'package:firebase_auth/firebase_auth.dart' as auth;
import 'home_screen.dart';
class AddClass extends StatefulWidget {
static final String routeName = 'addClass';
#override
_AddClassState createState() => _AddClassState();
}
class _AddClassState extends State<AddClass> {
final FirestoreService firestoreService = FirestoreService();
#override
Widget build(BuildContext context) {
print("Add Class Screen");
return Scaffold(
resizeToAvoidBottomInset: false,
backgroundColor: Color(0xFFFFFFE5),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
/* Meeting url TextField Widget */
/* Description TextField Widget */
/* Calender */
/* Add Class Button */
Expanded(
child: GestureDetector(
onTap: () async{
auth.User firebaseUser = await Provider.of<AuthService>(context, listen: false).getUser();
DateTime scheduledDateTime = Provider.of<ScheduledDate>(context, listen: false).scheduledDateTime;
print(scheduledDateTime);
print(firebaseUser);
final task = Task(
link: 'xyz',
isDone: false,
description: 'xyz',
scheduledDateTime: scheduledDateTime,
);
firestoreService.addTask(firebaseUser, task);
print('Task Added');
Navigator.popAndPushNamed(context,
HomeScreen.routeName,
arguments: firebaseUser,
);
},
child: Align(
alignment: FractionalOffset.bottomCenter,
child: Container(
height: 50,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(
color: Color(0xFFF9A826),
),
child: Center(
child: Text(
'SCHEDULE CLASS',
style: Theme.of(context).textTheme.bodyText1.copyWith(
color: Colors.white,
fontWeight: FontWeight.w700,
fontSize: 16,
letterSpacing: 0.5,
),
)
)
),
),
),
),
],
),
),
);
}
}
Actually, I have removed unnecessary codes, so after adding one more class to the database, I return to HomeScreen but this time firebaseUser becomes null, although I am sending it in the argument of the routes HomeScreen is receiving null. This is my problem.
How can I resolve this..?
If anyone needs more information, feel free to ask me.
Thanks

Flutter - The method '|' was called on null. After hot reload it is working

I am pretty new in flutter. I don't know what happening in background because after hot reload its work fine. On another dart files that happens, firebase dont provide me data on initialization just after hot reload.
class CityServices {
getCites() {
return Firestore.instance.collection('cities').getDocuments();
}
}
class _HomeScreenState extends State<HomeScreen> {
bool citiesFlag = false;
var cities;
int citiesCount;
String actualCity;
Maybe mistake is here.
#override
void initState() {
super.initState();
CityServices().getCites().then((QuerySnapshot) {
if (QuerySnapshot.documents.isNotEmpty) {
citiesFlag = true;
cities = QuerySnapshot.documents;
citiesCount = QuerySnapshot.documents.length;
}
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: MyColors.vintageGreen,
appBar: AppBar(
backgroundColor: MyColors.background,
title: Center(
child: Text(
'Válasszon települést...',
style: GoogleFonts.barlowCondensed(
color: MyColors.appbarText,
fontSize: 26.0,
fontWeight: FontWeight.w500),
),
),
),
body: Center(
child: Container(
child: GridView.count(
crossAxisCount: 2,
children: List.generate(citiesCount, (index) {
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)),
),
child: InkWell(
onTap: () {
actualCity = cities[index]['city_name'];
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
CityView(cityName: actualCity)),
);
},
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
title: Center(
child: Text(
cities[index]['city_name'],
style: TextStyle(
fontWeight: FontWeight.w500, fontSize: 18.0),
)),
subtitle: Center(child: Text('22 bejegyzés')),
),
Flexible(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(5)),
child: Padding(
padding: EdgeInsets.only(bottom: 15.0),
child: Image(
image: AssetImage(
cities[index]['img_path'],
),
),
),
),
)
],
),
),
color: MyColors.background,
);
}),
),
),
),
),
);
}
}
Maybe here is the mistake? Should it be on top of dart file?
class HomeScreen extends StatefulWidget {
static const String id = 'home';
#override
_HomeScreenState createState() => new _HomeScreenState();
}
Let me explain the issue and why it is happening, then propose few solutions.
inside initState you are calling CityServices().getCites().then... which is an async method.
However, when your widget is built for the first time, the data you expect from Firestore is not ready yet, thus you get null for both cities and citiesCount.
Short term solution:
make sure there is null check, display indicator while waiting for the data.
body: Center(
child: (cities == null) ?
CircularProgressIndicator()
: Container(...
Additionally, you can also refactor your initState to something like this
void getCities() async {
var snapshot CityServices().getCites();
setState(() {
citiesFlag = true;
cities = snapshot.documents;
citiesCount = snapshot.documents.length;
});
}
#override
void initState() {
getCities();
super.initState();
}
Long term solution:
use BLoC pattern and make data loading decoupled from UI.
see flutter_bloc for how to implement it.

Cloud firestore documentation for flutter

I am trying to write an app with flutter using cloud firestore but in the examples page I do not see a flutter/dart option for the example code, am I missing something?
Here is where I am looking at https://firebase.google.com/docs/firestore/query-data/get-data
Any help would be great. Thanks
There are indeed no examples for Flutter in the Firebase documentation. What I do is that I read the Firebase documentation on the topic I'm trying to learn more about, and then use the FlutterFire documentation for Firestore to construct the corresponding Flutter example myself.
To navigate to the Flutter example, but step-wise it (currently) is:
Go to the home page of the cloud_firestore plugin.
Click on the Example tab
I also frequently use the FlutterFire reference documentation for Firestore to look up API signatures for Flutter, based on the examples in the Firebase documentation for Firestore.
Sorry for late answer,
I was resolving my own project issue.
By the way I have Implemented CRUD Operation with cloud_firestore plugin.
SEE_CRUD_OPREATION_OUTPUT_VIDEO
Here you can analyse my
full code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class CRUDoperation extends StatefulWidget {
#override
_CRUDoperationState createState() => _CRUDoperationState();
}
class _CRUDoperationState extends State<CRUDoperation> {
Firestore firestore = Firestore.instance;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("CRUD"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.group_add),
onPressed: (){
showDialog(
context: context,
child: ShowCustomDialogBox(oprationName: "Add",)
);
}
)
],
),
body: Container(
padding: const EdgeInsets.all(10),
alignment: Alignment.center,
child: StreamBuilder<QuerySnapshot>(
stream: firestore.collection('Employee').snapshots(),
builder: (BuildContext context,AsyncSnapshot<QuerySnapshot> snapshot){
if (snapshot.hasError){
return new Center(
child:Text('Error: ${snapshot.error}')
);
}
if(!snapshot.hasData){
return new Center(
child:CircularProgressIndicator()
);
}
else{
var documents = snapshot.data.documents;
if(documents.length>0){
return ListView.builder(
itemCount:documents.length ,
itemBuilder: (context, index){
return Card(
child: ListTile(
leading: IconButton(
icon: Icon(Icons.edit,color: Colors.blue,),
onPressed: (){
showDialog(
context: context,
child: ShowCustomDialogBox(
documentSnapshot:documents[index],
oprationName: "Edit",
)
);
}
),
title: Text(documents[index].data['Name']),
subtitle: Text(documents[index].data['Post']),
trailing: IconButton(
icon: Icon(Icons.delete,color: Colors.red,),
onPressed: (){
firestore.collection('Employee').document(documents[index].documentID)
.delete().then((onValue){ //delete user
print("Deleted successfully");
});
}
),
),
);
}
);
}else{
return Center(
child: Text("Add Emlopyee list"),
);
}
}
}
),
),
);
}
}
//ADD OR EDIT USER DIALOG BOX
class ShowCustomDialogBox extends StatefulWidget {
final DocumentSnapshot documentSnapshot;
final String oprationName;
ShowCustomDialogBox({ this.documentSnapshot, this.oprationName});
#override
State<StatefulWidget> createState() => ShowCustomDialogBoxState();
}
class ShowCustomDialogBoxState extends State<ShowCustomDialogBox>with SingleTickerProviderStateMixin {
TextEditingController nameController;
TextEditingController postController ;
Firestore firestore = Firestore.instance;
#override
void initState() {
super.initState();
nameController = widget.oprationName == "Edit" ? TextEditingController(text: widget.documentSnapshot.data['Name'])
: TextEditingController();
postController = widget.oprationName == "Edit"? TextEditingController(text:widget.documentSnapshot.data['Post'])
: TextEditingController();
}
launchOpration(){
if(widget.oprationName == "Edit"){
editEmployee();
}else{
addEmployee();
}
}
addEmployee(){ //Create user
if(nameController.text.isNotEmpty && postController.text.isNotEmpty){
firestore.collection("Employee").add({
'Name':nameController.text,
'Post':postController.text
})
.then((doc){
print("employee added successfully documentID :${doc.documentID}");
nameController.clear();
postController.clear();
Navigator.of(context).pop();
});
}
else{
print("Please all fields");
}
}
editEmployee(){ //Update User
firestore.collection('Employee').document(widget.documentSnapshot.documentID).updateData({
'Name':nameController.text,
'Post':postController.text
}).then((onValue){
print("employee Edited successfully");
nameController.clear();
postController.clear();
Navigator.of(context).pop();
});
}
#override
void dispose() {
nameController.dispose();
postController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: Container(
margin: EdgeInsets.all(20.0),
padding: EdgeInsets.all(8.0),
height: MediaQuery.of(context).size.height/2.5,
width: MediaQuery.of(context).size.width,
decoration: ShapeDecoration(
color: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0))),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("${widget.oprationName} Employee"),
SizedBox(height:10),
TextField(
controller: nameController,
decoration: InputDecoration(
hintText: "Enter Name",
border: OutlineInputBorder()
),
),
SizedBox(height:10),
TextField(
controller: postController,
decoration: InputDecoration(
hintText: "Enter Post",
border: OutlineInputBorder()
),
),
],
),
),
Padding(
padding: const EdgeInsets.only(
left: 20.0, right: 10.0, top: 0.0,),
child: ButtonTheme(
height: 35.0,
minWidth: MediaQuery.of(context).size.width/3.5,
child: RaisedButton(
color: Colors.blue,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
splashColor: Colors.white.withAlpha(40),
child: Text(
widget.oprationName,
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 13.0),
),
onPressed: () {
launchOpration();
},
)
)
),
],
)
),
),
);
}
}