I am trying to show the progress of the file I am uploading to firebase storage in a progress indicator how can I achieve this.?
Note that I am a uploading two files at the same time.
here is my code.
Future<String?> _uploadFileToStorage(BuildContext context,File file, path) async {
try {
var task = _firebaseStorage.ref().child(path);
var status = await task.putFile(file);
print(status.state);
return task.getDownloadURL();
} catch (err) {
print(err.toString());
}
}
first take variable bool load and make initialy load=false when your function start make load=trueand at then end of your function load=false, so on your parent widget load==true?CircularProgressIndicator():Scaffold(),
so here you function
Future<String?> _uploadFileToStorage(BuildContext context,File file, path) async {
try {
setState({
load=true;
});
var task = _firebaseStorage.ref().child(path);
var status = await task.putFile(file);
print(status.state);
return task.getDownloadURL();
setState({
load=false;
})
} catch (err) {
print(err.toString());
setState({
load=false;
})
}
}
You can track the uploading progress by simply using the following code:
status.snapshotEvents.listen((TaskSnapshot snapshot) {
print('Task state: ${snapshot.state}');
print('Progress: ${(snapshot.bytesTransferred / snapshot.totalBytes) * 100} %');
switch (snapshot.state) {
case TaskState.paused:
// TODO: Handle this case.
break;
case TaskState.running:
return CircularProgressIndicator(
value: (snapshot.bytesTransferred > 0 && snapshot.totalBytes > 0) ? snapshot.bytesTransferred / snapshot.totalBytes : null);
break;
case TaskState.success:
// TODO: Handle this case.
break;
case TaskState.canceled:
// TODO: Handle this case.
break;
case TaskState.error:
// TODO: Handle this case.
break;
}
}, onError: (e) {
// The final snapshot is also available on the status via `.snapshot`,
// this can include 2 additional states, `TaskState.error` & `TaskState.canceled`
print(status.snapshot);
});
Related
Problem: I am building an application on an RSS feed reader.
In a feed:
There are various items and each item is an article which has a URL.
Each URL has open graph metadata which needs to be fetched and takes time.
As soon as URL open graphs metadata is loaded it needs to be shown in the list on the UI.
Now I want to run 2 and 3 in parallel, am doing this in the code for now:
Stream<News> _getNewsRssFeed(Categories selectedCategory) async* {
try {
final rssUrl = _getRssUrl(selectedCategory);
RssFeed feed = await _getRssFeed(rssUrl);
if (feed.items != null) {
for (int itemIndex = 0; itemIndex < feed.items!.length; itemIndex++) {
final item = feed.items![itemIndex];
try {
Future<News> news = _processRssFeedItem(item, feed);
news.then((value){
yield value; // This is not working
});
} catch (error) {
print("Error while parsing ${item.link} error = $error");
}
}
}
} catch (error) {
print("Error while parsing RssFeed url $error");
}
}
The problematic line I have commented in above code, can you please let me know what is the best way here?
Basically, news.then returns Future and you are not awaiting for the result to be available.
You can change it by changing code to following
try {
final value = await _processRssFeedItem(item, feed);
yield value;
} catch (error) {
print("Error while parsing ${item.link} error = $error");
}
For those who have already worked on Bluetooth Low Energy on Flutter:
I am developing a mobile application. Simply, every time the user clicks on the "Read Data" button, I want to discoverServices and receive data:
onTap: () async {
deviceStateSubscription = bluetoothDevice.state.listen((s) {
if (s == BluetoothDeviceState.connected) {
_discoverServices();
} else {
bluetoothDevice.connect();
_discoverServices();
}
});
},
I have realized that connection is sometimes dropping for no reason. That is why I use an 'if/else' to check the connection.
Here is my discoverServices method:
_discoverServices() async {
List<BluetoothService> services = await bluetoothDevice.discoverServices();
if (bluetoothServices != null && bluetoothServices.isNotEmpty) {
bluetoothServices.forEach((service) {
if (service.uuid.toString().toLowerCase() == Configuration.nusUUID) {
service.characteristics.forEach((c) async {
if (c.uuid.toString() == Configuration.txUUID) {
txChar = c;
try {
await txChar!.write(Configuration.config, withoutResponse: true); // Sending the configuration
await txChar!.write(Configuration.rfCmdStart, withoutResponse: true); // Sending the start configuration
await txChar!.write(Configuration.rfCmdStop, withoutResponse: true); // Sending the stop configuration to say that I am done, so send me data now
} catch (e) {
print(e.toString());
}
} else if (c.uuid.toString() == Configuration.rxUUID) {
rxChar = c;
rxChar!.setNotifyValue(true);
rxChar!.value.listen((value) async {
if (value.isEmpty) {
print('No data received');
} else {
print(value);
}
});
}
});
}
});
}
}
The problem is, the button sometimes works and sometimes doesn't... It is not stable at all. Sometimes when I click, I receive data; and sometimes I receive Unhandled Exception: PlatformException(set_notification_error, error when writing the descriptor, null, null). I couldn't find any logical answers for that. To fix it, I am simply clicking on the button a few more times so that it sends me the data.
Any thoughts about how to fix this descriptor error?
writing the txChar characteristic with withoutResponse: true three times in a row is a problem. As the documentation for the write method states:
Writes the value of a characteristic.
CharacteristicWriteType.withoutResponse: the write is not guaranteed
and will return immediately with success.
I have a problem with Vue3+service worker+keep-alive.
I use keep-live in template
<q-page-container>
<router-view v-slot="{ Component }">
<keep-alive :include="['WorkPage']">
<component :is="Component" :key="$route.fullPath"/>
</keep-alive>
</router-view>
</q-page-container>
create queue
createWorkQueue = new Queue('createWorkQueue', {
onSync: async ( {queue} ) => {
let entry
while (entry = await queue.shiftRequest()) {
try {
await fetch(entry.request);
const channel = new BroadcastChannel('sw-messages-work');
channel.postMessage({msg: 'offline-work-uploaded'});
} catch (error) {
await queue.unshiftRequest(entry);
throw error;
}
}
}
})
addEventListener('fetch'
self.addEventListener('fetch', (event) => {
if (event.request.url.endsWith('/api/ins_new_work')) {
const bgSyncLogic = async () => {
try {
const response = await fetch(event.request.clone())
return response
} catch (error) {
await createWorkQueue.pushRequest({request: event.request})
return error
}
}
event.respondWith(bgSyncLogic())
}
})
when in offline I send form - createWorkQueue.pushRequest hangs to 5 minutes
if I delete from keep-alive - WorkPage - then pushRequest works well
but I need keep-alive page. How can I solve this?
I found!!
I use IndexedDB library and for show offline message I read from DB information
const db = await openDB('workbox-background-sync')
but in first time - table 'requests' don't create
I insert next code
const db = await openDB('workbox-background-sync', undefined, { upgrade(db) { db.createObjectStore('requests') }})
and works well
I'm using the following code to successfully poll mysite for JSON data and return that data. If the request fails, then it successfully returns an error message as well return Result.error(title:"No connection",msg:"Status code not 200", errorcode:0);.
What I'd like to happen is have the app retry the request 3 times before it returns the error message.
Basically have the future call itself for some number of iterations.
I did try to create an external function that would get called from the outer catch which then would in turn call the getJSONfromTheSite function a second and then a third time, but the problem was that you would have a non-null return from the Future so the app wouldn't accept that approach
Is there another way of doing this?
Future<Result> getJSONfromTheSite(String call) async {
debugPrint('Network Attempt by getJSONfromTheSite');
try {
final response = await http.get(Uri.parse('http://www.thesite.com/'));
if (response.statusCode == 200) {
return Result<AppData>.success(AppData.fromRawJson(response.body));
} else {
//return Result.error("Error","Status code not 200", 1);
return Result.error(title:"Error",msg:"Status code not 200", errorcode:1);
}
} catch (error) {
return Result.error(title:"No connection",msg:"Status code not 200", errorcode:0);
}
}
The following extension method will take a factory for futures, create them and try them until the retry limit is reached:
extension Retry<T> on Future<T> Function() {
Future<T> withRetries(int count) async {
while(true) {
try {
final future = this();
return await future;
}
catch (e) {
if(count > 0) {
count--;
}
else {
rethrow;
}
}
}
}
}
Assuming you have a rather plain dart method:
Future<AppData> getJSONfromTheSite(String call) async {
final response = await http.get(Uri.parse('http://www.thesite.com/'));
if (response.statusCode == 200) {
return AppData.fromRawJson(response.body);
} else {
throw Exception('Error');
}
}
You can now call it like this:
try {
final result = (() => getJSONfromTheSite('call data')).withRetries(3);
// succeeded at some point, "result" being the successful result
}
catch (e) {
// failed 3 times, the last error is in "e"
}
If you don't have a plain method that either succeeds or throws an exception, you will have to adjust the retry method to know when something is an error. Maybe use one of the more functional packages that have an Either type so you can figure out whether a return value is an error.
Inside catch() you can count how many times have you retried, if counter is less than three you return the same getJSONfromTheSite() function, but with the summed counter. And if the connection keeps failing on try{} and the counter is greater than three it will then returns the error.
Future<Result> getJSONfromTheSite(String call, {counter = 0}) async {
debugPrint('Network Attempt by getJSONfromTheSite');
try {
String? body = await tryGet();
if (body != null) {
return Result<AppData>.success(AppData.fromRawJson(response.body));
} else {
//return Result.error("Error","Status code not 200", 1);
return Result.error(title:"Error",msg:"Status code not 200", errorcode:1);
}
} catch (error) {
if(counter < 3) {
counter += 1;
return getJSONfromTheSite(call, counter: counter);
} else {
return Result.error(title:"No connection",msg:"Status code not 200", errorcode:0);
}
}
}
When I am trying to check presence of not presented element/ button. I am getting:
Jasmine timeout exception
My code like
getName(): any {
let name = element(by.id("xxxxxx"));
return name.isPresent().then((ispresent) => {
if (ispresent) {
return name.getText();
} else {
return '';
}
})
}
I am trying to access that method expect(method).toequal('');
It should run, because if not present i am expecting empty string but i am getting Jasmine timeout.. I didn't added any waits any where.
isPresent()
From the GitHub repo, ElementFinder.isPresent
isPresent(): wdpromise.Promise<boolean> {
return this.count().then((count) => {
return count > 0;
});
}
isPresent checks for a count, but does not catch if there is an error. If the count throws, we should probably return 0. Getting a text for an element that does not exist should also have throw a promise rejection.
Note: It might be better to change your method to async / await (optional).
async getName(): webdriver.promise.Promise<string> {
const name = element(by.id("xxxxxx"));
try {
return name.getText();
} catch (e) {
return '';
}
}
Or not async / await
getName(): webdriver.promise.Promise<string> {
const name = element(by.id("xxxxxx"));
return name.getText().catch(e) {
return '';
}
}
Try the below one
async getName() {
let name = element(by.id("xxxxxx"));
let value: string = '';
await name.ispresent().then((ispresent) => {
if (ispresent) {
value=name.getText();
}
});
return value;
}
Hope it helps you