NoSuchMethodError: 'dart.global.firebase.auth' in the Flutter Chat App - firebase

I was creating this Chat App and after implementing the search function I encountered this NoSuchMethodError: tried to call a non-function, such as null: 'dart.global.firebase.auth' problem.
So basically now when I sign up the email and username doesn't get uploaded to firebase auth and Cloud Firestore, which earlier used to happen I think I did some mistake in the search.dart file which seems weird to me.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:intro/helper/constants.dart';
import 'package:intro/services/database.dart';
import 'package:intro/widgets/widgets.dart';
import 'conversation_screen.dart';
class SearchScreen extends StatefulWidget {
#override
_SearchScreenState createState() => _SearchScreenState();
}
class _SearchScreenState extends State<SearchScreen> {
DatabaseMethods databaseMethods = new DatabaseMethods();
TextEditingController searchTextEditingController =
new TextEditingController();
QuerySnapshot searchSnapshot;
Widget searchList() {
return searchSnapshot != null
? ListView.builder(
itemCount: searchSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return searchTile(
searchSnapshot.docs[index].data()["name"],
searchSnapshot.docs[index].data()["email"],
);
})
: Container();
}
initiateSearch() {
databaseMethods
.getUserByUsername(searchTextEditingController.text)
.then((val) {
setState(() {
searchSnapshot = val;
});
});
}
createChatroomAndStartConversation({String userName}) {
String chatRoomId = getChatRoomId(userName, Constants.myName);
List<String> users = [userName, Constants.myName];
Map<String, dynamic> chatRoomMap = {
"users": users,
"chatroomid": chatRoomId
};
DatabaseMethods().createChatRoom(chatRoomId, chatRoomMap);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ConversationScreen(),
));
}
Widget searchTile(String userName, String userEmail) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(userName, style: mediumTextStyle()),
Text(userEmail, style: mediumTextStyle())
],
),
Spacer(),
GestureDetector(
onTap: () {
createChatroomAndStartConversation(userName: userName);
},
child: Container(
decoration: BoxDecoration(
color: Colors.blue, borderRadius: BorderRadius.circular(30)),
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 6),
child: Text(
"Message",
style: mediumTextStyle(),
),
),
)
],
),
);
}
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: Container(
child: Column(
children: [
Container(
color: Color(0x54FFFFFF),
padding: EdgeInsets.symmetric(horizontal: 24, vertical: 16),
child: Row(children: [
Expanded(
child: TextField(
controller: searchTextEditingController,
style: TextStyle(
color: Colors.white,
),
decoration: InputDecoration(
hintText: "Search Username",
hintStyle: TextStyle(
color: Colors.white54,
),
border: InputBorder.none),
),
),
GestureDetector(
onTap: () {
initiateSearch();
},
child: Container(
height: 35,
width: 35,
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0x36FFFFFF),
const Color(0x0FFFFFFF)
]),
borderRadius: BorderRadius.circular(30)),
padding: EdgeInsets.all(1),
child: Icon(
Icons.search,
color: Colors.white,
)),
)
]),
),
searchList()
],
),
),
);
}
}
getChatRoomId(String a, String b) {
if (a.substring(0, 1).codeUnitAt(0) > b.substring(0, 1).codeUnitAt(0)) {
return "$b\_$a";
} else {
return "$a\_$b";
}
}
and just in case there is an error with the signUp.dart file here it is.
import 'package:flutter/material.dart';
import 'package:intro/helper/helperfunctions.dart';
import 'package:intro/services/auth.dart';
import 'package:intro/services/database.dart';
import 'package:intro/widgets/widgets.dart';
import 'chatRoomsScreen.dart';
class SignUp extends StatefulWidget {
final Function toggle;
SignUp(this.toggle);
#override
_SignUpState createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
bool isLoading = false;
AuthMethods authMethods = new AuthMethods();
DatabaseMethods databaseMethods = new DatabaseMethods();
final formKey = GlobalKey<FormState>();
TextEditingController userNameTextEditingController =
new TextEditingController();
TextEditingController emailTextEditingController =
new TextEditingController();
TextEditingController passwordTextEditingController =
new TextEditingController();
signMeUP() {
if (formKey.currentState.validate()) {
Map<String, String> userInfoMap = {
"name": userNameTextEditingController.text,
"email": emailTextEditingController.text,
};
HelperFunctions.saveUserEmailSharedPreference(
emailTextEditingController.text);
HelperFunctions.saveUserNameSharedPreference(
userNameTextEditingController.text);
setState(() {
isLoading = true;
});
authMethods
.signUpwithemailandpassword(emailTextEditingController.text,
passwordTextEditingController.text)
.then((value) {
// print("$value.uid");
databaseMethods.uploadUserInfo(userInfoMap);
HelperFunctions.saveUserLoggedInSharedPreference(true);
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => ChatRoom()));
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: appBarMain(context),
body: isLoading
? Container(
child: Center(child: CircularProgressIndicator()),
)
: SingleChildScrollView(
child: Container(
height: MediaQuery.of(context).size.height - 60,
alignment: Alignment.bottomCenter,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Form(
key: formKey,
child: Column(
children: [
TextFormField(
validator: (val) {
return val.isEmpty || val.length < 2
? "Invalid Username (Needs to be more than 2 characters)"
: null;
},
controller: userNameTextEditingController,
style: simpleTextStyle(),
decoration: textfieldInputDecoration("username"),
),
TextFormField(
validator: (val) {
return RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(val)
? null
: "Enter correct email";
},
controller: emailTextEditingController,
style: simpleTextStyle(),
decoration: textfieldInputDecoration("email"),
),
TextFormField(
obscureText: true,
validator: (val) {
return val.length < 6
? "Please provide with 6+ character"
: null;
},
controller: passwordTextEditingController,
style: simpleTextStyle(),
decoration: textfieldInputDecoration("password"),
),
],
),
),
SizedBox(
height: 10,
),
Container(
alignment: Alignment.centerRight,
child: Container(
padding:
EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
"Forgot Password?",
style: simpleTextStyle(),
),
),
),
SizedBox(
height: 10,
),
GestureDetector(
onTap: () {
signMeUP();
},
child: Container(
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(vertical: 20),
decoration: BoxDecoration(
gradient: LinearGradient(colors: [
const Color(0xff007EF4),
const Color(0xff2A75BC)
]),
borderRadius: BorderRadius.circular(30)),
child: Text("Sign Up", style: mediumTextStyle()),
),
),
SizedBox(
height: 10,
),
Container(
alignment: Alignment.center,
width: MediaQuery.of(context).size.width,
padding: EdgeInsets.symmetric(vertical: 20),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(30)),
child: Text("Sign Up with Google",
style:
TextStyle(color: Colors.black, fontSize: 18)),
),
SizedBox(
height: 15,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"Already have an account? ",
style: mediumTextStyle(),
),
GestureDetector(
onTap: () {
widget.toggle();
},
child: Container(
padding: EdgeInsets.symmetric(vertical: 8),
child: Text(
"Sign in now",
style: TextStyle(
color: Colors.white,
fontSize: 17,
decoration: TextDecoration.underline),
),
),
),
],
),
SizedBox(
height: 50,
)
],
),
),
),
),
);
}
}
And if there is any file anyone of you want: GitHub: Chat App

Because you Haven't initialize the method

Related

Search bar in flutter app fetch articles from WordPress API

I guys, I have a News Flutter app that fetch articles from WordPress API,I have this code in my app but I don't know how to show up articles from search bar.
As you can see in the body of the Home page I have a busy body homepage because there are tabs widgets to show up.
I share screens to understand my case.
Is there another way to show up results maybe using a search delegate?
HomePage
searchbar page
Empty searchbar when I search keyword, no results
Home screen with tabs to load
class SearchBar extends StatefulWidget{
final List<Article> posts;
const SearchBar({Key? key, required this.posts,}) : super(key: key);
#override
_SearchBarState createState() => _SearchBarState();
}
class _SearchBarState extends State<SearchBar> {
final List<Article> _searchedPost = [];
late List<Article> _searchedArticles = [];
late final data;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: TextField(
decoration: const InputDecoration(
hintText: "Cerca Articolo",
border: InputBorder.none,
),
onChanged: (val) {
setState(() {
_searchedArticles = widget.posts.where((element) => element.title!.contains(val)).toList();
});
},
),
),
body: _searchedArticles.isEmpty ?
Scaffold(
body: Padding(padding: const EdgeInsets.all(12),
child: Column(
children: [
Image.asset("assets/images/search-illustration.png", height: 230,),
const SizedBox(height: 20,),
const Text('Nessun articolo trovato!',
style: TextStyle(
fontSize: 20.0,
color: Colors.black,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 20,),
const Text('Inserisci meglio le lettere o parole chiave dell’articolo che stai cercando e riprova.',
style: TextStyle(
fontSize: 16.0,
color: Colors.black54,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 30,),
MaterialButton(
height: 50,
elevation: 0,
color: Colors.blue[900],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
child: Row(
children: const [
Text('Torna alla home', style: TextStyle(fontSize: 16.0, fontWeight: FontWeight.w600),),
],
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => HomePage(),
),
);
},
),
],
),
),
) : ListView.builder(
itemCount: _searchedArticles.length,
itemBuilder: (context, i) {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Card(
margin: const EdgeInsets.all(10),
elevation: 5,
shadowColor: Colors.black26,
child: InkWell(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
//data["_embedded"]["wp:featuredmedia"][0]["link"],),
_searchedArticles[i].urlImage == null
? const Text("Nessuna immagine caricata")
: Image.network(data["_embedded"]["wp:featuredmedia"][0]["link"],
width: double.infinity,
height: 220,
fit: BoxFit.cover,
),
// Title article
Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 16, top: 16, bottom: 16),
child: Row(
children: [
Expanded(
child: Text(_searchedArticles[i].title as String,
maxLines: 3,
overflow: TextOverflow.clip,
softWrap: true,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
,
),
),
),
],
),
)
],
),
],
),
),
onTap: () {
if (_searchedPost[i] != null) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ArticlePage(
data: _searchedPost[i],
),
),
);
}
},
),
),
],
);
},
),
);
}
}```
Home page
class HomePage extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<HomePage> with SingleTickerProviderStateMixin {
TabController? _tabController;
final List<Tab> topTabs = <Tab>[
const Tab(child: Text("Notizie")),
const Tab(child: Text("Fiscalità")),
const Tab(child: Text("Gestione")),
const Tab(child: Text("Business")),
const Tab(child: Text("Documentazione")),
];
#override
void initState() {
/// Start tabs articles
_tabController = TabController(length: topTabs.length, initialIndex: 0, vsync: this)..addListener(() {setState(() {});});
super.initState();
/// End tabs articles
}
/// tabs
Future<bool> _onWillPop() async {
if (_tabController?.index == 0) {
await SystemNavigator.pop();
}
Future.delayed(const Duration(microseconds: 200), () {
_tabController?.index = 0;
});
return _tabController?.index == 0;
}
final _scaffoldKey = GlobalKey<ScaffoldState>();
///
///
/// Search page
final List<Article> _posts = [];
#override
Widget build(BuildContext context) {
return Container(
child: WillPopScope(
onWillPop: _onWillPop,
child: Scaffold(
key: _scaffoldKey,
extendBody: true,
drawer: NavbarMenu(),
backgroundColor: const Color(0xFFFAFAFA),
appBar: AppBar(
elevation: 0,
leading: Builder(
builder: (BuildContext context) {
return GestureDetector(
child: Center(
child: IconButton(
icon: const Icon(
Icons.dehaze_outlined,
color: Colors.white,
),
onPressed: () {
Scaffold.of(context).openDrawer();
},
),
),
);
},
),
backgroundColor: Colors.blue[900],
centerTitle: true,
title: Image.asset('assets/images/bird.png', fit: BoxFit.contain, height: 32,),
/// Action search icon
actions: <Widget>[
/// First search icon
IconButton(
icon: const Icon(Icons.search, color: Colors.white,),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (context)=> SearchBar(posts: _posts,)
));
},
),
],
/// Bottom tab bar
bottom: TabBar(
controller: _tabController,
indicatorColor: const Color(0xFFF9E14B),
tabs: topTabs,
indicator: const UnderlineTabIndicator(
borderSide: BorderSide(
width: 4.0,
color: Color(0xFFF9E14B),
),
insets: EdgeInsets.symmetric(horizontal: 10.0, vertical: 0),
),
labelColor: Colors.yellow,
unselectedLabelColor: Colors.white,
isScrollable: true,
labelStyle: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 16,
fontFamily: "Raleway"),
unselectedLabelStyle: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 14,
),
),
),
/// Body
body: TabBarView(
controller: _tabController,
children: const [
//SearchBar(posts: [],),
NewsPage(),
FiscalitaPage(),
GestionePage(),
BusinessPage(),
DocumentazionePage(),
],
),
///
),
),
);
}```

How can I make that the on ttap button only be pressed one time? - Flutter

I have an issue with flutter, and the isComplet bool are not working well. When I press it twice in the app, it make the task as may times as you tap on there. How can I solve it? This is the entire code. The todos list is a list of tasks to do in a task app, but it works fine:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:mrplan/loading.dart';
import 'package:mrplan/services/database_services.dart';
import 'package:mrplan/src/models/todo.dart';
import 'package:mrplan/src/pages/graficas_circulares_page.dart';
import 'package:mrplan/src/widgets/appbar.dart';
bool isComplet = false;
TextEditingController todoTitleController = TextEditingController();
class Todolist extends StatefulWidget {
#override
_TodolistState createState() => _TodolistState();
}
class _TodolistState extends State<Todolist> {
TextEditingController todoTitleController = TextEditingController();
#override
Widget build(BuildContext context) {
setState(() {
});
return Scaffold(
body: SafeArea(
child: StreamBuilder<List<Todo>>(
stream: DatabaseService().listTodos(),
builder: (context, snapshot) {
if(!snapshot.hasData){
return Loading();
}
List<Todo> todos = snapshot.data;
if(todos.length == 0){
return Center(child: Text('No hay tareas agregadas!'));
}
return Padding(
padding:EdgeInsets.all(0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 20),
Expanded(
child: ListView.separated(
separatorBuilder: (context, index)=> Divider(color: Colors.white),
shrinkWrap: true,
itemCount: todos.length,
itemBuilder: (context, index){
return Dismissible(
key: UniqueKey(),
background: Container(padding: EdgeInsets.only(left: 20),
alignment: Alignment.centerLeft,
child: Icon(Icons.delete),
color: Colors.red),
onDismissed: (direction) async {
await DatabaseService().removeTodo(todos[index].uid);
quitar();
},
child: StreamBuilder<DocumentSnapshot>(
stream: FirebaseFirestore.instance.collection('Todos').doc().snapshots(),
builder: (context, snapshot) {
var todoss = snapshot.data;
return ListTile(
onTap: (){
isComplet = !isComplet;
if (Todo().isComplet = true)
{DatabaseService().completTask(todos[index].uid);}
if (Todo().isComplet = false)
{DatabaseService().uncompletTask(todos[index].uid);}},
leading: Container(
padding: EdgeInsets.all(2),
height: 30,
width: 30,
decoration: BoxDecoration(
color: Theme.of(context).primaryColor,
shape: BoxShape.circle
),
child: todos[index].isComplet
? Icon(
Icons.check,
color: Colors.white,)
: Container(),
),
title: Text(
todos[index].title,
style: todos[index].isComplet
? TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: TextDecoration.lineThrough,
decorationColor: Colors.red,
)
: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w600,
decoration: null
)
),
);
}
),
);
}
),
)
],
),
);
}
)
),
);
}
}
class Appbar extends StatefulWidget {
#override
_AppbarState createState() => _AppbarState();
}
class _AppbarState extends State<Appbar> {
#override
Widget build(BuildContext context) {
bool isbuttondisabled = false;
setState(() {
});
return StreamBuilder<Object>(
stream: null,
builder: (context, snapshot) {
return Container(
alignment: Alignment.bottomCenter,
child: BottomAppBar(
elevation: 0,
child: Container(
height: MediaQuery.of(context).size.height * 0.05,
width: MediaQuery.of(context).size.width,
child: Row(
children: [
Container(
decoration: BoxDecoration(
color:Colors.grey[100],
borderRadius: BorderRadius.only(
topLeft: const Radius.circular(5.0),
)
),
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.symmetric(horizontal: 10.0),
width: MediaQuery.of(context).size.width * 0.835,
child: Center(
child: TextFormField(
controller: todoTitleController,
autofocus: true,
decoration: InputDecoration(
hintStyle: TextStyle(color: Colors.blue[800]),
hintText: "Inserte una tarea...",
border: InputBorder.none
),
),
),
),
TextButton(
child: Container(
height: MediaQuery.of(context).size.height,
child: Center(child: Icon(Icons.add))),
style: TextButton.styleFrom(
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topRight: const Radius.circular(10.0),
)
),
backgroundColor: Theme.of(context).primaryColor
),
onPressed: isbuttondisabled ? null : ()async {
if(todoTitleController.text.isNotEmpty){
await DatabaseService().createNewTodo(todoTitleController.text.trim());
FocusScope.of(context).unfocus();
anadir();
todoTitleController.clear();
isComplet = !isComplet;
}
}
)
],
),
)
)
);
}
);
}
}
The relevant code where I am stucked is this:
onTap: (){
isComplet = !isComplet;
if (Todo().isComplet = true)
{DatabaseService().completTask(todos[index].uid);}
if (Todo().isComplet = false)
{DatabaseService().uncompletTask(todos[index].uid);}},
Thanks a lot!
It would be better if you could refactor the code a little bit. But heres the problem
remove this code inside the build method
bool isbuttondisabled = false;
setState(() {
});
add bool isbuttondisabled = false;
outside the build method.
where ever your button is,
in the onPressed parameter
setState(() {
isbuttondisabled=true;
//Todo add your code
});```

Error "The method '[]' was called on null. Receiver: null Tried calling: []("0tm2JqPY0oNq5vSM74BqOufhGao1")"

I am getting this error in the poll post Page after added the voting feature to it:
The new method I added is handleTotalVotePosts to handle the count of userPostPolls(in line number 178).
I think the error is getting the userId or something which i am not Sure .
I am not sure what is actually wrong here
The method '[]' was called on null.
Receiver: null
Tried calling: []("0tm2JqPY0oNq5vSM74BqOufhGao1")
But code seems to be correct
This my **pollPost.dart**
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:justpoll/libmodels/user_model.dart';
import 'package:justpoll/screens/chat/chat_data.dart';
import 'package:justpoll/widgets/progress.dart';
import 'package:justpoll/widgets/toast_text.dart';
import '../Constants.dart';
import 'package:justpoll/widgets/custom_image.dart';
import 'package:animated_button/animated_button.dart';
class PollPost extends StatefulWidget {
final String pollPostId;
final String mediaUrl;
final String ownerId;
final String username;
final String caption;
final String category;
final String colorTheme;
final Timestamp duration;
final String question;
final dynamic votesTotal;
final String optText1;
final String optText2;
final String optText3;
final String optText4;
final String optemo1;
final String optemo2;
final String optemo3;
final String optemo4;
final String optCount1;
final String optCount2;
final String optCount3;
final String optCount4;
PollPost({
this.pollPostId,
this.mediaUrl,
this.ownerId,
this.username,
this.caption,
this.category,
this.colorTheme,
this.duration,
this.question,
this.votesTotal,
this.optText1,
this.optText2,
this.optText3,
this.optText4,
this.optemo1,
this.optemo2,
this.optemo3,
this.optemo4,
this.optCount1,
this.optCount2,
this.optCount3,
this.optCount4,
});
factory PollPost.fromDocument(DocumentSnapshot doc) {
return PollPost(
pollPostId: doc['pollPostid'],
mediaUrl: doc['mediaUrl'],
ownerId: doc['ownerId'],
username: doc['username'],
caption: doc['caption'],
category: doc['category'],
colorTheme: doc['colorTheme'],
duration: doc['Duration'],
question: doc['Question'],
votesTotal: doc['votesTotal'],
optText1: doc["options"]["1"]["optionText1"],
optText2: doc["options"]["2"]["optionText2"],
optText3: doc["options"]["3"]["optionText3"],
optText4: doc["options"]["4"]["optionText4"],
optemo1: doc["options"]["1"]["optionEmoji1"],
optemo2: doc["options"]["2"]["optionEmoji2"],
optemo3: doc["options"]["3"]["optionEmoji3"],
optemo4: doc["options"]["4"]["optionEmoji4"],
// optCount1: doc["options"]["1"]["optionCount1"],
// optCount2: doc["options"]["2"]["optionCount2"],
// optCount3: doc["options"]["3"]["optionCount3"],
// optCount4: doc["options"]["4"]["optionCount4"],
);
}
int getreactionsTotalCount(votesTotal) {
if (votesTotal == null) {
return 0;
}
int count = 0;
votesTotal.values.forEach((val) {
if (val = true) {
count += 1;
}
});
return count;
}
#override
_PollPostState createState() => _PollPostState(
pollPostId: this.pollPostId,
mediaUrl: this.mediaUrl,
ownerId: this.ownerId,
username: this.username,
caption: this.caption,
category: this.category,
colorTheme: this.colorTheme,
duration: this.duration,
question: this.question,
optText1: this.optText1,
optText2: this.optText2,
optText3: this.optText3,
optText4: this.optText4,
optemo1: this.optemo1,
optemo2: this.optemo2,
optemo3: this.optemo3,
optemo4: this.optemo4,
votesTotalCount: getreactionsTotalCount(this.votesTotal),
);
}
class _PollPostState extends State<PollPost> {
GlobalKey floatingKey = LabeledGlobalKey("Floating");
bool isFloatingOpen = false;
OverlayEntry floating;
static FirebaseAuth auth = FirebaseAuth.instance;
final userRef = FirebaseFirestore.instance.collection("users");
final pollPostsRef = FirebaseFirestore.instance.collection("pollPosts");
final String currentUserId = auth.currentUser?.uid;
final String pollPostId;
final String mediaUrl;
final String ownerId;
final String username;
final String caption;
final String category;
final String colorTheme;
final Timestamp duration;
final String question;
final String optText1;
final String optText2;
final String optText3;
final String optText4;
final String optemo1;
final String optemo2;
final String optemo3;
final String optemo4;
int votesTotalCount;
Map votesTotal;
bool isVoted;
_PollPostState({
this.pollPostId,
this.mediaUrl,
this.ownerId,
this.username,
this.caption,
this.category,
this.colorTheme,
this.duration,
this.question,
this.votesTotal,
this.votesTotalCount,
this.optText1,
this.optText2,
this.optText3,
this.optText4,
this.optemo1,
this.optemo2,
this.optemo3,
this.optemo4,
});
handleTotalVotePosts() {
bool _isVoted = votesTotal[currentUserId] == true;
if (_isVoted) {
pollPostsRef
.doc(ownerId)
.collection('usersPollPosts')
.doc(pollPostId)
.update({'votesTotal.$currentUserId': false});
setState(() {
votesTotalCount -= 1;
isVoted = false;
votesTotal[currentUserId] = false;
});
} else if (!_isVoted) {
pollPostsRef
.doc(ownerId)
.collection('usersPollPosts')
.doc(pollPostId)
.update({'votesTotal.$currentUserId': true});
setState(() {
votesTotalCount += 1;
isVoted = true;
votesTotal[currentUserId] = true;
});
}
}
OverlayEntry createFloating() {
RenderBox renderBox = floatingKey.currentContext.findRenderObject();
Offset offset = renderBox.localToGlobal(Offset.zero);
return OverlayEntry(builder: (context) {
return Positioned(
left: offset.dx,
top: offset.dy - 70,
child: Material(
color: Colors.transparent,
elevation: 20,
child: ClipRRect(
borderRadius: BorderRadius.circular(40.0),
child: Container(
padding: EdgeInsets.all(5.0),
height: 50,
color: MyColors.black,
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(5.0),
child: AnimatedButton(
onPressed: () {
handleTotalVotePosts();
toastMessage("You voted for $optText1 $optemo1");
setState(() {
if (isFloatingOpen)
floating.remove();
else {
floating = createFloating();
Overlay.of(context).insert(floating);
}
isFloatingOpen = !isFloatingOpen;
});
},
duration: 20,
enabled: true,
width: 30,
height: 30,
color: MyColors.black,
shadowDegree: ShadowDegree.light,
child:
Text(optemo1, style: TextStyle(fontSize: 20.0)))),
Padding(
padding: const EdgeInsets.all(5.0),
child: AnimatedButton(
onPressed: () {
toastMessage("You voted for $optText2 $optemo2");
setState(() {
handleTotalVotePosts();
if (isFloatingOpen)
floating.remove();
else {
floating = createFloating();
Overlay.of(context).insert(floating);
}
isFloatingOpen = !isFloatingOpen;
});
},
duration: 20,
enabled: true,
width: 30,
height: 30,
color: MyColors.black,
shadowDegree: ShadowDegree.light,
child:
Text(optemo2, style: TextStyle(fontSize: 20.0)))),
optText3.isEmpty
? Text("")
: Padding(
padding: const EdgeInsets.all(5.0),
child: AnimatedButton(
onPressed: () {
handleTotalVotePosts();
toastMessage(
"You voted for $optText3 $optemo3");
setState(() {
if (isFloatingOpen)
floating.remove();
else {
floating = createFloating();
Overlay.of(context).insert(floating);
}
isFloatingOpen = !isFloatingOpen;
});
},
duration: 20,
enabled: true,
width: 30,
height: 30,
color: MyColors.black,
shadowDegree: ShadowDegree.light,
child: Text(optemo3,
style: TextStyle(fontSize: 20.0)))),
optText4.isEmpty
? Text("")
: Padding(
padding: const EdgeInsets.all(5.0),
child: AnimatedButton(
onPressed: () {
handleTotalVotePosts();
toastMessage(
"You voted for $optText4 $optemo4");
setState(() {
if (isFloatingOpen)
floating.remove();
else {
floating = createFloating();
Overlay.of(context).insert(floating);
}
isFloatingOpen = !isFloatingOpen;
});
},
duration: 20,
enabled: true,
width: 30,
height: 30,
color: MyColors.black,
shadowDegree: ShadowDegree.light,
child: Text(optemo4,
style: TextStyle(fontSize: 20.0)))),
],
),
),
),
),
);
});
}
buildPollPostHeader() {
return FutureBuilder(
future: userRef.doc(ownerId).get(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return circularProgress();
}
UserModel user = UserModel.fromMap(snapshot.data.data());
return ListTile(
leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(user.photoUrl),
backgroundColor: Colors.grey,
),
title: GestureDetector(
onTap: () => toastMessage("showing profile"),
child: Text(
user.username,
style: TextStyle(
color: MyColors.black,
fontWeight: FontWeight.bold,
),
),
),
subtitle: Text(category),
trailing: IconButton(
onPressed: () => toastMessage("pop up menu"),
icon: Icon(Icons.more_vert),
),
);
},
);
}
buildPollPostCenter() {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
question,
style: TextType.boldHeading,
),
),
mediaUrl == null
? Center(
child: Container(
height: 30.0,
))
: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: chachedNetworkImage(
mediaUrl,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Column(
children: [
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
optText1,
style: TextStyle(
color: MyColors.offBlack,
fontSize: 16.0,
),
),
Text(optemo1),
SizedBox(
width: 25.0,
),
Text(
optText2,
style: TextStyle(
color: MyColors.offBlack,
fontSize: 16.0,
),
),
Text(optemo2),
],
),
],
),
SizedBox(height: 13.0),
Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
optText3,
style: TextStyle(
color: MyColors.offBlack,
fontSize: 16.0,
),
),
Text(optemo3),
SizedBox(
width: 25.0,
),
Text(
optText4,
style: TextStyle(
color: MyColors.offBlack,
fontSize: 16.0,
),
),
Text(optemo4),
],
),
],
),
],
),
),
],
);
}
buildPollPostFooter() {
return Column(
children: [
Align(
alignment: Alignment.bottomLeft,
child: Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Padding(padding: EdgeInsets.only(top: 40.0, left: 20.0)),
isVoted
? GestureDetector(
key: floatingKey,
onTap: () {
setState(() {
if (isFloatingOpen)
floating.remove();
else {
floating = createFloating();
Overlay.of(context).insert(floating);
}
isFloatingOpen = !isFloatingOpen;
});
},
child: Icon(
Icons.poll,
color: MyColors.offBlack,
size: 28.0,
),
)
: Icon(Icons.check_circle),
Padding(padding: EdgeInsets.only(right: 20.0)),
GestureDetector(
onTap: () => toastMessage("show comments"),
child: Icon(
Icons.chat,
color: MyColors.offBlack,
size: 28.0,
),
),
Padding(padding: EdgeInsets.only(right: 20.0)),
GestureDetector(
onTap: () => toastMessage("saved successfully"),
child: Icon(
Icons.bookmark,
color: MyColors.offBlack,
size: 28.0,
),
),
Padding(padding: EdgeInsets.only(right: 20.0)),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
GestureDetector(
onTap: () => toastMessage("sharing with friends"),
child: Align(
alignment: Alignment.topRight,
child: Icon(
Icons.send,
color: MyColors.offBlack,
size: 28.0,
),
),
),
Padding(padding: EdgeInsets.only(right: 25.0)),
],
),
),
],
),
),
),
Row(
children: [
Container(
margin: EdgeInsets.only(left: 20.0, top: 5.0),
child: Text(
"$votesTotalCount votes",
style: TextStyle(
color: MyColors.black,
fontWeight: FontWeight.bold,
),
),
),
Container(
margin: EdgeInsets.only(left: 20.0, top: 5.0),
child: Text(
"expiring in 4 days",
style: TextStyle(
color: MyColors.black,
fontWeight: FontWeight.bold,
),
),
)
],
),
Padding(
padding: const EdgeInsets.only(top: 5.0, bottom: 10.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
margin: EdgeInsets.only(left: 20.0),
child: Text(
"$username ",
style: TextStyle(
color: MyColors.black,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: Text(caption),
),
],
),
)
],
);
}
#override
Widget build(BuildContext context) {
isVoted = (votesTotal[currentUserId] == true);
return Card(
elevation: 1.0,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
buildPollPostHeader(),
buildPollPostCenter(),
buildPollPostFooter(),
],
),
);
}
}
Please help me to get out of this bug.
Thank you :)
Please write the below code inside your handleTotalVotePosts method:
if(votesTotal == null){
return;
}

How to display and update multiple image in flutter

I want to display image from list of task which I pass the object of documentsnapshot into the edit task.
Here is my code.
ListOfTaskNotAccepted
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]));
}
DateTime myDateTime = (da['date']).toDate();
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)));}
)
);
});
}
}),
)
);
}
}
In this code, I pass the documentsnapshot da in navigator. here is my code EditTask
import 'dart:io';
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;
String _listOfImages;
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 = da.data['url'];
}
List <String> sumber = <String> ['Sistem Aduan MBPJ', 'Sistem Aduan Waze', 'Sistem Aduan Utiliti'];
List <String> kate = <String> ['Segera', 'Pembaikan Biasa'];
String kategori;
String sumberAduan;
File image;
#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(),
),
SizedBox(height: 10.0),
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,
autoplay: false,
images:Image.network(da.data['url']),
indicatorBgPadding: 5.0,
dotPosition: DotPosition.bottomCenter,
animationCurve: Curves.fastLinearToSlowEaseIn,
animationDuration: Duration(milliseconds: 2000),
),
)
],
)
],
),
),
)
);
}
}
The error show that
Error: The argument type 'Image' can't be assigned to the parameter type 'List'.
I had problem to display the image when user to want to edit specific task. I had tried many method to display specific image that user selected for updating. Is there anything method to display it? someone can explain please?
You have to provide a Image List. Look at the following exemple:
CarouselSlider(
options: CarouselOptions(height: 400.0),
items: [1,2,3,4,5].map((i) {
return Builder(
builder: (BuildContext context) {
return Container(
width: MediaQuery.of(context).size.width,
margin: EdgeInsets.symmetric(horizontal: 5.0),
decoration: BoxDecoration(
color: Colors.amber
),
child: Text('text $i', style: TextStyle(fontSize: 16.0),)
);
},
);
}).toList(),
)
You should change the way you are querying the images in the widget tree to something like the example above.
you can use
GridView.builder()
List imagesLinks = [
"first link",
"second link",
"third link",
"fourth link",
"fifth link",
"sixth link",
"seventh link",
];
GridView.builder(
padding: EdgeInsets.all(10),
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 5.0,
mainAxisSpacing: 5.0,
),
itemCount: imageLinks.length,
itemBuilder: (context, index) {
return Column(
children: [
CircleAvatar(
radius: 30,
child:Image.network('${imageLinks[index]}'),
),
],
);
},
)

How to perform CRUD operations with BLoC pattern?

I was learning on flutter how to perform CRUD operations using BLoC pattern, I saw a tutorial online and try to apply it. C,R,U are OK, but deletion is not working. this is the source code.
Please Help !
file todo_bloc.dart
import 'package:zencartos/models/todo.dart';
import 'package:zencartos/repository/todo_repository.dart';
class TodoBloc {
//Get instance of the Repository
final _todoRepository = TodoRepository();
final _todoController = StreamController<List<Todo>>.broadcast();
get todos => _todoController.stream;
TodoBloc() {
getTodos();
}
getTodos({String query}) async {
_todoController.sink.add(await _todoRepository.getAllTodos(query: query));
}
addTodo(Todo todo) async {
await _todoRepository.insertTodo(todo);
getTodos();
}
updateTodo(Todo todo) async {
await _todoRepository.updateTodo(todo);
getTodos();
}
deleteTodoById(int id) async {
_todoRepository.deleteTodoById(id);
getTodos();
}
dispose() {
_todoController.close();
}
}
DAO Page todo_dao.dart
import 'package:zencartos/database/database.dart';
import 'package:zencartos/models/todo.dart';
class TodoDao {
final dbProvider = DatabaseProvider.dbProvider;
Future<int> createTodo(Todo todo) async{
final db = await dbProvider.database;
var result = db.insert(todoTABLE, todo.toDatabaseJson());
return result;
}
Future<List<Todo>> getTodos({List<String> columns, String query})
async{
final db = await dbProvider.database;
List<Map<String, dynamic>> result;
if (query != null){
if (query.isNotEmpty)
result = await db.query(todoTABLE, columns: columns, where: 'description LIKE ?', whereArgs: ["%$query%"]);
} else {
result = await db.query(todoTABLE, columns: columns);
}
List<Todo> todos = result.isNotEmpty
? result.map((item)=> Todo.fromDatabaseJson(item)).toList()
: [];
return todos;
}
//Update Todo record
Future<int> updateTodo(Todo todo) async{
final db = await dbProvider.database;
var result = await db.update(todoTABLE, todo.toDatabaseJson(),
where: "id = ?", whereArgs: [todo.id]);
return result;
}
//Delete Todo records
Future<int> deleteTodo(int id) async{
final db = await dbProvider.database;
var result = await db.delete(todoTABLE, where: 'id = ?', whereArgs: [id]);
return result;
}
}
Database Page database.dart
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
final todoTABLE = 'Todo';
class DatabaseProvider {
static final DatabaseProvider dbProvider = DatabaseProvider();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await createDatabase();
return _database;
}
createDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "ReactiveTodo");
var database = await openDatabase(path, version: 1, onCreate: initDB, onUpgrade: onUpgrade);
return database;
}
void onUpgrade(Database database, int oldVersion, int newVersion){
if (newVersion > oldVersion){}
}
void initDB(Database database, int version) async{
await database.execute("CREATE TABLE $todoTABLE ("
"id INTEGER PRIMARY KEY, "
"description TEXT, "
"is_done INTEGER "
")");
}
}
Model page todo.dart
class Todo{
int id;
String description;
bool isDone = false;
Todo({this.id, this.description, this.isDone = false});
factory Todo.fromDatabaseJson(Map<String, dynamic> data) => Todo(
id: data['data'],
description: data['description'],
isDone: data['is_done'] == 0 ? false : true,
);
Map<String, dynamic> toDatabaseJson() => {
"id": this.id,
"description": this.description,
"is_done": this.isDone == false ? 0 : 1,
};
}
View page home_Page2.dart
import 'package:flutter/services.dart';
import 'package:zencartos/bloc/todo_bloc.dart';
import 'package:zencartos/models/todo.dart';
class HomePage2 extends StatelessWidget {
HomePage2({Key key, this.title}) : super(key: key);
final TodoBloc todoBloc = TodoBloc();
final String title;
//Allows Todo card to be dismissable horizontally
final DismissDirection _dismissDirection = DismissDirection.horizontal;
#override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle.dark.copyWith(
statusBarColor: Colors.white,
systemNavigationBarColor: Colors.white,
systemNavigationBarIconBrightness: Brightness.dark,
statusBarBrightness: Brightness.dark));
return Scaffold(
resizeToAvoidBottomPadding: false,
body: SafeArea(
child: Container(
color: Colors.white,
padding:
const EdgeInsets.only(left: 2.0, right: 2.0, bottom: 2.0),
child: Container(
//This is where the magic starts
child: getTodosWidget()))),
bottomNavigationBar: BottomAppBar(
color: Colors.white,
child: Container(
decoration: BoxDecoration(
border: Border(
top: BorderSide(color: Colors.grey, width: 0.3),
)),
child: Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
IconButton(
icon: Icon(
Icons.menu,
color: Colors.indigoAccent,
size: 28,
),
onPressed: () {
//just re-pull UI for testing purposes
todoBloc.getTodos();
}),
Expanded(
child: Text(
"Todo",
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.w600,
fontFamily: 'RobotoMono',
fontStyle: FontStyle.normal,
fontSize: 19),
),
),
Wrap(children: <Widget>[
IconButton(
icon: Icon(
Icons.search,
size: 28,
color: Colors.indigoAccent,
),
onPressed: () {
_showTodoSearchSheet(context);
},
),
Padding(
padding: EdgeInsets.only(right: 5),
)
])
],
),
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: Padding(
padding: EdgeInsets.only(bottom: 25),
child: FloatingActionButton(
elevation: 5.0,
onPressed: () {
_showAddTodoSheet(context);
},
backgroundColor: Colors.white,
child: Icon(
Icons.add,
size: 32,
color: Colors.indigoAccent,
),
),
));
}
void _showAddTodoSheet(BuildContext context) {
final _todoDescriptionFormController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return new Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: new Container(
color: Colors.transparent,
child: new Container(
height: 230,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: Padding(
padding: EdgeInsets.only(
left: 15, top: 25.0, right: 15, bottom: 30),
child: ListView(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller: _todoDescriptionFormController,
textInputAction: TextInputAction.newline,
maxLines: 4,
style: TextStyle(
fontSize: 21, fontWeight: FontWeight.w400),
autofocus: true,
decoration: const InputDecoration(
hintText: 'I have to...',
labelText: 'New Todo',
labelStyle: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.w500)),
validator: (String value) {
if (value.isEmpty) {
return 'Empty description!';
}
return value.contains('')
? 'Do not use the # char.'
: null;
},
),
),
Padding(
padding: EdgeInsets.only(left: 5, top: 15),
child: CircleAvatar(
backgroundColor: Colors.indigoAccent,
radius: 18,
child: IconButton(
icon: Icon(
Icons.save,
size: 22,
color: Colors.white,
),
onPressed: () {
final newTodo = Todo(
description:
_todoDescriptionFormController
.value.text);
if (newTodo.description.isNotEmpty) {
/*Create new Todo object and make sure
the Todo description is not empty,
because what's the point of saving empty
Todo
*/
todoBloc.addTodo(newTodo);
//dismisses the bottomsheet
Navigator.pop(context);
}
},
),
),
)
],
),
],
),
),
),
),
);
});
}
void _showTodoSearchSheet(BuildContext context) {
final _todoSearchDescriptionFormController = TextEditingController();
showModalBottomSheet(
context: context,
builder: (builder) {
return new Padding(
padding: EdgeInsets.only(
bottom: MediaQuery.of(context).viewInsets.bottom),
child: new Container(
color: Colors.transparent,
child: new Container(
height: 230,
decoration: new BoxDecoration(
color: Colors.white,
borderRadius: new BorderRadius.only(
topLeft: const Radius.circular(10.0),
topRight: const Radius.circular(10.0))),
child: Padding(
padding: EdgeInsets.only(
left: 15, top: 25.0, right: 15, bottom: 30),
child: ListView(
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextFormField(
controller: _todoSearchDescriptionFormController,
textInputAction: TextInputAction.newline,
maxLines: 4,
style: TextStyle(
fontSize: 18, fontWeight: FontWeight.w400),
autofocus: true,
decoration: const InputDecoration(
hintText: 'Search for todo...',
labelText: 'Search *',
labelStyle: TextStyle(
color: Colors.indigoAccent,
fontWeight: FontWeight.w500),
),
validator: (String value) {
return value.contains('#')
? 'Do not use the # char.'
: null;
},
),
),
Padding(
padding: EdgeInsets.only(left: 5, top: 15),
child: CircleAvatar(
backgroundColor: Colors.indigoAccent,
radius: 18,
child: IconButton(
icon: Icon(
Icons.search,
size: 22,
color: Colors.white,
),
onPressed: () {
/*This will get all todos
that contains similar string
in the textform
*/
todoBloc.getTodos(
query:
_todoSearchDescriptionFormController
.value.text);
//dismisses the bottomsheet
Navigator.pop(context);
},
),
),
)
],
),
],
),
),
),
),
);
});
}
Widget getTodosWidget() {
return StreamBuilder(
stream: todoBloc.todos,
builder: (BuildContext context, AsyncSnapshot<List<Todo>> snapshot) {
return getTodoCardWidget(snapshot);
},
);
}
Widget getTodoCardWidget(AsyncSnapshot<List<Todo>> snapshot) {
if (snapshot.hasData) {
return snapshot.data.length != 0
? ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, itemPosition) {
Todo todo = snapshot.data[itemPosition];
final Widget dismissibleCard = new Dismissible(
background: Container(
child: Padding(
padding: EdgeInsets.only(left: 10),
child: Align(
alignment: Alignment.centerLeft,
child: Text(
"Deleting",
style: TextStyle(color: Colors.white),
),
),
),
color: Colors.redAccent,
),
onDismissed: (direction) {
todoBloc.deleteTodoById(todo.id);
},
direction: _dismissDirection,
key: new ObjectKey(todo),
child: Card(
shape: RoundedRectangleBorder(
side: BorderSide(color: Colors.grey[200], width: 0.5),
borderRadius: BorderRadius.circular(5),
),
color: Colors.white,
child: ListTile(
leading: InkWell(
onTap: () {
//Reverse the value
todo.isDone = !todo.isDone;
todoBloc.updateTodo(todo);
},
child: Container(
//decoration: BoxDecoration(),
child: Padding(
padding: const EdgeInsets.all(15.0),
child: todo.isDone
? Icon(
Icons.done,
size: 26.0,
color: Colors.indigoAccent,
)
: Icon(
Icons.check_box_outline_blank,
size: 26.0,
color: Colors.tealAccent,
),
),
),
),
title: Text(
todo.description,
style: TextStyle(
fontSize: 16.5,
fontFamily: 'RobotoMono',
fontWeight: FontWeight.w500,
decoration: todo.isDone
? TextDecoration.lineThrough
: TextDecoration.none),
),
)),
);
return dismissibleCard;
},
)
: Container(
child: Center(
//this is used whenever there 0 Todo
//in the data base
child: noTodoMessageWidget(),
));
} else {
return Center(
child: loadingData(),
);
}
}
Widget loadingData() {
todoBloc.getTodos();
return Container(
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Text("Loading...",
style: TextStyle(fontSize: 19, fontWeight: FontWeight.w500))
],
),
),
);
}
Widget noTodoMessageWidget() {
return Container(
child: Text(
"Start adding Todo...",
style: TextStyle(fontSize: 19, fontWeight: FontWeight.w500),
),
);
}
dispose() {
todoBloc.dispose();
}
}
repository page todo_repository.dart
import 'package:zencartos/models/todo.dart';
class TodoRepository {
final todoDao = TodoDao();
Future getAllTodos({String query}) => todoDao.getTodos(query: query);
Future insertTodo(Todo todo) => todoDao.createTodo(todo);
Future updateTodo(Todo todo) => todoDao.updateTodo(todo);
Future deleteTodoById(int id) => todoDao.deleteTodo(id);
//We are not going to use this in the demo
//Future deleteAllTodos() => todoDao.deleteAllTodos();
}
In your todo_bloc.dart, your delete method should be:
deleteTodoById(int id) async {
await _todoRepository.deleteTodoById(id);
getTodos();
}

Resources