The method 'substring' was called on null. Receiver: null Tried calling: substring(0, 1) - flutter

I'm programming a chat application using flutter and firebase. Whenever I click on "Message" button to go to Chat Room screen following error appears:
The method 'substring' was called on null.
Receiver: null
Tried calling: substring(0, 1)
Here's the code of search view. Currently , I'm working to get ChatRoomID by a function to implement chatroom screen but it is showing an error that the substring was null.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:howdy_do/View/chatroomscreen.dart';
import 'package:howdy_do/View/conversation_screen.dart';
import 'package:howdy_do/helper/constants.dart';
import 'package:howdy_do/helper/helperfunctions.dart';
import 'package:howdy_do/services/database.dart';
import 'package:howdy_do/widgets/widget.dart';
class Search extends StatefulWidget {
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController = new TextEditingController();
QuerySnapshot searchResultSnapshot;
Widget searchList(){
return searchResultSnapshot != null ? ListView.builder(
itemCount: searchResultSnapshot.docs.length ,
shrinkWrap: true,
itemBuilder: (context, index) {
return SearchTile(
userName: searchResultSnapshot.docs[index].data()["name"],
userEmail: searchResultSnapshot.docs[index].data()["email"],
);
}) : Container();
}
initiateSearch(){
DatabaseMethods().getUserByUsername(searchTextEditingController.text)
.then((val){
setState(() {
searchResultSnapshot = val;
print("$searchResultSnapshot");
});
});}
Widget SearchTile( {String userName, String userEmail}){
return Container(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(userName, style: simpleTextStyle(),),
Text(userEmail, style: simpleTextStyle(),)
],
),
Spacer(),
GestureDetector(
onTap:() {
createChatroomAndStartConversation( **// Error appears here**
userName: userName
);
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text("Message", style: mediumTextStyle(),),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(24),
gradient: LinearGradient(
colors:[
const Color(0xffF7A1A0),
const Color(0xffF8A3A2)
]
),
)
),
)
],
),
);
}
createChatroomAndStartConversation({ String userName}){
print("${Constants.myName}");
if(userName != Constants.myName) {
List<String> users = [userName,Constants.myName];
String chatRoomId = getChatRoomId(userName,Constants.myName); **// Error appears here**
Map<String,dynamic> chatRoomMap= {
"users": users,
"chatRoomId" : chatRoomId
};
DatabaseMethods().createChatRoom(chatRoomId, chatRoomMap) ;
Navigator.push(context, MaterialPageRoute(
builder: (context) => ConversationScreen(chatRoomId)
));
}else {
print("You can't send text to yourself");
}
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body:Container(
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 15, vertical: 16),
child: Row(
children: [
Expanded(
child: TextField(
controller: searchTextEditingController,
style: TextStyle(
color: const Color(0xffa1a0ba),
fontFamily: 'Poppins',
),
decoration: InputDecoration(
filled: true,
fillColor: const Color(0xffffffff),
border: UnderlineInputBorder(
borderRadius:BorderRadius.circular(30.0)),
hintText: "search username...",
hintStyle: TextStyle(
color: Colors.black12,
fontFamily: 'Poppins',
),
),
)
),
GestureDetector(
onTap: (){
initiateSearch();
},
child: Container(
height: 40,
width: 40,
padding: EdgeInsets.all(8),
child:Image.asset("assets/images/search_white.png")
) ),
],
),
),
searchList() ],), ), ); } }
getChatRoomId(String a, String b) {
if(a.substring(0, 1).codeUnitAt(0)> b.substring(0, 1).codeUnitAt(0)){ **//And error appears here too**
return "$b\_$a";
} else {
return "$a\_$b";
}
}

What's happening is that you are passing getChatRoomId a null value so when you call the substring method it gives you an error because it cannot process a null value. Most probably you are unable to read data from firebase. I suggest you try to print the chatRoodID to make sure you are not getting a null value.

Related

TextFormField and Keyboard in flutter

Good morning, all, I've a problem. I've a text Form Field in my application when I tapped on it to type, the keyboard didn't show this video explain what happened exactly
I read questions that have same problem and try to do its answer but no way
solutions that I tried it.
1- convert the stateless to stateful and the oppsite
2- declare controller global (after imports - in cubit file - in shared file)
3-don't use Form Widget
4- don't use onFieldSubmitted properity
5- try to run flutter run --release but nothing shown in terminal
6- check crashes in google play console
probably I tried most of answers, but no one is working for me,
this is the code of my search screen
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class SearchScreen extends StatefulWidget {
const SearchScreen({Key? key}) : super(key: key);
#override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
var width = size.width;
return BlocConsumer<HomeCubit, HomeStates>(
listener: (context, state) {},
builder: (context, state) {
var cubit = HomeCubit.get(context);
return Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0),
child: Row(
children: [
// which zone text
SizedBox(
width: width * .30,
child: FittedBox(child: Text('اختر المنطقة',style: TextStyle(fontSize: 24,fontWeight:FontWeight.normal))))
const SizedBox(width: 25.0),
Expanded(
child: Center(
child: DropdownButton(
alignment: Alignment.center,
value: cubit.zonePopupValue,
hint: const Text('كل المناطق', textAlign: TextAlign.center),
style: TextStyle(
color: HexColor('#ECB365'),
fontSize: 24,
fontWeight: FontWeight.normal,
),
items: cubit.list,
onChanged: (value) => cubit.changePopupZoneValue(int.parse(value.toString())),
),
),
),
],
)
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: TextFormField(
textInputAction: TextInputAction.search,
onFieldSubmitted: (_) async => cubit.search(),
controller: cubit.searchController,
keyboardType: TextInputType.text,
maxLines: 1,
maxLength: 100,
textAlign: TextAlign.right,
textDirection: TextDirection.rtl,
decoration: InputDecoration(
contentPadding: const EdgeInsets.only(right: 20, left: 10),
labelText: "إبحث",
alignLabelWithHint: true,
labelStyle: TextStyle(
color: HexColor('#ECB365'),
fontSize: 24,
fontWeight: FontWeight.normal,
),
suffixIcon: cubit.isLoadingAuth? CircularProgressIndicator(color: HexColor('#ECB365')): IconButton(
onPressed: () => cubit.search(),
icon: Icon(Icons.search,color: HexColor('#ECB365')),
iconSize: 35,
color: HexColor('#081C31'),
),
border: OutlineInputBorder(borderSide:BorderSide(color: HexColor('#ECB365'))),
focusedBorder: OutlineInputBorder(borderSide: BorderSide(color: HexColor('#ECB365'))),
enabledBorder: OutlineInputBorder(borderSide:BorderSide(color: HexColor('#ECB365'))),
fillColor: HexColor('#ECB365')
),
)
),
Container(
margin: const EdgeInsets.only(left: 10.0, right: 20.0),
child: const Divider(color: Colors.black,height: 36)
),
cubit.responseBodySearch == null
? const Center(child: Text("أبدأ البحث"))
: cubit.responseBodySearch.isEmpty
? const Center(child: Text("غير متوفر حاليا"))
: ListView.builder(
physics: const NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: cubit.responseBodySearch!.length,
itemBuilder: (context, index) => buildSearchItem(cubit, context, index)
)
],
),
),
)
);
}
);
}
}
this is the code of shared component
class HomeCubit extends Cubit<HomeStates> {
HomeCubit() : super(HomeInitState());
static HomeCubit get(context) => BlocProvider.of(context);
String api = 'https://hadayekhof.com/dalel/api/';
var searchController = TextEditingController();
int? zonePopupValue;
void changePopupZoneValue(int value) {
zonePopupValue = value;
getCategoriesData(zoneIds[value].toString());
emit(HomeChangePopupButtonState());
}
var responseBodySearch;
Future search() async {
emit(HomeSearchLoadingState());
responseBodySubCategories = null;
var data = {
'zone_id': zonePopupValue == null ? '' : zoneIds[zonePopupValue!].toString(),
// 'parent_cat': categoryPopupValue == null ? '' : categoryIds[categoryPopupValue!].toString(),
'term': searchController.text.toString()
};
var uri = Uri.parse('${api}stores/searchStores');
var header = {'Authorization': 'Bearer $ciphertext'};
if (searchController.text == '') {
Fluttertoast.showToast(msg: 'من فضلك اكتب شئ');
} else {
await http.post(uri, body: data, headers:header ).then((value) async {
responseBodySearch = await jsonDecode(value.body);
if (value.body.toString().contains('[') == false) {
responseBodySearch = null;
Fluttertoast.showToast(msg: 'no stores found');
}
emit(HomeSearchSuccessState());
}).catchError((error) {
debugPrint("search error is : $error");
emit(HomeSearchErrorState());
});
}
}
}
how can I solve this problem?
finally, I solve It by write this code in the path android\app\src\main\AndroidManifest.xml
<application
...
android: labelwareAccelerated="true"
...>
and this
<activity
...
android:hardwareAccelerated="true"
...>
It's working now

Flutter with Firebase, Search by multiple queries

I am trying to create a search feature that allows users to search by their username, email, designation or company. I intend to let users have the flexibility of typing any of those into the search bar and search for their target. However, what i am facing is that my code below only calls on the first function and displays results only for username (username is the first function here, can be interchanged with other functions and it will call according to that). my code is below and thanks for all the help in advance.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:ib_club/services/database.dart';
import 'package:ib_club/widgets/widget.dart';
class SearchScreen extends StatefulWidget {
#override
State<SearchScreen> createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController =
new TextEditingController();
QuerySnapshot<Map<String, dynamic>> searchSnapshot;
initiateUsernameSearch() {
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateEmailSearch() {
databaseMethods
.getUserByEmail(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateDesignationSearch() {
databaseMethods
.getUserByDesignation(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateCompanySearch() {
databaseMethods
.getUserByCompany(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
initiateSearch() {
initiateUsernameSearch();
initiateEmailSearch();
initiateDesignationSearch();
initiateCompanySearch();
}
// Create chatroom, send user to conversation screen, pushreplacement
/*createChatroomAndStartConversation(String userUsername) {
List<String> users = [
userUsername,
];
databaseMethods.createChatRoom();
}*/
Widget searchList() {
return searchSnapshot != null
? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return SearchTile(
userUsername: searchSnapshot.docs[index].data()["username"],
userEmail: searchSnapshot.docs[index].data()["email"],
userDesignation:
searchSnapshot.docs[index].data()["designation"],
userCompany: searchSnapshot.docs[index].data()["company"],
);
})
: Container(
/*child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(
const Color(0XffFBD24F))))*/
);
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: Container(
child: Column(children: [
SizedBox(
height: 16,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Expanded(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFF)
]),
borderRadius: BorderRadius.circular(40)),
child: TextField(
controller: searchTextEditingController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: "Search User",
hintStyle: TextStyle(color: Colors.white54),
border: InputBorder.none),
),
)),
GestureDetector(
onTap: () {
initiateSearch();
},
child: Container(
height: 45,
width: 45,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFF)
]),
borderRadius: BorderRadius.circular(45)),
child: Icon(Icons.search,
size: 30, color: const Color(0XffFBD24F))),
),
],
),
),
searchList()
]),
));
}
}
class SearchTile extends StatelessWidget {
final String userUsername;
final String userEmail;
final String userDesignation;
final String userCompany;
SearchTile(
{this.userUsername,
this.userEmail,
this.userDesignation,
this.userCompany});
#override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 20),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [const Color(0x36FFFFFF), const Color(0x0FFFFFF)]),
borderRadius: BorderRadius.horizontal()),
child: Row(children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
userUsername,
style: mediumWhiteTextStyle(),
),
Text(
userEmail,
style: mediumWhiteTextStyle(),
),
Text(
userDesignation,
style: mediumWhiteTextStyle(),
),
Text(
userCompany,
style: mediumWhiteTextStyle(),
)
],
),
),
Spacer(),
GestureDetector(
onTap: () {},
child: Container(
decoration: BoxDecoration(
color: const Color(0XffFBD24F),
borderRadius: BorderRadius.circular(30)),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 16),
child: Text(
"Message",
style: mediumTextStyle(),
),
),
)
]),
);
}
}
I could not give a straight answer base on your code but I have a search concept, which I am hoping to help you in any way.
In my case, I always fetch all my item data from firebase and put it in "overallItems" (which is a List of Item Model). From there, I can now start to filter/search my list and return the result.
The concept I use is like this:
List<Item> filterItems() {
//first, I would want to have a temporary holder for a copy of my original items
final List<Item> itemHolder = List<Item>.from(overallItems);
//If user has title input on the search bar
if (titleKeyword.text != '') {
//then this for loop will iterate to all my data
for (final item in List<Item>.from(itemHolder)) {
//will check each title from the list
if (!item.title.toLowerCase().contains(titleKeyword.text.toLowerCase())) {
//elimate items that did not qualify
itemHolder.remove(item);
}
}
}
//so after the first if, itemHolder will be left with the result....
//now, I would also like to search the seller name.
//then, I would just have to repeat the process above
//Searching for Seller Name
if (sellerKeyword.text != '') {
for (final item in List<Item>.from(itemHolder)) {
if (!item.sellerName
.toLowerCase()
.contains(sellerKeyword.text.toLowerCase())) {
itemHolder.remove(item);
}
}
}
//the itemHolder list will have the result
return itemHolder;
}
In the end, we will have the search result after the elimination process.

error: The operator '[]' isn't defined for the type 'Object'. (undefined_operator at [lets_chat] lib/view/search.dart:34)

this is my search.dart file getting error in this
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/rendering.dart';
import 'package:lets_chat/services/database.dart';
import 'package:lets_chat/widgets/widget.dart';
class SearchScreen extends StatefulWidget {
#override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController = new TextEditingController();
QuerySnapshot searchSnapshot;
initiateSearch(){
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val){
searchSnapshot = val;
});
}
Widget searchList(){
return ListView.builder(
itemCount:searchSnapshot.docs.length ,
itemBuilder: (context, index){
return SearchTile(
userName: searchSnapshot.docs[index].data()["name"],
userEmail: searchSnapshot.docs[index].data()["email"],
);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: Container(
child: Column(
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Expanded(
child: TextField(
controller: searchTextEditingController,
style: TextStyle(
color: Colors.orangeAccent
),
decoration: InputDecoration(
hintText: "search username...",
hintStyle: TextStyle(
color: Colors.orangeAccent
),
border: InputBorder.none
)
)
),
GestureDetector(
onTap: (){
initiateSearch();
},
child: Container(
padding: EdgeInsets.all(4),
child: Image.asset("assets/images/SearchIcon.png", height: 35, width: 40,)),
)
],
),
)
],
),
),
);
}
}
class SearchTile extends StatelessWidget {
final String userName;
final String userEmail;
SearchTile({this.userName, this.userEmail});
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: [
Column(
children: [
Text(userName, style: simpleTextStyle(),),
Text(userEmail, style: simpleTextStyle(),)
],
),
Spacer(),
Container(
decoration: BoxDecoration(
color: Colors.deepOrange,
borderRadius: BorderRadius.circular(30)
),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text("Message"),
)
],
),
);
}
}
someone please help i will be very thankful to u :)
error: The operator '[]' isn't defined for the type 'Object'. (undefined_operator at [lets_chat] lib/view/search.dart:34)
i will share other files too if needed please let me know about that
i am just a begginer so please help
We are just assigning the result value here and not updating the state.
It is supposed to be
initiateSearch(){
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val) {
setState(() { searchSnapshot = val; })
});
}
Also, initially the value of searchSnapshot might be null
because of that searchSnapshot.docs[index] here we might run into error saying you have called [].
Tip: Have a loading state which is false until it fetches from the database.
Like
bool isLoaded = false;
and while setting the state,
setState(() {
searchSnapshot = val;
isLoaded = true;
})
Refer: https://flutter.dev/docs/development/data-and-backend/state-mgmt
there is a syntax error in the lines
userName: searchSnapshot.docs[index].data["name"],
userEmail: searchSnapshot.docs[index].data["email"]
it should be
userName: searchSnapshot.docs[index].data["name"],
userEmail: searchSnapshot.docs[index].data["email"]

How to solve: type 'List<dynamic>' is not a subtype of type 'String' [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
I want to update image from listofTaskNotApprove class which it will pass the object of documentsnapshot into the EditTaskNotApprove. Before I update the image, I need to display specific of image where the user will be select specific info from listofTaskNotApprove. The problem is how to display the current index of image into the new screen?
ListOfTaskNotAccepted class.
import 'package:carousel_pro/carousel_pro.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:fyp/screen/RecordOfficer/EditTaskNotApprove.dart';
import 'package:fyp/shared/Loading.dart';
import 'package:google_fonts/google_fonts.dart';
class ListOfTaskNotAccepted extends StatefulWidget {
#override
_ListOfTaskNotAcceptedState createState() => _ListOfTaskNotAcceptedState();
}
final FirebaseAuth auth = FirebaseAuth.instance;
Stream<QuerySnapshot> getUser(BuildContext context) async* {
final FirebaseUser rd = await auth.currentUser();
yield* Firestore.instance.collection("Task").where('uid',isEqualTo: rd.uid).where("verified", isEqualTo: 'TidakSah').snapshots();
}
class _ListOfTaskNotAcceptedState extends State<ListOfTaskNotAccepted> {
List<NetworkImage> _listOfImages = <NetworkImage>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Aduan Tidak Diterima"),
backgroundColor: Colors.redAccent,
),
body: Container(
child: StreamBuilder(
stream: getUser(context),
builder: (context, snapshot){
if (snapshot.hasError || !snapshot.hasData) {
return Loading();
} else{
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index){
DocumentSnapshot da = snapshot.data.documents[index];
_listOfImages =[];
for(int i =0; i <da['url'].length; i++){
_listOfImages.add(NetworkImage(da['url'][i]));
}
return Card(
child:ListTile(
title: Container(
alignment: Alignment.centerLeft,
child: Column(
children: <Widget>[
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Sumber Aduan: ", style: GoogleFonts.asap(fontWeight: FontWeight.bold)),
Text(da['sumberAduan'], style: GoogleFonts.asap(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Nombor Aduan: ", style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
Text(da['noAduan'], style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Lokasi: ", style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
Text(da['kawasan'] + " " + da['naJalan'], style: GoogleFonts.lato(fontWeight: FontWeight.bold)),
],
),
),
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Kategori: ", style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
Text(da['kategori'], style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
],
),
),
Column(
children: [
Container(
margin: EdgeInsets.all(10.0),
height: 200,
decoration: BoxDecoration(
color: Colors.white
),
width: MediaQuery.of(context).size.width,
child: Carousel(
boxFit: BoxFit.cover,
images: _listOfImages,
autoplay: false,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
)
],
),
),
subtitle: Container(
child: Column(
children: [
SizedBox(height: 5.0),
Container(alignment: Alignment.centerLeft,
child: Row(
children: [
Text("Catatan: ", style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
Text(da['comments'], style: GoogleFonts.arimo(fontWeight: FontWeight.w500)),
],
),
),
],
),
),
onTap: () {Navigator.push(context, MaterialPageRoute(builder: (context) => EditTask(da:da)));}
)
);
});
}
}),
)
);
}
}
Here is EditTask class which I need to display current index of image that selected by user.
import 'package:carousel_pro/carousel_pro.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class EditTask extends StatefulWidget {
final DocumentSnapshot da;
const EditTask({Key key, this.da}) : super(key: key);
#override
_EditTaskState createState() => _EditTaskState(da);
}
class _EditTaskState extends State<EditTask> {
DocumentSnapshot da;
_EditTaskState(DocumentSnapshot da){
this.da = da;
}
TextEditingController _noAduan;
TextEditingController _sumberAduan;
TextEditingController _kategori;
DateTime myDateTime = DateTime.now();
#override
void initState(){
super.initState();
_noAduan = TextEditingController(text: widget.da.data['noAduan']);
_sumberAduan =TextEditingController(text: widget.da.data['sumberAduan']);
_kategori = TextEditingController(text: widget.da.data['kategori']);
myDateTime = (da.data['date']).toDate();
_listOfImages = NetworkImage(da.data['url']) as List<NetworkImage>; // this line show the error
}
List <String> sumber = <String> ['Sistem Aduan MBPJ', 'Sistem Aduan Waze', 'Sistem Aduan Utiliti'];
List <String> kate = <String> ['Segera', 'Pembaikan Biasa'];
String kategori;
String sumberAduan;
List <NetworkImage> _listOfImages = <NetworkImage>[];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Kemaskini Aduan"),
backgroundColor: Colors.redAccent,
),
body: Container(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
SizedBox(height: 10.0),
TextFormField(
decoration:InputDecoration(
hintText: myDateTime.toString(),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5))),
onChanged: (value){
setState(() {
myDateTime = value as DateTime;
print(myDateTime);
});
},
),
SizedBox(height: 10.0),
TextFormField(
decoration:InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5))),
controller: _noAduan,
),
SizedBox(height: 10.0),
DropdownButtonFormField(
hint:Text(widget.da.data['sumberAduan']),
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_contact_calendar),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5))),
isExpanded: true,
value: sumberAduan,
onChanged: (newValue) {
setState(() {
sumberAduan = newValue;
_sumberAduan.text = sumberAduan;
});
},
items: sumber.map((sum){
return DropdownMenuItem(
value: sum,
child: new Text(sum),
);
}).toList(),
),
SizedBox(height: 10.0),
DropdownButtonFormField(
hint:Text(widget.da.data['kategori']),
decoration: InputDecoration(
prefixIcon: Icon(Icons.perm_contact_calendar),
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5))),
isExpanded: true,
value: kategori,
onChanged: (newValue) {
setState(() {
kategori = newValue;
_kategori.text = kategori;
});
},
items: kate.map((ka){
return DropdownMenuItem(
value: ka,
child: new Text(ka),
);
}).toList(),
),
Container(
margin: EdgeInsets.all(10.0),
height: 200,
decoration: BoxDecoration(
color: Colors.white
),
width: MediaQuery.of(context).size.width,
child: Carousel(
boxFit: BoxFit.cover,
autoplay: false,
//images: _listOfImages,
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
),
),
)
);
}
}
the image that need to display for update image
This is how I want to display image in class EditTask when the user want to update information from ListOfTaskNotApprove
The error show that "type 'List' is not a subtype of type 'String'"
Can someone help me? because I had tried many method to solve this problem but it didn't work for me.
You say:
_listOfImages = NetworkImage(da.data['url']) as List<NetworkImage>; // this line show the error
Yes, you can't cast a NetworkImage to a List<NetworkImage>. You probably meant:
_listOfImages = [ NetworkImage(da.data['url']) ] as List<NetworkImage>;
The thing is your are getting a list of url's from Firebase storage which are Strings but you are adding this strings into a list of type Network Image which is wrong. As a list of string cannot be converted to a list of Network Image.
There are 2 ways to resolve this-
Change your list type to List and then wherever you show this image use
list data as an argument for Network Image.
List<String> urls=new List();
//suppose list is not empty
....
return NetworkImage(urls[i]);
....
While adding url's to your list add an Network Image object and directly use the list item while showing images.
List<NetworkImage> list=new List();
list.add(NetworkImage('some url'));
....
return list[i];
....

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.