I've created a flutter project that show a staggeredgridview of images from firestore database. Once i click on one of the images it shows that image. What i want is a download button thats saves the image to my device. Ath the moment I've just used pop.
I've read some about the path provider package but i can't figure out how to implement this in the code. Perhaps there is a better solution?
StaggeredGridView Page
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
import 'package:proj/screens/home/instafull.dart';
import 'dart:async';
import 'package:proj/services/auth.dart';
import 'package:proj/shared/constants.dart';
class Instapage extends StatefulWidget {
#override
_InstapageState createState() => _InstapageState();
}
class _InstapageState extends State<Instapage> {
final AuthService _auth = AuthService();
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> wallpaperlist;
final CollectionReference collectionReference = FirebaseFirestore.instance.collection('mediapost');
#override
void initState() {
// TODO: implement initState
super.initState();
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
wallpaperlist = datasnapshot.docs;
});
});
}
#override
void dispose() {
subscription?.cancel();
// TODO: implement dispose
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: bas,
body: wallpaperlist != null?
StaggeredGridView.countBuilder(
padding: const EdgeInsets.fromLTRB(10, 8, 10, 0),
crossAxisCount: 4,
itemCount: wallpaperlist.length,
itemBuilder: (context, index){
String imgPath = wallpaperlist[index].get('img');
return new Material(
elevation: 8,
borderRadius: BorderRadius.all(Radius.circular(8.0)),
child: InkWell(
onTap: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InstaFull(imgPath: imgPath))),
child: Hero(
tag: imgPath,
child: FadeInImage(
image: NetworkImage(imgPath),
fit: BoxFit.cover,
placeholder: AssetImage('assets/wally2.jpg'),
),
),
),
);
},
staggeredTileBuilder: (index) => StaggeredTile.count(2, index.isEven?2:3),
mainAxisSpacing: 8,
crossAxisSpacing: 8,
): Center(
child: CircularProgressIndicator(),
),
);
}
}
Picture Page
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class InstaFull extends StatelessWidget {
String imgPath;
InstaFull({this.imgPath});
final LinearGradient backgroundGradient = LinearGradient(
colors: [Color(0x10000000), Color(0x30000000)],
begin: Alignment.topLeft,end: Alignment.bottomRight);
#override
Widget build(BuildContext context) {
return Scaffold(
body: SizedBox.expand(
child: Stack(
children: [
Align(
alignment: Alignment.center,
child: Hero(
tag: imgPath,
child: Image.network(imgPath),
),
),
Align(
alignment: Alignment.topCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
leading: IconButton(
icon: Icon(Icons.close,
color: Colors.black,
),
onPressed: () => Navigator.of(context).pop(),
),
),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
TextButton(
onPressed: () => Navigator.of(context).pop(),
child: Text('Download')),
],),
)
],
),
),
);
}
}
You can use gallery_saver
Install it and enable this permissions:
iOS
Add the following keys to your Info.plist file, located in <project root>/ios/Runner/Info.plist:
NSPhotoLibraryUsageDescription - describe why your app needs permission for the photo library. This is called Privacy - Photo Library Usage Description in the visual editor.
Android
Android
android.permission.WRITE_EXTERNAL_STORAGE - Permission for usage of external storage
Official example of gallery_saver:
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:gallery_saver/gallery_saver.dart';
import 'package:image_picker/image_picker.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String firstButtonText = 'Take photo';
String secondButtonText = 'Record video';
double textSize = 20;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Container(
color: Colors.white,
child: Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
child: SizedBox.expand(
child: RaisedButton(
color: Colors.blue,
onPressed: _takePhoto,
child: Text(firstButtonText,
style:
TextStyle(fontSize: textSize, color: Colors.white)),
),
),
),
),
Flexible(
child: Container(
child: SizedBox.expand(
child: RaisedButton(
color: Colors.white,
onPressed: _recordVideo,
child: Text(secondButtonText,
style: TextStyle(
fontSize: textSize, color: Colors.blueGrey)),
),
)),
flex: 1,
)
],
),
),
));
}
void _takePhoto() async {
ImagePicker.pickImage(source: ImageSource.camera)
.then((File recordedImage) {
if (recordedImage != null && recordedImage.path != null) {
setState(() {
firstButtonText = 'saving in progress...';
});
GallerySaver.saveImage(recordedImage.path).then((String path) {
setState(() {
firstButtonText = 'image saved!';
});
});
}
});
}
void _recordVideo() async {
ImagePicker.pickVideo(source: ImageSource.camera)
.then((File recordedVideo) {
if (recordedVideo != null && recordedVideo.path != null) {
setState(() {
secondButtonText = 'saving in progress...';
});
GallerySaver.saveVideo(recordedVideo.path).then((String path) {
setState(() {
secondButtonText = 'video saved!';
});
});
}
});
}
void _saveNetworkVideo() async {
String path =
'https://sample-videos.com/video123/mp4/720/big_buck_bunny_720p_1mb.mp4';
GallerySaver.saveVideo(path).then((bool success) {
setState(() {
print('Video is saved');
});
});
}
void _saveNetworkImage() async {
String path =
'https://image.shutterstock.com/image-photo/montreal-canada-july-11-2019-600w-1450023539.jpg';
GallerySaver.saveImage(path).then((bool success) {
setState(() {
print('Image is saved');
});
});
}
}
Related
I have this problem with this code. I tried to solve the problem, but I did not succeed. Please Help
Please see the screenshots to understand the problem well
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 370 pos 10: 'data != null'
Pictures description error
null in firebase
The users email address.Will be null if signing in anonymously.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flash_chat/constants.dart';
class ChatScreen extends StatefulWidget {
static const Id = 'chat_screen';
#override
_ChatScreenState createState() => _ChatScreenState();
}
class _ChatScreenState extends State<ChatScreen> {
// ignore: deprecated_member_use
final _firestore = Firestore.instance;
final _auth = FirebaseAuth.instance;
// ignore: deprecated_member_use
FirebaseUser loggedInUser;
String messageText;
#override
void initState() {
super.initState();
getCurrentUser();
}
void getCurrentUser() async {
try {
// ignore: await_only_futures
final user = await _auth.currentUser;
if (user != null) {
loggedInUser = user;
print(loggedInUser.email);
}
} catch (e) {
print(e);
}
}
// void getMessages() async {
// // ignore: deprecated_member_use
// final messages = await _firestore.collection('Messages').getDocuments();
// // ignore: deprecated_member_use
// for (var message in messages.docs) {
// print(message.data());
// }
// }
void messagesStream() async {
await for (var snapshot in _firestore.collection('Messages').snapshots()) {
for (var message in snapshot.docs) {
print(message.data());
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: null,
actions: <Widget>[
IconButton(
icon: Icon(Icons.close),
onPressed: () {
messagesStream();
//_auth.signOut();
//Navigator.pop(context);
}),
],
title: Text('⚡️Chat'),
backgroundColor: Colors.lightBlueAccent,
),
body: SafeArea(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
StreamBuilder<QuerySnapshot>(
stream: _firestore.collection('Messages').snapshots(),
// ignore: missing_return
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(
backgroundColor: Colors.lightBlueAccent,
));
}
// ignore: deprecated_member_use
final messages = snapshot.data.documents;
List<Messagebubble> messagebubbles = [];
for (var message in messages) {
final messageText = message.data()['text'];
final messagesendar = message.data()['Sender'];
final messagebubble = Messagebubble(
sendar: messagesendar,
text: messageText,
);
messagebubbles.add(messagebubble);
}
return Expanded(
child: ListView(
padding: EdgeInsets.symmetric(
horizontal: 10.0,
vertical: 20.0,
),
children: messagebubbles,
),
);
},
),
Container(
decoration: kMessageContainerDecoration,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
onChanged: (value) {
messageText = value;
},
decoration: kMessageTextFieldDecoration,
),
),
FlatButton(
onPressed: () {
_firestore.collection('Messages').add({
'text': messageText,
'Sender': loggedInUser,
});
},
child: Text(
'Send',
style: kSendButtonTextStyle,
),
),
],
),
),
],
),
),
);
}
}
class Messagebubble extends StatelessWidget {
Messagebubble({
Key key,
this.sendar,
this.text,
}) : super(key: key);
final String sendar;
final String text;
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(10.0),
child: Column(
children: [
Text(
sendar,
style: TextStyle(
fontSize: 12.0,
color: Colors.black54,
),
),
Material(
borderRadius: BorderRadius.circular(30.0),
elevation: 5.0,
color: Colors.lightBlueAccent,
child: Padding(
padding: EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 20.0,
),
child: Text(
text,
style: TextStyle(
color: Colors.white,
fontSize: 15.0,
),
),
),
),
],
),
);
}
}
You just need to check whether the text that you are passing is null or not. If it is null, you can show that the user is Anonymous.
final messageText = message.data()['text'];
final messagesendar = message.data()['Sender'] ?? 'Anonymous'; // If null then use 'Anonymous'
final messagebubble = Messagebubble(
sendar: messagesendar,
text: messageText,
);
Flutter doesn't allow you to pass null to Text widgets.
https://i.stack.imgur.com/9k5MB.png
I am new to flutter and I'm working on social distancing app in flutter. I wanted to push the uuid of bluetooth devices discovered to the firestore can someone please help me in doing this
I can print out the discovered devices in my app and i can get rssi uuid txpower
but as rssi keeps varying and scanning happens continuously the devices get pushed into firestore multiple times
i wanted UUID to be pushed into the firestore only once.
Nearby.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_blue/flutter_blue.dart';
import 'package:beacon_broadcast/beacon_broadcast.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'homescreen.dart';
import 'material.dart';
class BlueApp extends StatefulWidget {
#override
_BlueAppState createState() => _BlueAppState();
}
BeaconBroadcast beaconBroadcast = BeaconBroadcast();
BeaconStatus _isTransmissionSupported;
bool _isAdvertising = false;
StreamSubscription<bool> _isAdvertisingSubscription;
final databaseReference=Firestore.instance;
String UUID = "3E4D7TJ9008";
void createRecord(String usid) async {
await databaseReference.collection("users")
.document("1")
.setData({
'uuid':usid
});
print('senddddddddingggggg');
DocumentReference ref = await databaseReference.collection("users")
.add({
'uuid':usid
});
print(ref.documentID);
}
class _BlueAppState extends State<BlueApp> {
static const UUID = '39ED98FF';
static const MAJOR_ID = 1;
static const MINOR_ID = 100;
static const TRANSMISSION_POWER = -59;
static const IDENTIFIER = 'com.example.myDeviceRegion';
static const LAYOUT = BeaconBroadcast.ALTBEACON_LAYOUT;
static const MANUFACTURER_ID = 0x0118;
void initState() {
// TODO: implement initState
super.initState();
FlutterBlue.instance.state.listen((state) {
print("im in the init");
print(state);
if (state == BluetoothState.off) {
print("bluetooth is off");
} else if (state == BluetoothState.on) {
print("bluethooth on");
//print(device.id);
}
print("printing eacon");
});
beaconBroadcast.checkTransmissionSupported().then((isTransmissionSupported) {
setState(() {
_isTransmissionSupported = isTransmissionSupported;
print(_isTransmissionSupported);
});
});
_isAdvertisingSubscription =
beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) {
setState(() {
_isAdvertising = isAdvertising;
});
});
beaconBroadcast
.setUUID(UUID)
.setMajorId(MAJOR_ID)
.setMinorId(MINOR_ID)
.setTransmissionPower(-59)
.setIdentifier(IDENTIFIER)
.setLayout(LAYOUT)
.setManufacturerId(MANUFACTURER_ID)
.start();
if(_isAdvertising==true){
print('Beacon started Advertising');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
color: Colors.lightBlue,
home: StreamBuilder<BluetoothState>(
stream: FlutterBlue.instance.state,
initialData: BluetoothState.turningOn,
builder: (c, snapshot) {
final state = snapshot.data;
print(state);
if (state == BluetoothState.on) {
print("BlueTooth is on");
return FindDevicesScreen();
}
print("BlueTooth is off");
return BluetoothOffScreen(state: state);
}),
);
}
}
class BluetoothOffScreen extends StatelessWidget {
const BluetoothOffScreen({Key key, this.state}) : super(key: key);
final BluetoothState state;
#override
Widget build(BuildContext context) {
_BlueAppState a=new _BlueAppState();
createRecord(UUID);
return Scaffold(
backgroundColor: Colors.lightBlue,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.bluetooth_disabled,
size: 200.0,
color: Colors.white54,
),
Text(
'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.',
style: Theme.of(context)
.primaryTextTheme
.subhead
.copyWith(color: Colors.white),
),
],
),
),
);
}
}
class FindDevicesScreen extends StatefulWidget {
#override
_FindDevicesScreenState createState() => _FindDevicesScreenState();
}
class _FindDevicesScreenState extends State<FindDevicesScreen> {
#override
void initState() {
// TODO: implement initState
super.initState();
FlutterBlue.instance.startScan();
beaconBroadcast.checkTransmissionSupported().then((isTransmissionSupported) {
setState(() {
_isTransmissionSupported = isTransmissionSupported;
print(_isTransmissionSupported);
});
});
_isAdvertisingSubscription =
beaconBroadcast.getAdvertisingStateChange().listen((isAdvertising) {
setState(() {
_isAdvertising = isAdvertising;
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Find Devices'),
),
body: RefreshIndicator(
onRefresh: () =>
FlutterBlue.instance.startScan(),
child: SingleChildScrollView(
child: Column(
children: <Widget>[
StreamBuilder<List<BluetoothDevice>>(
stream: Stream.periodic(Duration(seconds: 4))
.asyncMap((_) => FlutterBlue.instance.connectedDevices),
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map((d) => ListTile(
title: Text(d.name),
subtitle: Text(d.id.toString()),
trailing: StreamBuilder<BluetoothDeviceState>(
stream: d.state,
initialData: BluetoothDeviceState.disconnected,
builder: (c, snapshot) {
print('entering if');
if (true) {
print('id----------------------------------------------did');
}
return Text(snapshot.data.toString());
},
),
))
.toList(),
),
),
StreamBuilder<List<ScanResult>>(
stream: FlutterBlue.instance.scanResults,
initialData: [],
builder: (c, snapshot) => Column(
children: snapshot.data
.map(
(r) => Card(
child: ScanResultTile(
result: r,
onTap: () => Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return null;
})),
),
),
)
.toList(),
),
),
],
),
),
),
);
}
}
material.dart
import 'package:flutter_blue/flutter_blue.dart';
import 'nearby.dart';
class ScanResultTile extends StatelessWidget {
const ScanResultTile({Key key, this.result, this.onTap}) : super(key: key);
final ScanResult result;
final VoidCallback onTap;
Widget _buildTitle(BuildContext context) {
if (result.device.name.length > 0) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
result.device.name,
overflow: TextOverflow.ellipsis,
),
Text(
result.device.id.toString(),
style: Theme.of(context).textTheme.caption,
),
// _buildAdvRow(
// context, 'Distance of the device',(result.rssi!=null && result.advertisementData.txPowerLevel!=null)?"${getDistance(result.rssi,result.advertisementData.txPowerLevel)}":"N/A" ),
],
);
} else {
return Text(result.device.id.toString());
}
}
Widget _buildAdvRow(BuildContext context, String title, String value) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 4.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(title, style: Theme.of(context).textTheme.caption),
SizedBox(
width: 12.0,
),
Expanded(
child: Text(
value,
style: Theme.of(context)
.textTheme
.caption
.apply(color: Colors.black),
softWrap: true,
),
),
],
),
);
}
String getNiceHexArray(List<int> bytes) {
return '[${bytes.map((i) => i.toRadixString(16).padLeft(2, '0')).join(', ')}]'
.toUpperCase();
}
int getDistance(int rssi, int txPower) {
print("rssi");
print(rssi);
return 10 ^ ((txPower - rssi) / (10 * 2)).round();
}
#override
Widget build(BuildContext context) {
print("rssi");
print(result.rssi);
print("Transmit power");
print(result.advertisementData.txPowerLevel);
// print(result.device.name);
print(result);
// if((getDistance(result.rssi,result.advertisementData.txPowerLevel))<=2)
// {
// createRecord(result.advertisementData.serviceUuids.iterator.moveNext().toString());
// }
return ExpansionTile(
title: _buildTitle(context),
leading: Column(
children: <Widget>[
Text("Tap for more...",style: TextStyle(fontSize: 10.0,color: Colors.lightBlueAccent),)
],
),
children: <Widget>[
_buildAdvRow(
context, 'Distance of the device',(result.rssi!=null && result.advertisementData.txPowerLevel!=null)?"${getDistance(result.rssi,result.advertisementData.txPowerLevel)}":"N/A" ),
_buildAdvRow(context, 'Tx Power Level',
'${result.advertisementData.txPowerLevel ?? 'N/A'}'),
_buildAdvRow(
context,
'Service UUIDs',
(result.advertisementData.serviceUuids.isNotEmpty)? result.advertisementData.serviceUuids.join(', ').toUpperCase(): 'N/A'),
],
);
}
}
class ServiceTile extends StatelessWidget {
final BluetoothService service;
final List<CharacteristicTile> characteristicTiles;
const ServiceTile({Key key, this.service, this.characteristicTiles})
: super(key: key);
#override
Widget build(BuildContext context) {
if (characteristicTiles.length > 0) {
return ExpansionTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Service'),
Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
children: characteristicTiles,
);
} else {
return ListTile(
title: Text('Service'),
subtitle:
Text('0x${service.uuid.toString().toUpperCase().substring(4, 8)}'),
);
}
}
}
class CharacteristicTile extends StatelessWidget {
final BluetoothCharacteristic characteristic;
final List<DescriptorTile> descriptorTiles;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
final VoidCallback onNotificationPressed;
const CharacteristicTile(
{Key key,
this.characteristic,
this.descriptorTiles,
this.onReadPressed,
this.onWritePressed,
this.onNotificationPressed})
: super(key: key);
#override
Widget build(BuildContext context) {
return StreamBuilder<List<int>>(
stream: characteristic.value,
initialData: characteristic.lastValue,
builder: (c, snapshot) {
final value = snapshot.data;
return ExpansionTile(
title: ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Characteristic'),
Text(
'0x${characteristic.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context).textTheme.body1.copyWith(
color: Theme.of(context).textTheme.caption.color))
],
),
subtitle: Text(value.toString()),
contentPadding: EdgeInsets.all(0.0),
),
children: descriptorTiles,
);
},
);
}
}
class DescriptorTile extends StatelessWidget {
final BluetoothDescriptor descriptor;
final VoidCallback onReadPressed;
final VoidCallback onWritePressed;
const DescriptorTile(
{Key key, this.descriptor, this.onReadPressed, this.onWritePressed})
: super(key: key);
#override
Widget build(BuildContext context) {
return ListTile(
title: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text('Descriptor'),
Text('0x${descriptor.uuid.toString().toUpperCase().substring(4, 8)}',
style: Theme.of(context)
.textTheme
.body1
.copyWith(color: Theme.of(context).textTheme.caption.color))
],
),
subtitle: StreamBuilder<List<int>>(
stream: descriptor.value,
initialData: descriptor.lastValue,
builder: (c, snapshot) => Text(snapshot.data.toString()),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(
Icons.file_download,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onReadPressed,
),
IconButton(
icon: Icon(
Icons.file_upload,
color: Theme.of(context).iconTheme.color.withOpacity(0.5),
),
onPressed: onWritePressed,
)
],
),
);
}
}
class AdapterStateTile extends StatelessWidget {
const AdapterStateTile({Key key, #required this.state}) : super(key: key);
final BluetoothState state;
#override
Widget build(BuildContext context) {
return Container(
color: Colors.redAccent,
child: ListTile(
title: Text(
'Bluetooth adapter is ${state.toString().substring(15)}',
style: Theme.of(context).primaryTextTheme.subhead,
),
trailing: Icon(
Icons.error,
color: Theme.of(context).primaryTextTheme.subhead.color,
),
),
);
}
}```
To avoid adding it additional times there are two altenatives.
Alternative 1:
Index the uuid field, as this will allow you to query over this field
Before writing query for documents with this uuid
Write only if the response is empty
This alternative has the advantage that no changes need to be done on firestore and minimun changes on the code, however will have the disadvantage that each write attempt will be preceeded by a read and reads are billed.
Alternative 2:
Change the data structucture on Firestore so that the UUID is the document ID
This has the advantage that the writes won't be preceeded by a read therefore its cheaper on firestore costs. However it needs more code edition and will need to change the data stucture.
for the code the main change is on the following method:
void createRecord(String usid) async {
await databaseReference.collection("users")
.document(usid)
.setData({
'uuid':usid
});
print('senddddddddingggggg');
DocumentReference ref = await databaseReference.collection("users")
.document(usid)
.setData({
'uuid':usid
});
print(ref.documentID);
}
In my flutter project, I want to read data from the Firebase Database of the current user logged in and display the User name from the database and display at the appbar[Line 43:title: Text('$userName'),] of the Page.I had tried by the following code below but it gives error on line 26[Line:final FirebaseUser user = _auth.currentUser();]. The error is on the keyword '_auth.currentUser()'
Error is:A value of type 'Future' can't be assigned to a variable of type 'FirebaseUser'
Here is the code:
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:udharibook/Screens/UserProfile.dart';
import 'package:udharibook/services/authservice.dart';
import 'Customer_Support.dart';
import 'package:udharibook/services/UserData.dart';
class DashboardPage extends StatefulWidget {
#override
_DashboardPageState createState() => _DashboardPageState();
}
class _DashboardPageState extends State<DashboardPage> {
List<UserData> userdata = [];
String userName;
#override
void initState()
{
super.initState();
FirebaseAuth _auth = FirebaseAuth.instance;
DatabaseReference DBRef = FirebaseDatabase.instance.reference().child('Users');
final FirebaseUser user = _auth.currentUser();
DBRef.child(user.uid).once().then((DataSnapshot user)
{
userName = user.value['Name'];
setState(() {
print(userName);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('$userName'),
backgroundColor: Color.fromRGBO(162, 42, 43, 1.0),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
print("Search Clicked");
}),
IconButton(
icon: Icon(Icons.sort),
onPressed: () {
print("Sort Clicked");
}),
],
),
drawer: Drawer(
child: ListView(
children: <Widget>[
DrawerHeader(
child: Text("mehul jain"),
decoration: BoxDecoration(
color: Color.fromRGBO(162, 42, 43, 1.0),
),
),
CustomMenu(
Icons.person,
'Profile',() => {
Navigator.pop(context),
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => UserProfile()))
}),
CustomMenu(Icons.assessment, 'Reports', () => {}),
CustomMenu(Icons.settings, 'Settings', () => {}),
CustomMenu(
Icons.perm_phone_msg,
'Customer Support',
() => {
Navigator.pop(context),
Navigator.push(
context,
new MaterialPageRoute(
builder: (context) => CustSupport()))
}),
CustomMenu(Icons.lock, 'Log Out', () => {AuthService().signOut()}),
],
),
),
);
}
}
class CustomMenu extends StatelessWidget {
IconData icon;
String text;
Function onTap;
CustomMenu(this.icon, this.text, this.onTap);
#override
Widget build(BuildContext context) {
// TODO: implement build
return Padding(
padding: EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 0.0),
child: Container(
decoration: BoxDecoration(
border:
Border(bottom: BorderSide(color: Colors.grey.shade400))),
child: InkWell(
splashColor: Colors.redAccent,
onTap: onTap,
child: Container(
height: 60.0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Row(
children: <Widget>[
Icon(icon),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
text,
style: TextStyle(
fontSize: 17.0, fontFamily: 'Exo2'),
)),
],
),
Icon(Icons.arrow_right),
],
),
))));
}
}
currentUser() returns a Future<FirebaseUser>, therefore you have to do the following:
_auth.currentUser().then((curUser)
{
DBRef.child(curUser.uid).once().then((DataSnapshot user)
{
userName = user.value['Name'];
setState(() {
print(userName);
});
});
});
https://dart.dev/codelabs/async-await
I have a splash screen where I want to control the followig:
1. If user is loged out, take the user to OnBoardingScreen.
2. If user is loged in, but has no data in firestore. Take the user to SetupAccountPage
3. If user is loged in and had data to go to HomePage.
My problem is the string value(_controller) returns null. when the user is loged out and works fine when the user is loged in. I'm confused. I gave the code some time to load but doesn't help.
Please help for anyone who has an idea what is wrong here.
Below is my code
import 'dart:async';
import 'package:app/model/user.dart';
import 'package:app/pages/HomePage.dart';
import 'package:app/pages/SetupAccountPage.dart';
import 'package:app/screens/home/home.dart';
import 'package:app/screens/onboarding.dart';
import 'package:app/screens/setup_profile.dart';
import 'package:app/shared/loading.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
//FirebaseUser user;
String onlineUserId;
String _controller;
#override
void initState() {
super.initState();
_checkUser();
Timer(Duration(seconds: 5), () {
print('done');
if (_controller == 'out') {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OnBoardingScreen(),
),
);
} else if (_controller == 'info') {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SetupAccountPage(),
),
);
} else if (_controller == 'home') {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => HomePage(),
),
);
}
;
});
}
_checkUser() async {
final FirebaseUser user = await FirebaseAuth.instance.currentUser();
final uid = user.uid;
if (await FirebaseAuth.instance.currentUser() == null) {
setState(() {
_controller = 'out';
});
} else {
final snapShot =
await Firestore.instance.collection('Users').document(user.uid).get();
if (snapShot.exists) {
setState(() {
_controller = 'home';
});
// Document with id == docId doesn't exist.
} else {
setState(() {
_controller = 'info';
});
}
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
fit: StackFit.expand,
children: <Widget>[
Container(
decoration: BoxDecoration(color: Colors.redAccent),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 2,
child: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircleAvatar(
backgroundColor: Colors.white,
radius: 50.0,
child: Icon(
Icons.shopping_cart,
color: Colors.greenAccent,
size: 50.0,
),
),
Padding(
padding: EdgeInsets.only(top: 10.0),
),
Text(
'this is a name',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 24.0),
)
],
),
),
),
Expanded(
flex: 1,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Padding(
padding: EdgeInsets.only(top: 20.0),
),
Text(
'another name',
softWrap: true,
textAlign: TextAlign.center,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 18.0,
color: Colors.white),
)
],
),
)
],
)
],
),
);
}
}
I finally found the answer. The reson was geting the user was returning a future and this was the missing code.
Future<FirebaseUser> getUser() async {
return await _auth.currentUser();
}
I am trying to figure out how to do this.
If I pass the document ID hardcoded it works. But Since I have multiple pages, I am trying to figure out how to pass it and then query it..
My main page has the following.
import 'package:flutter/material.dart';
import 'package:onlytag2/pages/category.dart';
import 'package:onlytag2/widget/maincard.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
Query collectionReference = Firestore.instance.collection("mainCategories").orderBy("title");
void initState() {
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
#override
void dispose() {
subscription.cancel(); //Streams must be closed when not needed
super.dispose();
}
passData(DocumentSnapshot snap, String cat, String title) {
print(cat);
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => Category(snapshot: snap, category: cat, title: title,)));
}
#override
Widget build(BuildContext context) {
if (snapshot == null) return Center(
child: Container(
color: Colors.black,
alignment: AlignmentDirectional(0.0, 0.0),
child: Container(
color: Colors.black,
constraints: BoxConstraints(
maxHeight: 300.0,
maxWidth: 200.0,
minWidth: 150.0,
minHeight: 150.0
),
child: CircularProgressIndicator(),
),
),
);
return Scaffold(
backgroundColor: Color(0xff0E0E0F),
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
"#",
style: TextStyle(
fontSize: 25, color: Color(0xffff9900), fontFamily: 'Dokyo'),
),
Text(
"onlytags",
style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),
)
],
),
),
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return InkWell(
onTap: () => passData(snapshot[index], snapshot[index].documentID.toString(), snapshot[index].data["title"] ),
child: MainCard(
title: snapshot[index].data["title"],
subtitle: snapshot[index].data["subTitle"],
image: snapshot[index].data["image"],
),
);
}),
),
],
),
),
],
),
);
}
}
The category widget is where I am having the problem.
Comment Listed where I am having the problem.
import 'package:flutter/material.dart';
import 'package:onlytag2/widget/sub.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class Category extends StatefulWidget {
DocumentSnapshot snapshot;
final String category;
final String title;
Category({this.snapshot, this.category, this.title});
#override
_CategoryState createState() => _CategoryState();
}
class _CategoryState extends State<Category>{
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
//How do I get the category passed properly? I know it is the Document ID, but since it changes based on what button is pressed before,
//I cant figure out how to pass it..
Query collectionReference = Firestore.instance.collection("mainCategories").document(widget.category).collection("subCategories").orderBy("title");
void initState() {
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
#override
void dispose() {
subscription.cancel(); //Streams must be closed when not needed
super.dispose();
}
#override
Widget build(BuildContext context) {
if (snapshot == null) return Center(
child: Container(
color: Colors.black,
alignment: AlignmentDirectional(0.0, 0.0),
child: Container(
color: Colors.black,
constraints: BoxConstraints(
maxHeight: 300.0,
maxWidth: 200.0,
minWidth: 150.0,
minHeight: 150.0
),
child: CircularProgressIndicator(),
),
),
);
return Scaffold(
backgroundColor: Color(0xff0E0E0F),
appBar: AppBar(
iconTheme: IconThemeData(
color: Color(0xffff9900),
),
centerTitle: true,
backgroundColor: Colors.black,
title: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
"#", style: TextStyle(fontSize: 25, color: Color(0xffff9900), fontFamily: 'Dokyo'),
),
Text(widget.title.toLowerCase(), style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),)
],
),
),
body: Column(
children: <Widget>[
Expanded(
child: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: snapshot.length,
itemBuilder: (context, index) {
return Sub(
title: snapshot[index].data["title"],
subtitle: snapshot[index].data["subTitle"],
image: snapshot[index].data["image"],
);
}),
),
Padding(padding: EdgeInsets.fromLTRB(0, 0, 0, 15),)
],
),
),
],
),
);
}
}
I have realised that the code looks shady on the comment so let me make an answer.
What you are trying to do is currently not supported in flutter as can be seen at these GitHub issues 1 and 2.
Change your code to,
class _CategoryState extends State<Category>{
StreamSubscription<QuerySnapshot> subscription;
List<DocumentSnapshot> snapshot;
Query collectionReference;
void initState() {
collectionReference = Firestore.instance.collection("mainCategories").document(widget.category).collection("subCategories").orderBy("title");
subscription = collectionReference.snapshots().listen((datasnapshot) {
setState(() {
snapshot = datasnapshot.documents;
});
});
super.initState();
}
...
Hope this helps.