Flutter/Firebase - Right Track? - firebase

At 54 I'm self-learning Flutter and have come a long way. I am stuck (again) with a speed-bump concerning my implementation of Firebase. Although I am getting the very basic of displaying a line of data for each record the problem is getting to the details of each record. I believe the issue is that I am not referencing the record ID.
When looking at endless examples I also believe my code to display a ListView of records is bloated making it more difficult to grab a record and display all fields (edit screen).
I want to click the "Walsh-Test" links to view all fields and update. I can create a new edit/update screen my initial problem is opening the screen to the selected record.
Any advice would be greatly appreciated.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/rendering.dart';
class MeterReadHomeScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Color(0xff4367b1),
automaticallyImplyLeading: false,
leading: GestureDetector(
onTap: () {
Navigator.pop(context);
},
child: Icon(
Icons.arrow_back,
color: Colors.white,
),
),
title: Text(
"WelakaOne",
style: TextStyle(
color: Colors.white,
),
),
),
body: StreamBuilder(
stream: FirebaseFirestore.instance
.collection('meter_reads')
.orderBy('accountname')
.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
}
return Padding(
padding: const EdgeInsets.fromLTRB(6, 20, 0, 0),
child: Container(
child: GestureDetector(
onTap: () {},
child: ListView(
children: snapshot.data.docs.map(
(document) {
return Row(
children: [
Container(
width: 50,
child: Icon(
Icons.access_alarm,
size: 36,
color: Color(0xff4367b1),
),
),
Container(
child: Text(
document['accountname'],
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
color: Color(0xff4367b1),
),
),
),
SizedBox(height: 44),
],
);
},
).toList(),
),
),
),
);
},
),
);
}
}
[![Flutter/Firebase/Open to Selected Record][1]][1]

I understand that you want to go to another page (Edit Screen) onTapping the alarm tile.
So, my suggestion is to use A ListTile widget instead of the row widget you are using.
You can read about ListTile's onTap property, here
Regarding your routing to a new screen/page, you'll have to make use of MaterialPageRoute to create a new route and using Navigator's push method you can push it onto your Material App.
Attaching an example code that uses Navigator to go to different pages, you need the BuildContext of your app. Here is an example of how you can get it:
import 'package:flutter/material.dart';
import 'package:rate_your_professor/screens/firstScreen.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Some App',
home: SomeApp(),
);
}
}
class SomeApp extends StatelessWidget {
Widget getListView(BuildContext context) {
var listView = ListView(
children: <Widget>[
Text(
"XXXXXXXXXXXXXXX",
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
),
ListTile(
leading: Icon(Icons.location_city),
title: Text("XXXXX ", textDirection: TextDirection.rtl),
subtitle: Text(
"XXXXXXXXXX",
textDirection: TextDirection.rtl,
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => YourNewPage(),
),
);
},
),
],
);
return listView;
}
#override
Widget build(BuildContext context) {
return Scaffold(body: getListView(context));
}
}

Related

Flutter signature upload to firebase storage

I'm creating a form app and I need to savethe signature in database. I don't know what to save this signature plugin from the pub.dev, can someone help me with this? I can't find something in google. I have this seperated code, I'm trying to save it to firebase storage.
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:signature/signature.dart';
/// example widget showing how to use signature widget
class Sig extends StatefulWidget {
#override
_SigState createState() => _SigState();
}
class _SigState extends State<Sig> {
final SignatureController _controller = SignatureController(
penStrokeWidth: 1,
penColor: Colors.red,
exportBackgroundColor: Colors.white,
);
#override
void initState() {
super.initState();
_controller.addListener(() => print('Value changed'));
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Builder(
builder: (BuildContext context) => Scaffold(
body: ListView(
children: <Widget>[
Signature(
controller: _controller,
height: 300,
backgroundColor: Colors.lightBlueAccent,
),
//OK AND CLEAR BUTTONS
Container(
decoration: const BoxDecoration(color: Colors.black),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: <Widget>[
//SHOW EXPORTED IMAGE IN NEW ROUTE
IconButton(
icon: const Icon(Icons.check),
color: Colors.blue,
onPressed: () async {
if (_controller.isNotEmpty) {
final Uint8List data = await _controller.toPngBytes();
if (data != null) {
await Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
color: Colors.grey[300],
child: Image.memory(data),
),
),
);
},
),
);
}
}
},
),
//CLEAR CANVAS
IconButton(
icon: const Icon(Icons.clear),
color: Colors.blue,
onPressed: () {
setState(() => _controller.clear());
},
),
],
),
),
],
),
),
),
);
}
}
I want to upload it in firebase storage and also view it from firebase storage but I don't know how to do it.
If the plugin that are you are using can export the data to coordinates point, maybe you can store the signature on the database without any problems. You can check this for a possible solution:
Changing colour of CustomPaint changes for all previous points
I see this on your code:
final Uint8List data = await _controller.toPngBytes();
So maybe you can check if this data can be exported as a coordinate points or maybe as a base64 image in order to save it on a database.
I hope this can be helpful.

Cant Figure Out How To display Only the post details for the post I have clicked on

So I have this code here and I would like to display post details from firebase for the post which I have clicked on, but instead, it lists post details for every single post in the database one after another.
Can anyone help me figure out how I can make it so that when A post is clicked, details will show for only the post which was clicked, and not for all of the posts? Any help would be greatly appreciated, thank you.
The Info I would like to display on the post is
postTitle
postDesc
postAuthor
Here is what the firebase looks like
Code Here:
import 'package:tennis_event_app/services/crud.dart';
import 'package:tennis_event_app/views/create_blog.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot? blogSnapshot;
#override
void initState() {
crudMethods.getData()?.then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 24),
itemCount: blogSnapshot!.docs.length,
itemBuilder: (context, index) {
return BlogTile(
author: blogSnapshot!.docs[index].get('author'),
title: blogSnapshot!.docs[index].get('title'),
desc: blogSnapshot!.docs[index].get('desc'),
imgUrl: blogSnapshot!.docs[index].get('imgUrl'),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Flutter",
style: TextStyle(fontSize: 22),
),
Text(
"Blog",
style: TextStyle(fontSize: 22, color: Colors.blue),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
child: blogSnapshot != null
? blogsList()
: Container(
child: Center(
child: CircularProgressIndicator(),
))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateBlog()));
},
),
);
}
}
class BlogTile extends StatelessWidget {
final String imgUrl, title, desc, author;
BlogTile(
{required this.author,
required this.desc,
required this.imgUrl,
required this.title});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16, right: 16, left: 16),
child: Stack(
children: <Widget>[
Container(
child: ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(8)),
child: Image.network(
imgUrl,
width: MediaQuery.of(context).size.width,
fit: BoxFit.cover,
height: 170,
),
),
),
Container(
height: 170,
decoration: BoxDecoration(
color: Colors.black45.withOpacity(0.3),
borderRadius: BorderRadius.circular(6)),
),
Container(
height: 170,
width: MediaQuery.of(context).size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
SizedBox(height: 4),
Text(
'$desc',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
SizedBox(
height: 4,
),
Text(author),
],
)),
Container(
child: SizedBox(
height: 170,
width: MediaQuery.of(context).size.width,
child: TextButton(
style: TextButton.styleFrom(
textStyle: const TextStyle(fontSize: 20),
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage()));
},
child: const Text(''),
),
),
),
],
),
);
}
}
class DetailPage extends StatefulWidget {
#override
_DetailPageState createState() => _DetailPageState();
}
class _DetailPageState extends State<DetailPage> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot? blogSnapshot;
#override
void initState() {
crudMethods.getData()?.then((result) {
blogSnapshot = result;
setState(() {});
});
super.initState();
}
Widget blogsList2() {
return Container(
child: ListView.builder(
padding: EdgeInsets.only(top: 24),
itemCount: blogSnapshot!.docs.length,
itemBuilder: (context, index) {
return PageContent(
postAuthor: blogSnapshot!.docs[index].get('postAuthor'),
postTitle: blogSnapshot!.docs[index].get('postTitle'),
postDesc: blogSnapshot!.docs[index].get('postDesc'),
imgUrl: blogSnapshot!.docs[index].get('imgUrl'),
);
},
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"Flutter",
style: TextStyle(fontSize: 22),
),
Text(
"Blog",
style: TextStyle(fontSize: 22, color: Colors.blue),
)
],
),
backgroundColor: Colors.transparent,
elevation: 0.0,
),
body: Container(
child: blogSnapshot != null
? blogsList2()
: Container(
child: Center(
child: CircularProgressIndicator(),
))),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => CreateBlog()));
},
),
);
}
}
class PageContent extends StatelessWidget {
final String imgUrl, postTitle, postDesc, postAuthor;
PageContent(
{required this.postAuthor,
required this.postDesc,
required this.imgUrl,
required this.postTitle});
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(bottom: 16, right: 16, left: 16),
child: Card(
child: ListTile(
title: Text(
postTitle,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
subtitle: Text(
'$postDesc',
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
)
)
);
}
}
I also reference crud.dart in that code, so incase you need it, here it is:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:collection';
class CrudMethods {
Future<void> addData(blogData) async {
print(blogData);
FirebaseFirestore.instance
.collection("blogs")
.add(blogData)
.then((value) => print(value))
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance
.collection("blogs")
.orderBy("ts", descending: true)
.get();
}
}
Thank you again for any help!
First I would recommend to modelize your data in an object for exemple a class Article that is easier to serialize and manipulate.
Then instead of requesting another time the database you should save your data in a List<Article> for example then you only update this list on refresh from your main page. That way you don'y manipulate a QuerySnapshot or Future but just your list of objects.
Finally and to answer your question, you could simply pass the clicked item Article to your details page and only display its content. Because here, you have the same construction as your main page with the same request that is resent.
Usually you can build your route like that (adding a parameter to your details with the index you clicked on for example)
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => DetailPage(article: _data[i])));
},
Here is an article on serialization from Flutter docs, it shows how to build your model with the toMap, toJson and fromJson methods.

NoSuchMethodError. The getter 'weekday' was called on null. Table_Calendar Flutter

I'm stuck with the table calendar.
In Android Studio I get following error:
The following NoSuchMethodError was thrown building StreamBuilder<List<AppEvent>>(dirty, state: _StreamBuilderBaseState<List<AppEvent>, AsyncSnapshot<List<AppEvent>>>#c5581):
The getter 'weekday' was called on null.
Receiver: null
Tried calling: weekday
This is my code: If necessarily I can post more code such the classes.
The other code works perfekt. even in the red issuescreen in the app I can trigger the floated button and add an event. But I cant see the calendar anymore cause the red issuescreen.
import 'package:app_tennis_sv_schwaig/kalender/add_event.dart';
import 'package:app_tennis_sv_schwaig/kalender/event_details.dart';
import 'package:app_tennis_sv_schwaig/kalender/event_firestore_service.dart';
import 'package:app_tennis_sv_schwaig/kalender/app_event.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:table_calendar/table_calendar.dart';
class TennisKalender extends StatefulWidget {
#override
_TennisKalenderState createState() => _TennisKalenderState();
}
class _TennisKalenderState extends State<TennisKalender> {
CalendarController _calendarController = CalendarController();
Map<DateTime, List<AppEvent>> _groupedEvents;
_groupEvents(List<AppEvent> events) {
_groupedEvents = {};
events.forEach((event) {
DateTime date =
DateTime.utc(event.date.year, event.date.month, event.date.day, 12);
if (_groupedEvents[date] == null) _groupedEvents[date] = [];
_groupedEvents[date].add(event);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.orange,
appBar: AppBar(
backgroundColor: Colors.red,
title: Text("Tenniskalender"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.person),
onPressed: (null),
)
],
),
body: SingleChildScrollView(
child: StreamBuilder(
stream: eventDBS.streamList(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
final events = snapshot.data;
_groupEvents(events);
DateTime selectedDate = _calendarController.selectedDay;
final _selectedEvents = _groupedEvents[selectedDate] ?? [];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Card(
clipBehavior: Clip.antiAlias,
margin: const EdgeInsets.all(8.0),
child: TableCalendar(
calendarController: _calendarController,
events: _groupedEvents,
onDaySelected: (date, events, holidays) {
setState(() {});
},
startingDayOfWeek: StartingDayOfWeek.monday,
headerStyle: HeaderStyle(
decoration: BoxDecoration(
color: Colors.red,
),
headerMargin: const EdgeInsets.only(bottom: 8.0),
),
),
),
Padding(
padding: const EdgeInsets.only(left: 12.0, top: 8.0),
child: Text(
DateFormat('EEEE, dd MMMM, yyyy').format(selectedDate),
style: Theme.of(context).textTheme.headline6,
),
),
ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: _selectedEvents.length,
itemBuilder: (BuildContext context, int index) {
AppEvent event = _selectedEvents[index];
return ListTile(
title: Text(event.title),
subtitle: Text(DateFormat("EEEE, dd MMMM, yyyy")
.format(event.date)),
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => EventDetails(
event: event,
)),
);
},
trailing: IconButton(
icon: Icon(Icons.edit),
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => AddEventPage(
event: event,
)));
},
));
},
),
],
);
}
return CircularProgressIndicator();
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.grey[900],
),
backgroundColor: Colors.yellow,
onPressed: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => AddEventPage(
selectedDate: _calendarController.selectedDay,
),
),
);
}),
);
}
}
I dont get it where the weekday is written null.
Can you please help? Thanks a lot!
I solved it. In fact others have a similar issue here's my solution.
The DateFormat in the ListTile from the ListView.builder was the Problem. Don't know why but I deleted it, cause don't needed the view in the app anyway.
Errorcommand:
subtitle: Text(DateFormat("EEEE, dd MMMM, yyyy").format(event.date)),

Flutter how to call multiple api(with futurebuilders) in one screen?

I am building a home page with rest api and using http library. I can get latest posts from my api call. But I am building a Home Page and So I have to show more data from my rest api.
Using Wordpress as back end. I want to fetch 5 posts from 3-4 categories to make home page fill with contents.
Here is my code :
class HomePage extends StatelessWidget {
static const routeName = 'homepage';
final WpPostService wpPostService = WpPostService();
// final WpGhazalService wpGhazalService = WpGhazalService();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('welcome to LilwaQamar'),
),
body: Container(
child: Column(
children: [
Container(
child: FutureBuilder(
future: wpPostService.getPosts(),
builder: (BuildContext context,
AsyncSnapshot<List<Post>> snapshot) {
if (snapshot.hasData) {
List<Post> posts = snapshot.data;
return ListView(
children: posts
.map((Post post) => Card(
elevation: 6,
margin: EdgeInsets.all(10.0),
child: ListTile(
title: Html(
data: post.title.rendered,
defaultTextStyle: GoogleFonts.lato(
textStyle: TextStyle(
color: Colors.black,
letterSpacing: .5,
fontSize: 19),
),
),
subtitle: Html(
data: post.content.rendered
.substring(0, 73) +
'..',
defaultTextStyle: GoogleFonts.lato(
textStyle: TextStyle(
color: Colors.black54,
letterSpacing: .5,
fontSize: 16),
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PostDetaislPage(
post: post,
),
),
);
},
),
))
.toList(),
);
}
return Center(child: CircularProgressIndicator());
}),
),
Container(
child: Text("Ghazals"),
),
],
),
),
);
}
}
I can get data from latest posts. But I have few more api calls like posts from category/1, category/2 etc. How can I get posts from multiple category ? Or how can I call multiple futurebuilders in one screen ? I hope you got my question.
Check out the video for multiple API calls
fetchData() async {
var responses = await Future.wait([
http.get(firstAPI), // make sure return type of these functions as Future.
http.get(secondAPI),
]);
var response1 = responses.first;
var response2 = responses[1];
}

navigator operation requested with a context that does not include a navigator statefulwidget [duplicate]

This question already has answers here:
Navigator operation requested with a context that does not include a Navigator
(18 answers)
Closed 4 years ago.
I am working on the Flutter code that follows. I have issues with the second button called "Regitrese". Every place I have looked work with statelesswidgets so I'm not sure how to fix it. I tried changing the void to put on it home: MyHomePage() and put MyHomePage to statefull instead of taking the statefull from MyApp bus it shows a mistake Missing concrete implementation of StatefulWidget.createState. I am not sure how is it supposed to go. Can you make a button work in a StatefulWidget? Is there a trick I am not seeing?
void main()=> runApp(new MyApp());
class MyApp extends StatefulWidget{
#override
State<StatefulWidget> createState(){
return new MyHomePage();
}
}
class MyHomePage extends State<MyApp>{
final TextEditingController rutController = TextEditingController();
final TextEditingController passwordController = TextEditingController();
var _rut, _password;
#override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
body: new Container(
padding: const EdgeInsets.all(50.0),
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
controller: this.rutController,
decoration: InputDecoration(
labelText: 'Rut',
hintText: 'eg. 154683265',
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
rutController.clear();
}
)
),
),
TextFormField(
controller: this.passwordController,
decoration: InputDecoration(
labelText: 'ContraseƱa',
hintText: 'ContraseƱa',
suffixIcon: IconButton(
icon: Icon(Icons.clear),
onPressed: () {
passwordController.clear();
},
)
),
obscureText: true,
),
RaisedButton(
onPressed: (){
loginButton(rut: this.rutController.text, password: this.passwordController.text);
},
child: Text('Login'),
),
RaisedButton(
onPressed: (){
Navigator.push(
context,
MaterialPageRoute(builder(context)=>SelectUserPage())
)
},
child: Text('Registrese'),
),
],
),
),
),
);
}
}
class SelectUserType extends StatelessWidget{
#override
Widget build(BuildContext context){
return new Container(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: (){
//Do something
},
child: Text(''),
),
RaisedButton(
onPressed: (){
//Do something
},
child: Text(''),
),
],
),
);
}
}
The thing is that you need to access a context below the MaterialApp widget that adds the Navigator to the tree. If you look at your code the context is above it.
One way to solve it is to move a part of the tree to another widget.
Or you can use a Builder around your button or around the Column as in the following code:
Builder(
builder: (context) => RaisedButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(
builder: (context) => SelectUserType()));
},
child: Text('Registrese'),
),
),

Resources