Uploading picture in Firebase storage flutter dart - firebase

I am trying to upload pictures from my gallery, the code works perfectly and is running, but not on my device. I want to know why it isn't working with me please help
this is what is showing when I'm trying to run.
The selection of images is working too
name and title and all that is showing if Firebase but image are not visible in storage.
Future selectFile() async {
final result = await FilePicker.platform
.pickFiles(allowMultiple: false, type: FileType.any);
if (result != null) {
final path = result.files.single.path;
file = File(path!);
setState(() => file = File(path));
}
}
Future uploadFile() async {
if (file == null) return;
final fileName = basename(file!.path);
final destination = 'Content/$fileName';
task = FirebaseApi.uploadFile(destination, file!);
setState(() {});
}
Widget buildUploadStatus(UploadTask uploadTask) =>
StreamBuilder<TaskSnapshot>(
stream: task!.snapshotEvents,
builder: (context, snapshot) {
if (snapshot.hasData) {
final snap = snapshot.data!;
final progress = snap.bytesTransferred / snap.totalBytes;
final percentage = (progress * 100).toStringAsFixed(2);
return Row(
children: [
Text(
'$percentage %',
style: GoogleFonts.asap(
fontSize: 17,
color: Colors.white,
fontWeight: FontWeight.w500,
),
)
],
);
} else {
return Container();
}
},
);
#override
State<StatefulWidget> createState() {
// TODO: implement createState
throw UnimplementedError();
}
}
class StatfulWidget {}
class FirebaseApi {
static UploadTask? uploadFile(String destination, File file) {
try {
final ref = FirebaseStorage.instance.ref(destination);
return ref.putFile(file);
} on FirebaseException catch (e) {
return null;
}
}
}

That's because you're giving the database an empty value. I encountered a similar issue where I was sending the most recent message to the database and initializing it with "." Instead, use something like a space " ".
Example code:
admin.firestore().collection('whatever').doc(""+id);
or use ${id} surrounded with backticks `
An alternative solution could be that data needs to be in JSON format. By default, it is set to text, so it must be changed to JSON (application/json).
Here is a Github forum that is related to same issue: https://github.com/firebase/firebase-admin-node/issues/320

Related

How I can get the right data for specific user when I did auth flow (log in, log out) with Flutter Firestore?

Here is my stream to get data from firebase inside Flutter
Stream<List<TodoModel>> todoStream(String uid) {
return _firestore
.collection("users")
.doc(uid)
.collection("todos")
.orderBy("dateCreated", descending: true)
// .where("done", isEqualTo: true)
.snapshots()
.map((QuerySnapshot query) {
List<TodoModel> retVal = [];
for (var element in query.docs) {
retVal.add(TodoModel.fromDocumentSnapshot(element));
}
return retVal;
});
Here is homeController
Rxn<List<TodoModel>> todoList = Rxn<List<TodoModel>>();
var selectedDate = DateTime.now().obs;
List<TodoModel>? get todos => todoList.value;
#override
void onInit() {
String uid = Get.find<AuthController>().user.value?.uid ?? ' ';
todoList.bindStream(Database().todoStream(uid));
super.onInit();
}
chooseDate() async {
DateTime? pickedDate = await showDatePicker(
context: Get.context!,
initialDate: selectedDate.value,
firstDate: DateTime(2000),
lastDate: DateTime(2024),
//initialEntryMode: DatePickerEntryMode.input,
// initialDatePickerMode: DatePickerMode.year,
);
if (pickedDate != null && pickedDate != selectedDate.value) {
selectedDate.value = pickedDate;
}
}
}
And from home view, I called to get data from firestore.
GetX<HomeController>(
init: Get.put<HomeController>(HomeController()),
builder: (HomeController todoController) {
if (todoController.todos != null) {
// print(todoController.todos?.done ?? false);
return Expanded(
child: ListView.builder(
itemCount: todoController.todos?.length,
itemBuilder: (_, index) {
return TodoCard(
uid: controller.user.value?.uid ?? ' ',
todo: todoController.todos![index],
);
},
),
);
} else {
return Text("loading...");
}
},
),
And I get the data for specific users but only the first time when I open my app. When I tried to log out and log in with a new user I get the data from the previous user. I checked and it's not a problem with SignOut functions from firestore, I think it's a problem with reactive snapshot because I got the right snapshot for a specific user but only if I restarted my app and try to log in. So can someone help with this problem?
without seeing the AuthController difficult to tell.
Get.find<AuthController>().user.value?.uid ?? ' ';
You can replace this with FirebaseAuth.instace.currentUser.uid

How to cache network videos in flutter application?

Im trying to understand what caching videos means and how exactly it works.
The problem that I had was a high bandwidth in my flutter /firebase application . I had like 19gb a day with 10-20 videos and like up to 10 users. So I could not figure out what the problem was. Therefore I contacted firebase support and they say
Looking at the graph, the high bandwidth comes from the storage bucket where the videos are stored. Even though it looks like there are few videos, your bandwidth will increase more and more if your application doesn't store the videos in cache.
Try to double check your applications and ensure that these ones download the information only once.
And I was like what the hak is chaching? And how to do it ?
And will this solve the problem of high bandwidth?
here's how my code looks like
class Videoplayeritem extends StatefulWidget {
final bool mute;
final int pickedvideo;
final int currentPageIndex;
final bool isPaused;
final int pageIndex;
final String videourl;
final String thumbnailUrl;
const Videoplayeritem({
Key key,
this.videourl,
this.currentPageIndex,
this.isPaused,
this.pageIndex,
this.thumbnailUrl,
this.pickedvideo,
this.mute,
}) : super(key: key);
#override
_VideoplayeritemState createState() => _VideoplayeritemState();
}
class _VideoplayeritemState extends State<Videoplayeritem> {
VideoPlayerController videoPlayerController;
bool initialized = false;
bool stopvideo = false;
#override
void initState() {
super.initState();
try {
videoPlayerController = VideoPlayerController.network(
widget.videourl,
videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
)..initialize().then((value) {
if (this.mounted) setState(() {});
try {
videoPlayerController?.play();
videoPlayerController?.setLooping(true);
if (widget.mute) {
videoPlayerController?.setVolume(0);
} else if (!widget.mute) {
videoPlayerController?.setVolume(1);
}
} catch (e) {
print('error: $e');
}
});
} catch (e) {
print('error2: $e');
}
print('init');
}
#override
void dispose() {
try {
if (videoPlayerController.value.isPlaying) {
videoPlayerController?.pause();
}
videoPlayerController?.setVolume(0);
videoPlayerController?.dispose();
videoPlayerController = null;
} catch (e) {
print('error3: $e');
}
print('dispose');
super.dispose();
}
#override
Widget build(BuildContext context) {
if (widget.pageIndex == widget.currentPageIndex &&
!widget.isPaused &&
!stopvideo ||
widget.pageIndex == widget.pickedvideo &&
widget.currentPageIndex == null &&
!stopvideo) {
setState(() {
videoPlayerController?.play();
});
} else {
setState(() {
videoPlayerController?.pause();
});
}
if (widget.mute) {
videoPlayerController?.setVolume(0);
} else if (!widget.mute) {
videoPlayerController?.setVolume(1);
}
return Container(
color: Colors.black,
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Center(
child: videoPlayerController.value.isInitialized
? GestureDetector(
onTap: () {
if (videoPlayerController.value.isPlaying) {
if (this.mounted) {
setState(() {
stopvideo = true;
videoPlayerController?.pause();
});
}
} else {
if (this.mounted) {
setState(() {
stopvideo = false;
videoPlayerController?.play();
videoPlayerController?.setLooping(true);
});
}
}
},
child: VisibilityDetector(
key: Key("unique keys"),
onVisibilityChanged: (VisibilityInfo info) {
debugPrint(
"${info.visibleFraction} of my widget is visible");
if (info.visibleFraction == 0) {
print("pause");
if (stopvideo == false) {
if (this.mounted) {
setState(() {
stopvideo = true;
});
}
}
videoPlayerController?.pause();
} else if (widget.pageIndex == widget.currentPageIndex ||
widget.pageIndex == widget.pickedvideo &&
widget.currentPageIndex == null) {
if (this.mounted) {
if (stopvideo == true) {
setState(() {
stopvideo = false;
});
}
}
videoPlayerController?.play();
} else {}
},
child: Stack(children: [
Center(
child: AspectRatio(
aspectRatio: videoPlayerController.value.aspectRatio,
child: VideoPlayer(videoPlayerController),
),
),
PlayPauseOverlay(
controller: videoPlayerController,
stopvideo: stopvideo,
)
]),
))
: Center(
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: CachedNetworkImage(
errorWidget: (context, url, error) => Icon(Icons.error),
imageUrl: widget.thumbnailUrl,
fit: BoxFit.cover,
),
),
)),
);
}
}
My app is playing videos in Preloadpageview which are vertical scrollable like reels in instagram. The videos are loaded from stream .
Hope anyone can explain what chaching exactly mean and how it will affect my high bandwidth . Also how to used it in my case ?
The problem that I had was a high bandwidth in my flutter /firebase application . I had like 19gb a day with 10-20 videos and like up to 10 users.
There are two layers where caching can with this problem: initial video download, and subsequent video replay.
For initial video download, one option is to dedicate a server to act as an intermediary cache. It would download and stay in sync with the current videourl's content and then serve it. The videourls would then be pointed to this server so the client pulls videos from it.
This only moves the problem around though, and bandwidth isn't free. But you don't have to host this cache server, there are companies that will host for a fee.
The way caching can help for subsequent video replay is by keeping it in local temporary storage on the video playing client, and when returning to the video, retrieving it from local temporary storage and playing it - thereby avoiding asking it from the server again.
One possibly quick solution could be by using the better_player library. It allows many configurations, including using a cache. You can find it here
I might be a little late to answer the question, but if you or anybody else out there are still looking for the answer here's how I did it.
After trying every possible library out there I ended up making my own "video cacher". Note: This might not be the prettiest or the slickest solution, but it gets the job done.
On my main file:
Homepage.dart
body: FutureBuilder(
future: FetchPostData,
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return SizedBox(
child: ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data!.docs.length,
itemBuilder: (context, index) {
return Container(
child: VideoCacher(snapshot.data!.docs[index].data()['VideoUrl'])))
I had a future builder using a cached future stream. Now the data I got form that stream I passed it into another file with a stateful widget called: VideoCacher.dart
VideoCacher.dart
#override
void initState() {
super.initState();
getMedia();
}
Future<void> getMedia() async {
String exp = r'(_.*\.(mp4))';
final RegExp regExp = RegExp(exp);
final String? fileName = regExp.stringMatch(widget._videoUrl);
final Directory tmpDir = Directory.systemTemp;
final File file = File('${tmpDir.path}/$fileName');
if (file.existsSync() == false) {
FirebaseStorage.instance
.ref()
.child('videos')
.child(fileName!)
.writeToFile(file);
setState(() {
_cachedFile = file;
});
} else {
setState(() {
_cachedFile = file;
});
}
}
#override
Widget build(BuildContext context) {
return PostVideoPlayer(_cachedFile);
}
}
In this file I created a tmp location on the system directory where I would download the film from the data I got in stream and pass it on to another file called: VideoPlayer.dart
VideoPlayer.dart
Here I would use the original video_player library provided by flutter team to output the video to my main file.
body: Stack(
alignment: Alignment.bottomCenter,
children: [
SizedBox.expand(
child: FittedBox(
fit: BoxFit.contain,
child: SizedBox(
width: _controller.value.size.width,
height: _controller.value.size.height,
child: VideoPlayer(_controller),
),
),
),
],
),
So the chain would be: Homepage.dart < return VideoCacher.dart <
return VideoPlayer.dart
Prior to this I had my bandwidth consumption at hitting the daily limit in just couple of minutes. Even though I only had 3 videos and total storage of about 2mb.
What I noticed was that anytime you put anything that even remotely relies on fetching data or dynamic data you are bound to run into problems as build method is called every time there is a change. So if you try to get video from storage it will send thousands of requests in succession until you run out of bandwidth.
After this method my bandwidth consumption was around couple mbs, before the video was downloaded and 0mb after it was cached.
Let me know if you found this helpful.
Good Luck.

Adding up values stored in Firebase and displaying total in a FutureBuilder

Im trying to retrieve a list of monthly expenses from Firebase, add up the amount of each monthly expense and show it in a FutureBuilder.
In the Text widget i'm simply getting null. Been trying to google an answer for the past half hour but i don't even know where to begin as in what to search for.
Tried throwing in some print statement to see whats going on but any print statement I put in after the provider call doesn't show.
EDIT: Added Future casts to the commented lines. still no luck. but ignored the variable and called the future function directly from the FutureBuilder. Now all print statements are working and it is returning an instance of 'MonthlyExpense'. It is null still.
class SummaryView extends StatefulWidget {
#override
_SummaryViewState createState() => _SummaryViewState();
}
class _SummaryViewState extends State<SummaryView> {
/* Removed future variable and initState()
Future<double> _totalExpensesAmount; //Future<double> added
#override
void initState() {
super.initState();
print("init");
_totalExpensesAmount = _getTotalExpensesAmount();
}
*/
Future<double> _getTotalExpensesAmount() async { //Future<double> added
print("started");
final user = Provider.of<BPUser>(context);
print("user: $user");
double expensesTotal = 0.0;
var snapshot = await FirebaseFirestore.instance
.collection("BPUsers/${user.uid}/monthlyexpenses")
.get();
print(snapshot);
List<MonthlyExpense> searchedProducts =
DatabaseService().monthlyExpenseListFromSnapshot(snapshot);
print(searchedProducts);
for (var i = searchedProducts.length; i >= 1; i--) {
expensesTotal += double.parse(searchedProducts[i].amount);
}
return Future<double>expensesTotal; //Future<double> added
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: mainBackgroundColor,
body: Column(
children: [
Container(
child: FutureBuilder(
future: _getTotalExpensesAmount(), // called the function directly
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Text(
"${snapshot.data}",
style: nameStyle,
);
} else {
return Text("Loading...");
}
}),
)
],
),
);
}
}
The monthlyExpenseListFromSnapshot function (which works perfectly in another widget I use it in):
List<MonthlyExpense> monthlyExpenseListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return MonthlyExpense(
name: doc.data()['name'] ?? '',
amount: doc.data()['amount'] ?? '',
isActive: doc.data()['isActive']);
}).toList();
}
The firebase database:
You're getExpensesTotal doesn't return a future. Because of this, the widgetvwill never rebuild since the data is already calculated. FutureBuilder and StreamBuilder only cause a rebuild AFTER data been loaded after the initial build. Try surrounding your expensesTotal with Future.value.
You need to define the signature of the function to represent what it is expected, in this case Future <double>.
// ....
Future<double> _getTotalExpensesAmount() async {
First issue was to skip the variable and the init call and call the _getTotalExpensesAmount() future function (adding the Future signature to it).
Secondly my for loop was wrong. needed to change the conditions to:
for (var i = searchedProducts.length - 1; i >= 0; i--) {
Everything is working fine now!

I have data in Firestore ,and filed with values , but some of them shows as null

I have a collection in firestore, and I am fetching the data from firestore to my app, and translate the latitude and longitude to address and it's work ok with other documents, but one of the documents it shows me an error that this field is null, but it has a value as you can see
I always face this problem in Firestore, so sometimes I deleted the document and recreated it again , but I am tired to do that every time, what's is the problem with my Firestore?
Can anyone help me with this?
This is the method to translate the latitude and longitude
Future<String> gymLocation ;
#override
void initState() {
gymLocation = translate.getAddressFromLatLng(widget.gym.gym_region_lat_long.latitude,widget.gym.gym_region_lat_long.longitude);
Future<String> getAddressFromLatLng(double lat , double long) async {
String stringAddress='';
try {
List<Placemark> p = await geolocator.placemarkFromCoordinates(lat,
long);
final coordinates = new Coordinates(lat, long);
var address = await
Geocoder.local.findAddressesFromCoordinates(coordinates);
var first = address.first;
Placemark place = p[0];
final cor2 = await Geocoder.local.findAddressesFromQuery(place.name);
var ad2 = cor2.first;
stringAddress = first.addressLine;
print(stringAddress +' current address');
print('${first.featureName} ,\n${first.addressLine}');
print('${ad2.coordinates}');
// return string_address;
} catch (e) {
print(e);
}
return stringAddress;
}
and this is the method to show the address in Text widget
gymAddressContainter(gym_model gym) {
return FutureBuilder<String>(
future: gymLocation,
builder:(context, snapshot)
{
if (snapshot.hasError) {
return Center(child: Text('No data'));
}
else if (snapshot.hasData) {
return Container(
padding: EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
adressText(
widget.gym.gym_address['g_phone'].toString(), Icons.phone,
Colors.green),
adressText(widget.gym.gym_address['g_email'], Icons.email,
Colors.amber),
adressText(widget.gym.gym_address['g_website'], Icons.public,
Colors.blue),
adressText(snapshot.data, Icons.location_on, Colors.pink)
],
)
);
}
else return Center(child:CircularProgressIndicator());
}
);
}
and this is how I map the document from firrestore to dart
gym_model.map(dynamic obj){
this.gym_name = obj['gym_name'];
this.gym_region = obj['gym_region'];
this.gphoto= obj['gphoto'];
this.gym_region_lat_long = obj['gym_region_lat_long'];
this.gym_city_point = obj['gym_city_point'];
this.gym_address['g_email']= obj['gym_address']['g_email'];
this.gym_address['g_phone'] =obj['gym_address']['g_phone'];
this.gym_address['g_website'] = obj['gym_address']['g_website'];
The other documents work fine but only with this gym Rashad sport club, and it has a value ..
Always have a problem in Firestore, when I create a collection with and create documents and put values for each document , some of the documents shows as null, and give me this message error
PlatformException(failed, Failed, null)

Flutter can't read from Clipboard

I come asking for quite a specific question regarding Flutter and the Future and await mechanism, which seems to be working, but my Clipboard does not really function while operating with my editable text fields, even following Google's advice on implementation...
This is my code for pasting:
onPressed: () async {
await getMyData('text');
_encodingController.text = clipData;
Scaffold.of(context).showSnackBar(
new SnackBar(
content: new Text(
"Pasted from Clipboard"),
),
);
},
what doesnt work is my paste functionality... While debugging the result of this following function is null, wth?????????
static Future<ClipboardData> getMyData(String format) async {
final Map<String, dynamic> result =
await SystemChannels.platform.invokeMethod(
'Clipboard.getData',
format,
);
if (result == null) {
return null;
} else {
clipData = ClipboardData(text: result['text']).text;
return ClipboardData(text: result['text'].text);
}
}
I am probably using the Futures and async await wrong, would love some guidance!!! Copying is working using the Clipboard Manager plugin! Thanks very much!
You can simply re-use Flutter's existing library code to getData from Clipboard.
ClipboardData data = await Clipboard.getData('text/plain');
First create a method
Future<String> getClipBoardData() async {
ClipboardData data = await Clipboard.getData(Clipboard.kTextPlain);
return data.text;
}
Then in build method
FutureBuilder(
future: getClipBoardData(),
initialData: 'nothing',
builder: (context, snapShot){
return Text(snapShot.data.toString());
},
),
It's works for me:
_getFromClipboard() async {
Map<String, dynamic> result =
await SystemChannels.platform.invokeMethod('Clipboard.getData');
if (result != null) {
return result['text'].toString();
}
return '';
}
Also can be useful if you want to listen for periodic updates from the system clipboard.
Originally I replied here, just re-posting the solution:
#creating a listening Stream:
final clipboardContentStream = StreamController<String>.broadcast();
#creating a timer for updates:
Timer clipboardTriggerTime;
clipboardTriggerTime = Timer.periodic(
# you can specify any duration you want, roughly every 20 read from the system
const Duration(seconds: 5),
(timer) {
Clipboard.getData('text/plain').then((clipboarContent) {
print('Clipboard content ${clipboarContent.text}');
# post to a Stream you're subscribed to
clipboardContentStream.add(clipboarContent.text);
});
},
);
# subscribe your view with
Stream get clipboardText => clipboardController.stream
# and don't forget to clean up on your widget
#override
void dispose() {
clipboardContentStream.close();
clipboardTriggerTime.cancel();
}

Resources