loading spinner with image_picker_web (FLUTTER-WEB) - flutter

How can I incorporate a loading spinner in a image_picker_web application that only triggers as an image is selected?
The best I have been able to do is a spinner triggered by the 'select image' button, as below, but this shows a spinner when the the directory is opened i.e. before anything is selected, I need it to trigger when the user selects an image and hits 'open' in the directory.
Image pickedImage;
bool isWaiting = false;
pickImage() async {
setState(() {
isWaiting = true;
});
Image fromPicker =
await ImagePickerWeb.getImage(outputType: ImageType.widget);
if (fromPicker != null) {
setState(() {
isWaiting = false;
pickedImage = fromPicker;
});
}
}
RaisedButton(
onPressed: () => pickImage(),
child: isWaiting
? SizedBox(child: Image.asset('assets/spinner.gif'))
: Text('Select Image'),
),
(adapted from the original example: https://pub.dev/packages/image_picker_web/example)

You can use the default material CircularProgressIndicator(), if you want.
If you want it a little more colorful with google color accents, you can go with my ColoredCircularProgressIndicator() package.
If you want a custom spinner then you have to definitely go with this awesome package - flutter_spinkit
Your implementation is correct, you can also use GestureDetector with Material widget for input button customizations.
EDIT -
As mentioned in comment, if you want the spinner to kick-in AFTER the image is picked, you can use then() from getImage's future and a void callback to achieve this.
Image fromPicker = await ImagePickerWeb.getImage(outputType: ImageType.widget).then(() => /* do something after image is picked (change widget to spinner in setState) */ );
I really don't know why you want to kick-in the spinner AFTER not before.
Also, image_picker_web package is now deprecated so use the image_picker package with web check.

Related

Uploading image into Floating Action Button, set state not working

I have a floating action button that I want a user to click to take a picture with their camera and then have that image replace the camera icon on the floating action bar button.
Here is the code for my FAB, and including uploading the image to firestore storage.
floatingActionButton: FloatingActionButton.large(
heroTag: "add image",
backgroundColor: const Color(0xFF93C3B9),
child: (imageURL == ' ')
? const Icon(Icons.add_a_photo_outlined)
: Image.network(imageURL),
//open add gear page
onPressed: () async {
// todo: upload an image to Firebase Storage
//Take picture
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(source: ImageSource.camera);
if (file == null) return;
String uniqueFileName =
DateTime.now().millisecondsSinceEpoch.toString();
//Get reference to storage root
Reference referenceRoot = FirebaseStorage.instance.ref();
Reference referenceDirImages = referenceRoot.child('images/$userID');
Reference referenceImageToUpload =
referenceDirImages.child(uniqueFileName);
try {
//upload image
await referenceImageToUpload.putFile(File(file.path));
//get download URL
setState(() async {
imageURL = await referenceImageToUpload.getDownloadURL();
print(imageURL);
});
//upload path to fireStore database
} catch (error) {}
},
),
After the image uploads it's like the set state is not working to replace the icon with the image. The odd part is is I crtl-s and save in Visual Studio Code then the widgets seem to rebuild and then the image is visible there...
So after playing around with my code a bit I decided to edit the above code and take tha await function out of the setState() and make setState() not async anymore:
//get download URL
String tempUrl = await referenceImageToUpload.getDownloadURL();
setState(() {
print("--------- Set State -----------");
imageURL = tempUrl;
print("--------- Set State end -----------");
});
print("New image url $imageURL ------------");
not sure why it works, but this solves my issue.
By your description of the issue, I think you might be using StatelessWidget instead of StatefulWidget.
You see the button change when performing a hotreload because the value of imageURL is correctly changing internally, but you need a StatefulWidget to update the UI also.
Hope it helps!

How to identify if the controls has gone or not in flutter chewie video player

I am working on a flutter app and using chewie videoplayer plugin.So when we started playing a video it shows controls at bottom and after few seconds it vanishes and when we move the mouse again it shows again. so is there any method to find when the controls are shown on screen and when its not shown.
actually i am giving close button on the video player. but it doesnt vanishes with those video player controls. it still stay on screen so to hide that close button along with video controls i need to get which process hides the control.
Please help me...
This process is inside the source code of chewie player. So if you need to customize and synchronise your own custom controls and options, either you have to explicitly fetch the source code and edit in that or you need to make your own controllers from scratch using video_player package as the core.
You need to customize the source code of the chewie player.
You can find MaterialControl class inside the source code of this package there is a function called _buildHitArea() just change notifier.hideStuff boolean according to your preference.
Widget _buildHitArea() {
final bool isFinished = _latestValue.position >= _latestValue.duration;
final bool showPlayButton = widget.showPlayButton && !_dragging && !notifier.hideStuff;
return GestureDetector(
onTap: () {
if (_latestValue.isPlaying) {
if (_displayTapped) {
setState(() {
notifier.hideStuff = false;
});
} else {
_cancelAndRestartTimer();
}
} else {
_playPause();
setState(() {
notifier.hideStuff = false;
});
}
},
child: CenterPlayButton(
backgroundColor: Colors.black54,
iconColor: Colors.white,
isFinished: isFinished,
isPlaying: controller.value.isPlaying,
show: showPlayButton,
onPressed: _playPause,
),
);
}

Flutter remove image after upload using image_picker package

I have managed to upload an image using the image picker package as shown below:
final picker = ImagePicker();
Future selectPhoto() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_image = File(pickedFile.path);
});
}
The image has been displayed on the device where I have a remove button which I can use to remove the image and upload another before saving it.
child: Container(
height: height * 0.2,
width: width * 0.2,
child: Image.file(
_image,
fit: BoxFit.fill,
),
),
My question is how can I remove the image from cache as this piece is not working
onTap: () {
setState(() {
imageCache.clear();
print('removes $_image');
});
},
You have a misunderstanding of what the cache is compared to explicitly storing a file in memory with your code. Flutter may store images that you use in widgets in a cache so that they may load faster in the future. imageCache.clear(); does clear the cache and is likely doing it's work in your code. However, your method of checking if the image is still cached is flawed.
imageCache.clear(); only clears the cache, it does not delete the file that you're passing to the Image.file widget. This means that _image(the file variable you have stored in memory) will persist even over the cache clearing. To truly delete this image you could use the delete method or if you just want to stop showing the image, deference the file by setting the file reference to null:
_image = null;
Solved it by calling a method within the button which had set state method where the path was returned back to null
clearimage() {
setState(() {
_image = null;
});
}

Flutter and translated buttons for showAboutDialog

I have a button to display info about my app that works fine:
onTap: () async {
PackageInfo packageInfo = await PackageInfo.fromPlatform();
return showAboutDialog(
context: context,
applicationName: translate('title'),
applicationVersion: packageInfo.version,
children: [
Image(
image: AssetImage('assets/images/brand/icon.jpg'),
height: 100,
),
],
);
},
The problem is that the "View licenses" and "Close" buttons are not translated on real time. I need to refresh the whole app to get them translated:
(check that the language was updated but the buttons still not in English)
And this is the code that make the language change:
onChanged: (String newLang) async {
// update dropdown language
_language = newLang;
// update app language
changeLocale(context, newLang);
// save language
final options = json.decode(_prefs.get('options'));
options["language"] = newLang;
_prefs.setString('options', json.encode(options));
Provider.of<MyRents>(context, listen: false)
.updateLanguage(newLang);
},
The showAboutDialog() method will always display two buttons in the system's language (for you that seems to be Spanish). If you want a different behaviour, you will have to develop a custom dialog

How to hide alertDialog after one second with Navigator.of(context).pop()

I am trying to auto-hide an alertDialog after one second
This is the code:
Widget popupWidget(BuildContext context, ...) {
Future.delayed(Duration(seconds: 1), () {
Navigator.of(context).pop();
});
return AlertDialog(...);}
What works:
I can click somewhere else on the screen to close the alertDialog
I can wait for one second and it closes automatically
The bug:
If, after (exactly?) one second, I click somewhere else on the screen (which closes the alertDialog), the Future.delayed(...) will not hide the alertDialog, but the whole screen
I unsuccessfully tried making showDialog async, also tried the line
Navigator.of(context, rootNavigator: true).pop();
I think I've found a workaround with:
bool popupIsActive = true;
Future.delayed(Duration(seconds: 1), () {
if (popupIsActive) Navigator.of(context).pop();
});
and
showDialog(...).then((_) {
popupIsActive = false;
});
You might want to ignore any taps outside the dialog in order to prevent it from dismissing and just wait for the future to complete. You can set barrierDismissible to false in showDialog().