Related
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(),
],
),
///
),
),
);
}```
I am fetching certain details from firebase and showing them in the form of card, with the help of ListView.Builder. Now, upon tapping a specific card I want to change its border colour to green. I have tried using the flag variable in the setState but it sets the border colour for every card to green. Someone pls have a look at the code I've pasted, and let me know what should be done.This is the image of the UI
Thank You:)
StreamBuilder<QuerySnapshot>(
stream: collectionTests.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
final myDocs = snapshot.data!.docs;
try {
return ListView.builder(
itemCount: myDocs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.fromLTRB(17, 11, 17, 11),
child: InkWell(
onTap: () {},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
side: const BorderSide(
color: Colors.white,
),
),
child: ListTile(
contentPadding: const EdgeInsets.all(8),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
myDocs[index]['name'],
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
Card(
color: Colors.indigo,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
myDocs[index]['price'],
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.italic,
fontSize: 20,
),
),
),
)
],
),
subtitle: Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 12, 8),
child: Text(
myDocs[index]['description'],
style: const TextStyle(
fontSize: 18,
),
),
),
),
),
),
);
},
);
} catch (e) {
return const Center(
child: Card(
child: Text(
'Something went wrong, please check your connection',
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
);
}
}
},
),
Extract your widget into a new stateful class and call the class inside the ListView.
main.dart
import 'package:flutter/material.dart';
import 'package:stackoverflow/custom_card.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView.builder(
itemCount: 5,
itemBuilder: (context, i){
return CustomCard();
},
),
),
);
}
}
custom_card.dart
import 'package:flutter/material.dart';
class CustomCard extends StatefulWidget {
const CustomCard({Key? key}) : super(key: key);
#override
_CustomCardState createState() => _CustomCardState();
}
class _CustomCardState extends State<CustomCard> {
Color borderColor = Colors.black;
#override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: 100,
child: GestureDetector(
onTap: (){
setState(() {
borderColor = Colors.green;
});
},
child: Card(
color: borderColor,
),
),
);
}
}
Firstly, you need to define a list that contains bool variables out of build method. These variables will decide whether the border of relevant card is white or green.
List<bool> bordersColors = [];
Then in your listview like this;
return ListView.builder(
itemCount: myDocs.length,
itemBuilder: (context, index) {
bordersColors.add(false);
return Padding(
padding: const EdgeInsets.fromLTRB(17, 11, 17, 11),
child: InkWell(
onTap: () {
setState((){
bordersColors[index] = true;
})
},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
side: const BorderSide(
color: bordersColors[index] ? Colors.green : Colors.white,
),
),
child: ListTile(
contentPadding: const EdgeInsets.all(8),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
myDocs[index]['name'],
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
Card(
color: Colors.indigo,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
myDocs[index]['price'],
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.italic,
fontSize: 20,
),
),
),
)
],
),
subtitle: Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 12, 8),
child: Text(
myDocs[index]['description'],
style: const TextStyle(
fontSize: 18,
),
),
),
),
),
),
);
},
);
} catch (e) {
return const Center(
child: Card(
child: Text(
'Something went wrong, please check your connection',
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
);
I want to Display logged user's username. I am using the firebase realTime database, not the cloud firestore.
I am looking at different methods like Stream Builder, Datasnap shot. Anything that works is welcomed
HERE IS MY CODE:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../services/auth.dart';
import 'home.dart';
import 'settings.dart';
import 'package:shadow_app_project/data_models/user_profile_browse.dart';
import 'package:shadow_app_project/image_selection/user_edit_image.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
class SettingsUI extends StatelessWidget {
const SettingsUI({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: "Setting UI",
home: EditProfilePage(),
);
}
}
class EditProfilePage extends StatefulWidget {
const EditProfilePage({Key? key}) : super(key: key);
#override
_EditProfilePageState createState() => _EditProfilePageState();
}
class _EditProfilePageState extends State<EditProfilePage> {
TextEditingController displayNameController = TextEditingController();
TextEditingController ageController = TextEditingController();
bool isLoading = false;
User? user;
UserProfileBrowse? userModel;
String? imageUrl;
final refDatabase = FirebaseDatabase.instance;
bool showPassword = false;
final userName = "Name";
final userAge = "age";
String name = FirebaseDatabase.instance.ref().child('userProfileBrowse/${FirebaseAuth.instance.currentUser?.uid}/name').toString();
var usersRef = FirebaseDatabase.instance
.ref()
.child('userProfileBrowse/${FirebaseAuth.instance.currentUser?.uid}');
String currentUserEmail = (Auth().auth.currentUser as User).email.toString();
#override
Widget build(BuildContext context) {
final ref = refDatabase.ref();
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
elevation: 1,
leading: IconButton(
icon: const Icon(
Icons.arrow_back,
color: Colors.green,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => const SettingsPage()));
},
),
actions: [
IconButton(
icon: const Icon(
Icons.settings,
color: Colors.green,
),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => const SettingsPage()));
},
),
],
),
body: StreamBuilder(
stream: usersRef.onValue,
builder: (context, snapshot) {
return Container(
padding: const EdgeInsets.only(left: 16, top: 25, right: 16),
child: GestureDetector(
onTap: () {
FocusScope.of(context).unfocus();
},
child: ListView(
children: [
const Text(
"Edit Profile",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
const SizedBox(
height: 15,
),
Container(
width: 130,
height: 130,
decoration: BoxDecoration(
border: Border.all(
width: 4,
color: Theme.of(context).scaffoldBackgroundColor),
boxShadow: [
BoxShadow(
spreadRadius: 2,
blurRadius: 10,
color: Colors.black.withOpacity(0.1),
offset: const Offset(0, 10))
],
shape: BoxShape.circle,
image: const DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(
"https://images.pexels.com/photos/3307758/pexels-photo-3307758.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=250",
))),
),
const SizedBox(
height: 35,
),
Text(userName,
textAlign: TextAlign.left,
style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
TextFormField(
// initialValue: name,
controller: displayNameController,
keyboardType: TextInputType.name,
),
Text(userAge,
textAlign: TextAlign.left,
style: const TextStyle(fontSize: 25, fontWeight: FontWeight.bold),
),
TextFormField(
// initialValue: ,
controller: ageController,
keyboardType: TextInputType.number,
),
const Padding(
padding: EdgeInsets.all(8.0),
child: Text("Email: ", style: TextStyle(fontSize: 20),),
),
Text(currentUserEmail,
textAlign: TextAlign.left,
style: const TextStyle(fontSize: 15, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 35,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () {},
child: const Text("CANCEL",
style: TextStyle(
fontSize: 14,
letterSpacing: 2.2,
color: Colors.black)),
),
TextButton(
onPressed: () {
ref.child('userProfileBrowse/${FirebaseAuth.instance.currentUser?.uid}/name').set(displayNameController.text);
print("updating name");
ref.child('userProfileBrowse/${FirebaseAuth.instance.currentUser?.uid}/age').set(ageController.text);
print("updating age");
},
child: const Text(
"SAVE",
style: TextStyle(
fontSize: 14,
letterSpacing: 2.2,
color: Colors.white),
),
)
],
)
],
),
),
);
}
),
);
}
}
Should I even stream builder in my code?
I just want to display my logged user's name in my TextFormField initialvalue: name,
please help me, ive been trying a lot of tutorials but i still failed to checked one checkbox with its value in the ListView.builder.
Below is my code that I supposed to add checkbox with its own value. Each card contain the picture and its description, and the user supposely have to select the picture that they need. With that, the image checked should be store in the firebase database.
//import 'dart:html';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:smartconstructionreport/data/project_model.dart';
import 'package:smartconstructionreport/data/user_model.dart';
import 'package:smartconstructionreport/screens/image_details.dart';
import 'package:smartconstructionreport/screens/project_screen.dart';
import 'package:smartconstructionreport/theme.dart';
import 'package:intl/intl.dart';
import 'dart:ui';
import 'dart:io';
class WorkPerformedForm extends StatefulWidget {
final Project project;
final String reportID ;
final int itemIndex;
final String albumid;
const WorkPerformedForm({this.project, #required this.reportID, this.albumid, this.itemIndex});
#override
_WorkPerformedFormState createState() => _WorkPerformedFormState();
}
class _WorkPerformedFormState extends State<WorkPerformedForm> {
FirebaseFirestore _firebaseFirestore = FirebaseFirestore.instance;
User user = FirebaseAuth.instance.currentUser;
UserModel loggedInUser = UserModel();
final Ref = FirebaseFirestore.instance
.collection("images")
.doc('photoid')
.snapshots();
ImageDetails date;
DateTime now = DateTime.now();
#override
void initState() {
super.initState();
FirebaseFirestore.instance
.collection("user")
.doc(user.uid)
.get()
.then((value) {
this.loggedInUser = UserModel.fromMap(value.data());
// name = value.data()['name'];
setState(() {});
//getAlbumID();
});
//checklist.forEach((element) => checkboxStatus.add(false));
}
List<bool> checkboxStatus = [];
bool _checked = false;
#override
Widget build(BuildContext context) {
String _formatteddate = new DateFormat.yMMMd().format(now).toString();
double width = MediaQuery.of(context).size.width * 0.5;
return Scaffold(
appBar: new AppBar(
title: FittedBox(
fit: BoxFit.fill,
child: Text(
'Work Performed',
style: TextStyle(
fontSize: 25,
color: Color(0xFF222B45),
fontFamily: 'Poppins',
fontWeight: FontWeight.w700,
),
),
),
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back_ios, color: kPrimaryColor),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) {
return ProjectScreen(project: widget.project,);
}),
);
},
),
backgroundColor: Colors.transparent,
elevation: 0,
),
body: StreamBuilder<QuerySnapshot>(
stream: _firebaseFirestore
.collection("album")
.doc(widget.albumid)
.collection("images")
.where("photographer", isEqualTo: this.loggedInUser.name)
//.where("dateUploaded", isEqualTo: _formatteddate)
.orderBy('dateUploaded', descending: true)
.snapshots(),
// ignore: missing_return
builder: (BuildContext context, snapshot) {
return snapshot.connectionState == ConnectionState.waiting
? Center(child: CircularProgressIndicator())
: snapshot.hasData
? ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (BuildContext context, index){
return GestureDetector(
onTap: (){
//print(checkboxStatus.length);
print(snapshot.data.docs[index].get('url'));
showDialogFunc(context, snapshot.data.docs[index].get('url'), snapshot.data.docs[index].get('stageOfWork'), snapshot.data.docs[index].get('description'));
},
child: Card(
child: Row(
children: <Widget>[
Container(
width: 100,
height: 100,
child: ImageView(
imagePath: snapshot.data.docs[index].get('url'),
index: index,
photoid: snapshot.data.docs[index].get('photoid'),
albumid: widget.albumid,
project: widget.project),
),
Padding(padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
snapshot.data.docs[index].get('stageOfWork') !=null
?Text(snapshot.data.docs[index].get('stageOfWork'),
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontWeight: FontWeight.bold,
)
): Text(
"None",
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontWeight: FontWeight.bold,
)),
SizedBox( height: 10,),
Container(
width: width,
child: snapshot.data.docs[index].get('description') != null
?Text(
snapshot.data.docs[index].get('description'),
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontStyle: FontStyle.italic,
),
): Text(
"No description yet",
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontStyle: FontStyle.italic,
)),
),
],
),),
Padding(padding: const EdgeInsets.all(10.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Checkbox(
value: _checked,
onChanged: (value) {
print(checkboxStatus.length);
setState((() {
_checked =
!_checked;
}));
},
checkColor: Colors.white,
)
],
),
),
],
),
),
);
})
: Container();
},
),
);
}
}
class ImageView extends StatelessWidget {
final String imagePath;
final int index;
final String photoid;
final String albumid;
final Project project;
ImageView(
{#required this.imagePath,
#required this.index,
#required this.photoid,
#required this.albumid,
#required this.project});
#override
Widget build(BuildContext context) {
return GestureDetector(
child: Hero(
tag: 'logo$index',
child: Image.network(imagePath,
fit: BoxFit.cover,),
),
onTap: () {
});
}
}
showDialogFunc(context,String url, String sow, String decs){
return showDialog(
context:context,
builder: (context){
return Center(
child: Material(
type: MaterialType.transparency,
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white,
),
padding: EdgeInsets.all(15),
width: MediaQuery.of(context).size.width *0.7,
height: 320,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(url,
width: 200,
height: 200,),
),
SizedBox(
height:20
),
sow!=null?
Text(
sow,
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontWeight: FontWeight.bold,
)
):Text(
"None",
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontStyle: FontStyle.italic,
)),
SizedBox(
height:10
),
decs != null?
Text(
decs,
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontStyle: FontStyle.italic,
),
textAlign: TextAlign.center,
): Text(
"No description yet",
maxLines: 3,
style: TextStyle(
fontSize: 15,
fontFamily: 'Poppin',
fontStyle: FontStyle.italic,
)),
],
),
),
),
);
}
);
}
here is the interface
Interface
You need to save the states of each checkbox in similar things like your list.
I would create a Map<String, bool> and update/get the values of each entry. The strings would be the doc ids and the bool the checkbox state concerning the doc id
I'm working on a chat room and I want to enable users send photos in chat. But I don't seem to be getting a hang of it.
I have the image picker widget, but I'm still yet to implement it cos I can't get a hang of it.
Here is the code to the chat screen and a photo as well. I have initialised Firebase properly and everything is working fine, messages are sending, and all. But I want to implement a message send feature into the project.
import 'package:chat/constants.dart';
import 'package:chat/utilities/constants.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:chat/models/auth.dart';
import 'package:chat/models/message.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
class ChatScreen extends StatefulWidget {
final AuthImplementation auth;
final VoidCallback signedOut;
ChatScreen({
this.auth,
this.signedOut,
});
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
final Firestore _firestore = Firestore.instance;
TextEditingController messageController = TextEditingController();
ScrollController scrollController = ScrollController();
String userName;
#override
void initState() {
super.initState();
widget.auth.getCurrentUserEmail().then((email) {
setState(() {
final String userEmail = email;
final endIndex = userEmail.indexOf("#");
userName = userEmail.substring(0, endIndex);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: new Container(
padding: new EdgeInsets.all(8.0),
decoration: new BoxDecoration(
image: new DecorationImage(
image: new AssetImage("assets/images/social-logo.png"),
fit: BoxFit.fill),
color: Colors.white,
borderRadius: new BorderRadius.all(new Radius.circular(80.0)),
border: new Border.all(
color: Colors.white,
width: 1.0,
),
),
),
title: Text("One Gov FX Signal Room",
style: TextStyle(
fontSize: 20,
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'Spartan',
)),
backgroundColor: kPrimaryColor,
actions: <Widget>[
IconButton(
icon: FaIcon(FontAwesomeIcons.signOutAlt),
color: Colors.white,
onPressed: logOut),
],
),
backgroundColor: antiFlashWhite,
body: Column(
children: <Widget>[
Container(
color: Colors.white,
padding: EdgeInsets.only(left: 10, right: 0, bottom: 10, top: 10),
child: Row(
children: [
CircleAvatar(
backgroundColor: Colors.white,
backgroundImage: AssetImage("assets/images/social-logo.png"),
),
SizedBox(
width: 50,
),
Flexible(
child: Column(children: const <Widget>[
Text('Message From the Admins'),
Text(
'Keep your messages polite and do not abuse the channel. Try to keep your discussions within the community guidelines'),
]),
)
],
),
),
Expanded(
child: Container(
//margin: EdgeInsets.symmetric(horizontal: 5),
child: StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection("messages")
.orderBy(
"timestamp",
)
.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Center(
child: CircularProgressIndicator(
backgroundColor: kPrimaryColor,
),
);
List<DocumentSnapshot> docs = snapshot.data.documents;
List<Widget> messages = docs
.map((doc) => Message(
user: doc.data['user'],
text: doc.data['text'],
timestamp: doc.data['timestamp'],
mine: userName == doc.data['user'],
))
.toList();
return ListView(
controller: scrollController,
children: messages,
);
}),
),
),
Container(
color: Colors.white,
child: Row(
children: <Widget>[
IconButton(
icon: FaIcon(
FontAwesomeIcons.image,
color: kPrimaryColor,
),
onPressed: sendChat,
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10),
child: TextField(
style: TextStyle(
fontFamily: 'Poppins',
fontSize: 15,
),
onSubmitted: (value) => sendChat(),
controller: messageController,
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.newline,
maxLines: null,
cursorColor: kPrimaryColor,
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(20)),
filled: true,
hintText: "Say Something. Be Nice...",
hintStyle:
TextStyle(fontFamily: 'Montserrat', fontSize: 12),
),
),
),
),
IconButton(
icon: FaIcon(
FontAwesomeIcons.paperPlane,
color: kPrimaryColor,
),
onPressed: sendChat,
),
],
),
),
],
),
);
}
void logOut() async {
try {
await widget.auth.signOut();
widget.signedOut();
} catch (e) {
print("error :" + e.toString());
}
}
Future<void> sendChat() async {
if (messageController.text.length > 0) {
await _firestore.collection("messages").add({
'user': userName,
'text': messageController.text,
'timestamp': FieldValue.serverTimestamp(),
});
messageController.clear();
scrollController.animateTo(scrollController.position.maxScrollExtent,
duration: Duration(milliseconds: 300), curve: Curves.easeOut);
}
}
}
Screenshot of the chat screen:
To send images in a chat, you need a place to host those images. One way of doing this is by using file hosting services like Firebase Cloud Storage. This boils down to these steps.
Upload images on Cloud Storage. The image paths from the
device's local storage can be fetched using image_picker
Store the Cloud Storage path of the uploaded image i.e. using Cloud
Firestore
Display the image from the Cloud Storage path using Image.network()