How to take the datas from firebase in order? - android

I am currently developing chat app, the problem is I can not take the datas from firebase, on the chat screen nothing shown as a chat, To sort my datas on firebase to take them to my chat screen like a real chat app, I used orderBy('createAt', descending: true).snapshots() property, It sort my datas on firebase according time, but before I used this parameter I could see the messages but now I can, Thanks for your answers, Have a nice day..
import 'package:flutter/material.dart';
import'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:naber/constants.dart';
final _firestore=FirebaseFirestore.instance;
User loggedInUser;
class ChatScreen extends StatefulWidget {
static String id="chat_screen";
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final messageTextController = TextEditingController();
final _auth = FirebaseAuth.instance;
String messageText;
void initState(){
super.initState();
getCurrentUser();
}
void getCurrentUser()async{
try{
final currentUser = await _auth.currentUser;
if(currentUser!=null){
loggedInUser=currentUser;
}
}
catch(e){
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
MessagesStream(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextController.clear();
_firestore.collection('messages').add({
'text': messageText,
'sender': loggedInUser.email,
'createdAt': FieldValue.serverTimestamp(),
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class MessagesStream extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('messages').
orderBy('createAt', descending: true).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
),
);
}
final messages = snapshot.data.docs.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data()['text'];
final messageSender = message.data()['sender'];
final currentUser = loggedInUser.email;
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10.0, vertical: 20.0),
children: messageBubbles,
),
);
},
);
}
}
class MessageBubble extends StatelessWidget {
MessageBubble({this.sender, this.text, this.isMe});
final String sender;
final String text;
final bool isMe;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
sender,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30.0),
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0))
: BorderRadius.only(
bottomLeft: Radius.circular(30.0),
bottomRight: Radius.circular(30.0),
topRight: Radius.circular(30.0),
),
elevation: 5.0,
color: isMe ? Colors.lightBlueAccent : Colors.white,
child: Padding(
padding: EdgeInsets.symmetric(vertical: 10.0, horizontal: 20.0),
child: Text(
text,
style: TextStyle(
color: isMe ? Colors.white : Colors.black54,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
[![Here is my database screenshot][1]][1]

Related

How to use Streambuilder in flutter

import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
void main() async {
//Run this first
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Smart Bin',
home: new HomePageWidget(),
);
}
}
class HomePageWidget extends StatefulWidget {
const HomePageWidget({Key key}) : super(key: key);
#override
_HomePageWidgetState createState() => _HomePageWidgetState();
}
class _HomePageWidgetState extends State<HomePageWidget> {
final scaffoldKey = GlobalKey<ScaffoldState>();
final currentBinRecord = FirebaseFirestore.instance.collection("current_bin");
#override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
title: Text(
'SmartBin',
),
),
body: SafeArea(
child: GestureDetector(
onTap: () => FocusScope.of(context).unfocus(),
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: StreamBuilder<List<CurrentBinRecord>>(
stream: queryCurrentBinRecord(
queryBuilder: (currentBinRecord) =>
currentBinRecord.orderBy('level', descending: true),
),
builder: (context, snapshot) {
// Customize what your widget looks like when it's loading.
if (!snapshot.hasData) {
return Center(
child: SizedBox(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
}
List<CurrentBinRecord> listViewCurrentBinRecordList =
snapshot.data;
return ListView.builder(
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemCount: listViewCurrentBinRecordList.length,
itemBuilder: (context, listViewIndex) {
final listViewCurrentBinRecord =
listViewCurrentBinRecordList[listViewIndex];
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
listViewCurrentBinRecord.area,
),
Text(
listViewCurrentBinRecord.level.toString(),
),
],
);
},
);
},
),
),
],
),
),
),
);
}
}
This is the error
First error is on:
child: StreamBuilder<List<CurrentBinRecord>>
The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument.
Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.
Second error is on:
stream: queryCurrentBinRecord
The method 'queryCurrentBinRecord' isn't defined for the type '_HomePageWidgetState'.
Try correcting the name to the name of an existing method, or defining a method named 'queryCurrentBinRecord'.
Third error is on:
List<CurrentBinRecord> listViewCurrentBinRecordList =
snapshot.data;
The name 'CurrentBinRecord' isn't a type so it can't be used as a type argument.
Try correcting the name to an existing type, or defining a type named 'CurrentBinRecord'.
These is the syntax try -
return StreamBuilder(
stream: theStreamSource, // Eg a firebase query
builder: (context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, int index) {
return Text(snapshot.data.documents[index]['title']);
}
);
},
);
Hope it helps.
I think the best way to use StreamBuilder is to create separate controller class that can handle all your business logic and update UI.
// your widget class
class UIClass extends StatefulWidget {
const UIClass({Key key}) : super(key: key);
#override
_UIClassState createState() => _UIClassState();
}
class _UIClassState extends State<UIClass> {
UIClassController<List<CurrentBinRecord>> _uiController;
#override
void initState() {
_uiController = UIClassController(StreamController<List<CurrentBinRecord>>());
super.initState();
}
#override
Widget build(BuildContext context) {
return Column(
children: [
Text("Hello Everyone"),
StreamBuilder<List<CurrentBinRecord>>(
stream: _uiController.uiStream,
builder: (context, snapshot) {
if(snapshot.hasError){
return ErrorWidget();
}
else if(snapshot.connectionState == ConnectionState.waiting){
return WaitingWidget();
}
else if(snapshot.hasData){
return ListView.builder(
padding: EdgeInsets.zero,
scrollDirection: Axis.vertical,
itemCount: snapshot.data.length,
itemBuilder: (context, listViewIndex) {
final listViewCurrentBinRecord =
snapshot.data[listViewIndex];
return Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(
listViewCurrentBinRecord.area,
),
Text(
listViewCurrentBinRecord.level.toString(),
),
],
);
},
);
}
else{
return SizedBox();
}
}
),
],
);
}
#override
void dispose() {
super.dispose();
_uiController.dispose();
}
}
// controller class to handle all business logic
// you can also split it into multiple sub controllers
class UIClassController<T> {
final StreamController<T> _controller;
// If you are using this on multiple widgets then use asBroadcastStream()
Stream<T> get uiStream => _controller.stream;
UIClassController(this._controller);
void updateMyUI([dynamic params]){
T t;
// your logic //
//------------//
_controller.sink.add(t);
}
void dispose(){
_controller.close();
}
}
Code I'm Using for StreamBuilder
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import '../door/widgets/Navbar.dart';
import '../door/widgets/sidenav.dart';
import 'package:get/get.dart';
FirebaseAuth auth = FirebaseAuth.instance;
class CartPage extends StatefulWidget {
#override
_CartPageState createState() => _CartPageState();
}
class _CartPageState extends State<CartPage> {
final FirebaseFirestore fb = FirebaseFirestore.instance;
int up = 1;
bool loading = false;
final ScrollController _scrollController = ScrollController();
#override
void initState() {
super.initState();
getCartData();
}
void addMore(qty, documentID) {
int new_qty = qty + 1;
Get.snackbar('Qty! ', new_qty.toString());
String collection_name = "cart_${auth.currentUser?.email}";
FirebaseFirestore.instance
.collection(collection_name)
.doc(documentID)
.update({
'qty': new_qty,
'updated_at': Timestamp.now(),
}) // <-- Your data
.then((_) => print('Added'))
.catchError((error) => Get.snackbar('Failed!', 'Error: $error'));
}
void minusMore(qty, documentID) {
if (qty > 1) {
int new_qty = qty - 1;
String collection_name = "cart_${auth.currentUser?.email}";
FirebaseFirestore.instance
.collection(collection_name)
.doc(documentID)
.update({
'qty': new_qty,
'updated_at': Timestamp.now(),
}) // <-- Your data
.then((_) => print('Subtracted'))
.catchError((error) => Get.snackbar('Failed!', 'Error: $error'));
}
}
Stream<QuerySnapshot> getCartData() {
String collection_name = "cart_${auth.currentUser?.email}";
return FirebaseFirestore.instance
.collection(collection_name)
.orderBy("created_at", descending: false)
.snapshots();
}
final ButtonStyle style = ElevatedButton.styleFrom(
minimumSize: Size(50, 30),
backgroundColor: Color(0xFFFFB61A),
elevation: 6,
textStyle: const TextStyle(fontSize: 11),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(20),
)));
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: Navbar.navbar(),
drawer: Sidenav.sidenav(),
body: Container(
padding: EdgeInsets.all(10.0),
child: StreamBuilder<QuerySnapshot>(
stream: getCartData(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
default:
if (snapshot.hasError) {
return buildText('Something Went Wrong Try later');
} else {
if (!snapshot.hasData) {
return Card(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTile(
leading: ConstrainedBox(
constraints: const BoxConstraints(
minWidth: 100,
minHeight: 190,
maxWidth: 200,
maxHeight: 200,
),
child: Icon(Icons.shopping_cart, size: 45),
),
title: Text('No Food!'),
subtitle: const Text('Your cart is empty!'),
),
],
),
);
} else {
return ListView.builder(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: snapshot.data?.docs.length,
itemBuilder: (BuildContext context, int index) {
return SizedBox(
height: 90.0,
child: Card(
elevation: 10,
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
const SizedBox(
width: 20,
),
_buildImg('assets/logo.png', '60', '60'),
const SizedBox(
width: 14,
),
SizedBox(
width:
MediaQuery.of(context).size.width *
0.33,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment:
CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(
height: 20,
),
Text(
snapshot.data?.docs[index]
["name"],
maxLines: 2,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14)),
const SizedBox(
height: 5,
),
Text(
"₹${snapshot.data?.docs[index]["price"]}",
style: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 12)),
],
),
),
const SizedBox(
width: 10,
),
Container(
margin: const EdgeInsets.only(
top: 20.0, bottom: 10.0),
decoration: BoxDecoration(
color: const Color(0xFFFFB61A),
// color: Color(0xFF0A2031),
borderRadius:
BorderRadius.circular(17)),
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
crossAxisAlignment:
CrossAxisAlignment.end,
children: <Widget>[
SizedBox(
height: 40,
child: IconButton(
onPressed: () {
minusMore(
snapshot.data
?.docs[index]
["qty"],
snapshot
.data
?.docs[index]
.reference
.id);
},
color: Colors.white,
icon:
const Icon(Icons.remove)),
),
const SizedBox(
width: 5,
),
Container(
margin: const EdgeInsets.only(
bottom: 10.0),
child: Text(
"${snapshot.data?.docs[index]["qty"]}",
style: const TextStyle(
fontWeight:
FontWeight.w400,
color: Colors.white,
fontSize: 16)),
),
const SizedBox(
width: 5,
),
SizedBox(
height: 40,
child: IconButton(
color: Colors.white,
onPressed: () {
addMore(
snapshot.data
?.docs[index]
["qty"],
snapshot
.data
?.docs[index]
.reference
.id);
},
icon: const Icon(Icons.add)),
),
],
),
),
const SizedBox(
width: 10,
),
],
),
),
);
});
}
}
}
},
),
),
);
}
Widget buildText(String text) => Center(
child: Text(
text,
style: TextStyle(fontSize: 24, color: Colors.black),
),
);
_buildImg(img, hei, wid) {
return Container(
alignment: Alignment.center, // use aligment
child: Image.asset(
img,
height: double.parse(hei),
width: double.parse(wid),
fit: BoxFit.cover,
),
);
}
}

How to pass method into another class in flutter

I tried to create a task app using flutter, So I created a text field in DialogBox and my aim is when I add some text into the text field and when I clicked the OK button, I need to show that text in the list. but I have no idea how to call a method in another class, I've added my two classes.
ListTask Class
import 'package:flutter/material.dart';
class ListTask extends StatefulWidget {
const ListTask({Key? key}) : super(key: key);
#override
State<ListTask> createState() => _ListTaskState();
}
class _ListTaskState extends State<ListTask> {
final List<String> tasks = ['masu', 'adasf', 'wfqf', 'santha'];
final TextEditingController _textFieldController = TextEditingController();
void addItemToList() {
setState(() {
tasks.insert(0, _textFieldController.text);
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 320,
width: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.only(bottom: 10),
itemCount: tasks.length,
itemBuilder: (context, index) {
return Card(
elevation: 1,
color: Colors.grey[200],
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ExpansionTile(title: Text(tasks[index]), children: <Widget>[
ListTile(
title: Text(tasks[index]),
)
]),
],
),
);
},
),
);
}
Future<void> _displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('TextField in Dialog'),
content: TextField(
onChanged: (value) {
setState(() {
// valueText = value;
});
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "Text Field in Dialog"),
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
addItemToList();
Navigator.pop(context);
});
},
),
],
);
});
}
}
TaskApp Class
import 'package:flutter/material.dart';
import 'package:task_app/Widgets/listtasks.dart';
import 'package:task_app/Widgets/logo.dart';
import 'package:task_app/Widgets/searchbar.dart';
class TaskApp extends StatefulWidget {
const TaskApp({Key? key}) : super(key: key);
#override
State<TaskApp> createState() => _TaskAppState();
}
class _TaskAppState extends State<TaskApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
Logo(),
SizedBox(height: 0),
SearchBar(),
SizedBox(height: 15),
Column(
children: [
Text(
'All tasks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
)
],
),
SizedBox(height: 15),
ListTask(),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
_displayTextInputDialog(context);
},
label: const Text('Add Task'),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue[900],
),
);
}
}
Calling point of that method in TaskApp Class:
Method:
You can give this a try, it will call a method defined in ListTask(StatefulWidget) from TaskApp(StatefulWidget) widget.
TaskApp.dart
import 'package:flutter/material.dart';
import 'package:vcare/Screens/tetxing1.dart';
class TaskApp extends StatefulWidget {
final ListTask listTask;
const TaskApp({Key? key,required this.listTask}) : super(key: key);
#override
State<TaskApp> createState() => _TaskAppState();
}
class _TaskAppState extends State<TaskApp> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(15.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(height: 10),
// Logo(),
SizedBox(height: 0),
//SearchBar(),
SizedBox(height: 15),
Column(
children: [
Text(
'All tasks',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
)
],
),
SizedBox(height: 15),
ListTask(),
],
),
),
floatingActionButton: FloatingActionButton.extended(
onPressed: () {
ListTask().method1(context);
},
label: const Text('Add Task'),
icon: const Icon(Icons.add),
backgroundColor: Colors.blue[900],
),
);
}
}
ListTask.dart
import 'package:flutter/material.dart';
class ListTask extends StatefulWidget {
method1(context) => createState().displayTextInputDialog(context);
#override
_ListTaskState createState() => _ListTaskState();
}
class _ListTaskState extends State<ListTask> {
final List<String> tasks = ['masu', 'adasf', 'wfqf', 'santha'];
final TextEditingController _textFieldController = TextEditingController();
void addItemToList() {
setState(() {
tasks.insert(0, _textFieldController.text);
});
}
#override
Widget build(BuildContext context) {
return Container(
height: 320,
width: double.maxFinite,
child: ListView.builder(
padding: EdgeInsets.only(bottom: 10),
itemCount: tasks.length,
itemBuilder: (context, index) {
return Card(
elevation: 1,
color: Colors.grey[200],
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ExpansionTile(title: Text(tasks[index]), children: <Widget>[
ListTile(
title: Text(tasks[index]),
)
]),
],
),
);
},
),
);
}
Future<void> displayTextInputDialog(BuildContext context) async {
return showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: Text('TextField in Dialog'),
content: TextField(
onChanged: (value) {
setState(() {
// valueText = value;
});
},
controller: _textFieldController,
decoration: InputDecoration(hintText: "Text Field in Dialog"),
),
actions: <Widget>[
FlatButton(
color: Colors.red,
textColor: Colors.white,
child: Text('CANCEL'),
onPressed: () {
setState(() {
Navigator.pop(context);
});
},
),
FlatButton(
color: Colors.green,
textColor: Colors.white,
child: Text('OK'),
onPressed: () {
setState(() {
addItemToList();
Navigator.pop(context);
});
},
),
],
);
});
}
}
if you find this solution helpful please mark as accepted answer

Navigate to a new screen without leaving parent screen

I am completely new to Flutter and I have this screen that uses bottomSheet and I want to go to a new screen when I click on a project, while staying inside this parent screen that has the bottomSheet in it. Here is the source code for the parent screen and the Projects screen inside it.
Parent Main Menu screen
import 'package:flutter/material.dart';
import 'projects.dart';
import 'app-bar.dart';
class MainMenu extends StatefulWidget {
#override
_MainMenuState createState() => _MainMenuState();
}
class _MainMenuState extends State<MainMenu> {
final GlobalKey<ScaffoldState> _scaffoldKey = new GlobalKey<ScaffoldState>();
int _selectedIndex = 0;
static List<TabItem> _widgetOptions = <TabItem>[
TabItem(
text: new Text('Projects'),
className: Projects(),
),
TabItem(
text: new Text('Organization'),
className: null,
),
TabItem(
text: new Text('Profile'),
className: null,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: SafeArea(
child: new DefaultTabController(
length: 3,
child: new Scaffold(
key: _scaffoldKey,
appBar: appBar(_widgetOptions.elementAt(_selectedIndex).text),
body: _widgetOptions.elementAt(_selectedIndex).className,
bottomNavigationBar: BottomNavigationBar(
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.view_column),
label: 'Projects'
),
BottomNavigationBarItem(
icon: Icon(Icons.people),
label: 'Organization'
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'Profile'
)
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
),
)
),
);
}
}
class TabItem {
Widget text;
dynamic className;
TabItem({ #required this.text, #required this.className });
}
Projects
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:pmtool/project-page.dart';
import './interfaces/iprojects.dart';
import './constants/route-names.dart';
class Projects extends StatefulWidget {
#override
_ProjectsState createState() => _ProjectsState();
}
class _ProjectsState extends State<Projects> {
final GlobalKey<ScaffoldState> _scaffoldState = new GlobalKey<ScaffoldState>();
static const List<Text> sortOptions = [
Text('Project Name'),
Text('Project Number'),
Text('Client Name'),
Text('Percent Completed'),
Text('Date Added'),
Text('Project Type'),
];
static const List<String> sortOrder = [
'Descending',
'Ascending',
];
static const List<String> filters = [
'Ongoing',
'All',
'Completed',
];
List<bool> isSelected = [
true, false, false, false, false, false,
];
String selectedSort = 'Descending';
static List<ProjectsMock> projects = [
ProjectsMock(projectId: '1', projectNumber: '1', projectName: 'Project 1', clientName: 'asd', projectStatus: 'Ongoing'),
ProjectsMock(projectId: '2', projectNumber: '2', projectName: 'Project 2', clientName: 'qwe', projectStatus: 'Completed'),
];
String selectedFilter = 'Ongoing';
void selectItem(int index) {
setState(() {
for (int i = 0; i < isSelected.length; i++) {
if (i != index) {
isSelected[i] = false;
return;
}
isSelected[i] = true;
}
});
}
void navigateToProject(BuildContext context, ProjectsMock project) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProjectPage(),
settings: RouteSettings(
arguments: project,
)
)
);
}
void setBottomSheet(context) {
showModalBottomSheet(
context: context,
builder: (BuildContext buildContext) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text('Filters', style: TextStyle(fontWeight: FontWeight.bold),),
new Wrap(
spacing: 5.0,
children: List.generate(filters.length, (index) {
if (selectedFilter == filters.elementAt(index)) {
return new ActionChip(
label: new Text(filters.elementAt(index)),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
onPressed: () {
return;
},
);
}
return new ActionChip(
label: new Text(filters.elementAt(index)),
backgroundColor: Colors.white,
labelStyle: TextStyle(color: Colors.blue),
onPressed: () {
return;
},
);
}),
),
new Text('Sort by', style: TextStyle(fontWeight: FontWeight.bold),),
new Wrap(
spacing: 5.0,
children: List.generate(sortOptions.length, (index) {
if (isSelected[index]) {
return new ActionChip(
label: sortOptions.elementAt(index),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
onPressed: () {
return;
},
);
}
return new ActionChip(
label: sortOptions.elementAt(index),
backgroundColor: Colors.white,
labelStyle: TextStyle(color: Colors.blue),
onPressed: () {
return;
},
);
}),
),
new Container(
margin: const EdgeInsets.only(top: 10.0),
child: new Text('Sort Order', style: TextStyle(fontWeight: FontWeight.bold),),
),
new Wrap(
spacing: 5.0,
children: List.generate(sortOrder.length, (index) {
if (selectedSort == sortOrder[index]) {
return new ActionChip(
label: Text(sortOrder.elementAt(index)),
backgroundColor: Colors.blue,
labelStyle: TextStyle(color: Colors.white),
onPressed: () {
return;
},
);
}
return new ActionChip(
label: Text(sortOrder.elementAt(index)),
backgroundColor: Colors.white,
labelStyle: TextStyle(color: Colors.blue),
onPressed: () {
return;
},
);
}),
),
],
),
);
}
);
}
#override
Widget build(BuildContext context) {
return new Scaffold(
floatingActionButton: new FloatingActionButton(child: new Icon(Icons.filter_alt), onPressed: () => setBottomSheet(context), mini: true),
key: _scaffoldState,
body: new Column(
children: <Widget>[
new Expanded(
child: new Column(
children: <Widget>[
// Search header
new Container(
padding: const EdgeInsets.all(10.0),
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Expanded(
child: new TextField(
decoration: new InputDecoration(
hintText: 'Search',
labelText: 'Search',
suffixIcon: new IconButton(icon: Icon(Icons.search), onPressed: () {
return;
}),
contentPadding: const EdgeInsets.only(left: 5.0, right: 5.0)
),
)
),
],
),
],
),
),
new Padding(
padding: const EdgeInsets.only(left: 10.0, right: 10.0),
child: new Column(
children: List.generate(projects.length, (index) {
return new Container(
margin: const EdgeInsets.only(bottom: 10.0),
child: new RaisedButton(
onPressed: () => navigateToProject(context, projects.elementAt(index)),
color: Colors.white,
textColor: Colors.black,
child: new Padding(
padding: const EdgeInsets.all(10.0),
child: new Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Expanded(
child: new Column(
children: <Widget>[
new Text(projects.elementAt(index)?.projectName, style: TextStyle(fontWeight: FontWeight.bold)),
new Text(projects.elementAt(index)?.projectNumber),
]
),
),
new Expanded(
child: new Column(
children: <Widget>[
new Text(projects.elementAt(index)?.clientName, style: TextStyle(fontWeight: FontWeight.bold)),
new Text(projects.elementAt(index)?.projectStatus),
]
),
)
],
),
),
),
);
}),
),
)
],
),
)
],
),
);
}
}
Here is a snapshot of the page.
How do I do it? I tried using Navigator but it goes to a completely new screen. Let me know if you need more information.
You create another inside your main.dart file and use Navigator to move to that screen without actually moving to another screen instead replacing the current one
this is how the code goes
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DisplayPictureScreen(string1: string),//passing a parameter
),
);
and this how the class goes
class DisplayPictureScreen extends StatelessWidget {
final String string1;
const DisplayPictureScreen({Key key, this.string1}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(value[0]["label"],style: TextStyle(color: Colors.black,fontSize: 20),
)),
body: Column(
children: [
Text("lsfnklsnlvfdngvlirs")
],
),
);
}
}

StreamBuilder builds snapshot twice for every one update

I'm trying to build a chat application which displays time along with the message. Here is the main code:
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final _fireStore = Firestore.instance;
FirebaseUser loggedInUser;
class ChatScreen extends StatefulWidget {
static String chatScreen = 'ChatScreenpage1';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final messageTextEditingController = TextEditingController();
String messageText;
final _auth = FirebaseAuth.instance;
#override
void initState() {
super.initState();
getUserDetail();
}
void getUserDetail() async {
try {
final createdUser = await _auth.currentUser();
if (createdUser != null) {
loggedInUser = createdUser;
}
} catch (e) {
print(e);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
_auth.signOut();
Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreambuilderClass(),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: messageTextEditingController,
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
messageTextEditingController.clear();
_fireStore.collection('messages').add({
'sender': loggedInUser.email,
'text': messageText,
'time': FieldValue.serverTimestamp()
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class StreambuilderClass extends StatelessWidget {
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _fireStore
.collection('messages')
.orderBy('time', descending: false)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.blueAccent,
),
);
}
final messages = snapshot.data.documents.reversed;
List<MessageBubble> messageBubbles = [];
for (var message in messages) {
final messageText = message.data['text'];
final messageSender = message.data['sender'];
final messageTime = message.data['time'] as Timestamp;
final currentUser = loggedInUser.email;
print('check time: $messageTime'); //print(message.data['time']); both gives null
print('check sender: $messageSender');
print('check sender: $messageText');
print(snapshot.connectionState);
final messageBubble = MessageBubble(
sender: messageSender,
text: messageText,
isMe: currentUser == messageSender,
time: messageTime,
);
messageBubbles.add(messageBubble);
}
return Expanded(
child: ListView(
reverse: true,
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 20),
children: messageBubbles),
);
});
}
}
class MessageBubble extends StatelessWidget {
final String text;
final String sender;
final bool isMe;
final Timestamp time;
MessageBubble({this.text, this.sender, this.isMe, this.time});
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment:
isMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
children: <Widget>[
Text(
' $sender ${DateTime.fromMillisecondsSinceEpoch(time.seconds * 1000)}',
style: TextStyle(color: Colors.black54, fontSize: 12),
),
Material(
color: isMe ? Colors.blueAccent : Colors.white,
borderRadius: isMe
? BorderRadius.only(
topLeft: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30))
: BorderRadius.only(
topRight: Radius.circular(30),
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30)),
elevation: 6,
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15),
child: Text(
text,
style: TextStyle(
fontSize: 20, color: isMe ? Colors.white : Colors.black),
),
),
),
],
),
);
}
}
But I get this exception for a moment(almost a second) with a red screen and then everything works fine:
By printing the snapshot data field values(The highlighted code in the image) for like 100 times with 100 messages, I realized that the StreamBuilder is sending updated snapshot twice.
(You can see in the output that the first snapshot is with just time field being null and immediately in the second snapshot all values are being present, this happens for every new message I send.)
Everything works as expected in my other app which doesn't use timestamp field in cloud firestore.
My question is shouldn't the StreamBuilder should just send one snapshot for every one update with all the data values being present at once?
Please tell me if I've made a mistake. Any help would be really appreciated!
This is actually expected behaviour for a StreamBuilder. As you can see in this Community Answer:
StreamBuilder makes two build calls when initialized, once for the
initial data and a second time for the stream data.
Streams do not guarantee that they will send data right away so an
initial data value is required. Passing null to initialData throws an
InvalidArgument exception.
StreamBuilders will always build twice even when the stream passed is
null.
So, in order to mitigate that exception and red screen glitch, you will have to take this into consideration and treat this scenario in your code.

MyAppState is not displaying anything

import 'dart:async';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:image_gallery_saver/image_gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
import 'package:qrscan/qrscan.dart' as scanner;
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Uint8List bytes = Uint8List(0);
TextEditingController _inputController;
TextEditingController _outputController;
#override
initState() {
super.initState();
this._inputController = new TextEditingController();
this._outputController = new TextEditingController();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.grey[300],
body: Builder(
builder: (BuildContext context) {
return ListView(
children: <Widget>[
_qrCodeWidget(this.bytes, context),
Container(
color: Colors.white,
child: Column(
children: <Widget>[
TextField(
controller: this._inputController,
keyboardType: TextInputType.url,
textInputAction: TextInputAction.go,
onSubmitted: (value) => _generateBarCode(value),
decoration: InputDecoration(
prefixIcon: Icon(Icons.text_fields),
helperText: 'Please input your code to generage qrcode image.',
hintText: 'Please Input Your Code',
hintStyle: TextStyle(fontSize: 15),
contentPadding: EdgeInsets.symmetric(
horizontal: 7, vertical: 15),
),
),
SizedBox(height: 20),
TextField(
controller: this._outputController,
maxLines: 2,
decoration: InputDecoration(
prefixIcon: Icon(Icons.wrap_text),
helperText: 'The barcode or qrcode you scan will be displayed in this area.',
hintText: 'The barcode or qrcode you scan will be displayed in this area.',
hintStyle: TextStyle(fontSize: 15),
contentPadding: EdgeInsets.symmetric(
horizontal: 7, vertical: 15),
),
),
SizedBox(height: 20),
this._buttonGroup(),
SizedBox(height: 70),
],
),
),
],
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => _scanBytes(),
tooltip: 'Take a Photo',
child: const Icon(Icons.camera_alt),
),
),
);
}
Widget _qrCodeWidget(Uint8List bytes, BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
child: Card(
elevation: 6,
child: Column(
children: <Widget>[
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Icon(Icons.verified_user, size: 18, color: Colors.green),
Text(' Generate Qrcode', style: TextStyle(fontSize: 15)),
Spacer(),
Icon(Icons.more_vert, size: 18, color: Colors.black54),
],
),
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 9),
decoration: BoxDecoration(
color: Colors.black12,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(4), topRight: Radius.circular(4)),
),
),
Padding(
padding: EdgeInsets.only(
left: 40, right: 40, top: 30, bottom: 10),
child: Column(
children: <Widget>[
SizedBox(
height: 190,
child: bytes.isEmpty
? Center(
child: Text('Empty code ... ',
style: TextStyle(color: Colors.black38)),
)
: Image.memory(bytes),
),
Padding(
padding: EdgeInsets.only(top: 7, left: 25, right: 25),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Expanded(
flex: 5,
child: GestureDetector(
child: Text(
'remove',
style: TextStyle(
fontSize: 15, color: Colors.blue),
textAlign: TextAlign.left,
),
onTap: () =>
this.setState(() => this.bytes = Uint8List(0)),
),
),
Text('|', style: TextStyle(fontSize: 15, color: Colors
.black26)),
Expanded(
flex: 5,
child: GestureDetector(
onTap: () async {
final success = await ImageGallerySaver.saveImage(
this.bytes);
SnackBar snackBar;
if (success) {
snackBar = new SnackBar(content: new Text(
'Successful Preservation!'));
Scaffold.of(context).showSnackBar(snackBar);
} else {
snackBar =
new SnackBar(content: new Text('Save failed!'));
}
},
child: Text(
'save',
style: TextStyle(
fontSize: 15, color: Colors.blue),
textAlign: TextAlign.right,
),
),
),
],
),
)
],
),
),
Divider(height: 2, color: Colors.black26),
],
),
),
);
}
Widget _buttonGroup() {
return Row(
children: <Widget>[
Expanded(
flex: 1,
child: SizedBox(
height: 120,
child: InkWell(
onTap: () => _generateBarCode(this._inputController.text),
child: Card(
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Image.asset('images/generate_qrcode.png'),
),
Divider(height: 20),
Expanded(flex: 1, child: Text("Generate")),
],
),
),
),
),
),
Expanded(
flex: 1,
child: SizedBox(
height: 120,
child: InkWell(
onTap: _scan,
child: Card(
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Image.asset('images/scanner.png'),
),
Divider(height: 20),
Expanded(flex: 1, child: Text("Scan")),
],
),
),
),
),
),
Expanded(
flex: 1,
child: SizedBox(
height: 120,
child: InkWell(
onTap: _scanPhoto,
child: Card(
child: Column(
children: <Widget>[
Expanded(
flex: 2,
child: Image.asset('images/albums.png'),
),
Divider(height: 20),
Expanded(flex: 1, child: Text("Scan Photo")),
],
),
),
),
),
),
],
);
}
Future _scan() async {
String barcode = await scanner.scan();
if (barcode == null) {
print('nothing return.');
} else {
this._outputController.text = barcode;
}
}
Future _scanPhoto() async {
String barcode = await scanner.scanPhoto();
this._outputController.text = barcode;
}
Future _scanPath(String path) async {
String barcode = await scanner.scanPath(path);
this._outputController.text = barcode;
}
Future _scanBytes() async {
File file = await ImagePicker.pickImage(source: ImageSource.camera);
Uint8List bytes = file.readAsBytesSync();
String barcode = await scanner.scanBytes(bytes);
this._outputController.text = barcode;
}
Future _generateBarCode(String inputCode) async {
Uint8List result = await scanner.generateBarCode(inputCode);
this.setState(() => this.bytes = result);
}
}
class MyAppState extends State<MyApp> {
Future<SharedPreferences> _sPrefs = SharedPreferences.getInstance();
final TextEditingController controller = TextEditingController();
List<String> listOne, listTwo;
#override
void initState() {
super.initState();
listOne = [];
listTwo = [];
}
Future<Null> addString() async {
final SharedPreferences prefs = await _sPrefs;
listOne.add(controller.text);
prefs.setStringList('list', listOne);
setState(() {
controller.text = '';
});
}
Future<Null> clearItems() async {
final SharedPreferences prefs = await _sPrefs;
prefs.clear();
setState(() {
listOne = [];
listTwo = [];
});
}
Future<Null> getStrings() async {
final SharedPreferences prefs = await _sPrefs;
listTwo = prefs.getStringList('list');
setState(() {});
}
Future<Null> updateStrings(String str) async {
final SharedPreferences prefs = await _sPrefs;
setState(() {
listOne.remove(str);
listTwo.remove(str);
});
prefs.setStringList('list', listOne);
}
#override
Widget build(BuildContext context) {
getStrings();
return Center(
child: ListView(
children: <Widget>[
TextField(
controller: controller,
decoration: InputDecoration(
hintText: 'Type in something...',
)),
RaisedButton(
child: Text("Submit"),
onPressed: () {
addString();
},
),
RaisedButton(
child: Text("Clear"),
onPressed: () {
clearItems();
},
),
Flex(
direction: Axis.vertical,
children: listTwo == null
? []
: listTwo
.map((String s) => Dismissible(
key: Key(s),
onDismissed: (direction) {
updateStrings(s);
},
child: ListTile(
title: Text(s),
)))
.toList(),
)
],
),
);
}
}
Here the first Appstate creates a Qr code reader. Second is for creating an input controller with shared preferences that can store and retrieve data locally. But when running the code the app displays only the qrscan part and 2nd is not working. I'm new to Flutter. I've just started working on Android Studio. Can anybody help please?
Try to call Another class from home property of the MyApp class.
As you can see in this image
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
//Here I have called MyWidget Class
home: MyWidget()
);
}
}
class MyWidget extends StatefulWidget {
#override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
Uint8List bytes = Uint8List(0);
TextEditingController _inputController;
TextEditingController _outputController;
#override
initState() {
super.initState();
this._inputController = new TextEditingController();
this._outputController = new TextEditingController();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(

Categories

Resources