ABausG / home_widget

Flutter Package for Easier Creation of Home Screen Widgets
780 stars 216 forks source link

Show Image in the widget #91

Open codesbyatif opened 2 years ago

codesbyatif commented 2 years ago

Is it possible to show a network image from rest api? If yes can you please specify a code for it? If no, till when can we expect this functionality to be added? Regards

milindgoel15 commented 1 year ago

So have you find any way to do this?

I followed up the same steps in google codelabs to render it but came across an error. We can render full flutter widget saved as a screenshot in the imageview.

    var path = await HomeWidget.renderFlutterWidget(
      Image.network(
        "https://openweathermap.org/img/wn/${data.currentData.icon}@4x.png",
        height: 64,
        width: 64,
      ),
      logicalSize: const Size(64, 64),
      key: "weather_image",
    );
    print(path); 

But gives

Exception has occurred.
_Exception (Exception: Failed to render the widget: Exception: Failed to save screenshot to app group container: Null check operator used on a null value)
ABausG commented 1 year ago

Yes with Network Images inside the renderFlutterWidget it would need to wait for the Network Image to be loaded. My plan is to provide a similar method of saving an Image to a path in the future. For now you could try to load the image as byte data. Convert it to base64 and then save that as a string

heygarvish commented 1 year ago

Why to convert the byte data to base64 string?

And one more thing NetworkImage is not a widget, right?

milindgoel15 commented 1 year ago

Can we also save svg images through flutter_svg package?

i am trying this way:

    var path = await HomeWidget.renderFlutterWidget(
      SvgPicture.asset(
        "assets/icons/$weatherSource/${data.currentData.icon}.svg",
        height: 64,
        width: 64,
        alignment: Alignment.center,
      ),
      logicalSize: const Size(64, 64),
      key: "weather_image",
    );

But i get same error as it did with network image.

milindgoel15 commented 1 year ago

Just an update, I have created a pull request to fix the null pointer exception.

I believe all types of images will now work. I have already tested SVG, network image, and png file asset and it works fine on my end.

One more thing, during my testing, I noticed that I had to refresh the flutter image widget by opening the app and making an API call. I have made a method that saves data coming from an API. Is there any way I could fix that?

this is a function that is used to update the data when API data is fetched.

  void updateSmallWidget(WeatherData data) {
    if (Platform.isAndroid) {

      WidgetService().updateWidget(data);
    }
  }

Can renderFlutterWidget not run in the background using the work manager plugin? Is there any way to work around this?

esDotDev commented 1 year ago

Yes with Network Images inside the renderFlutterWidget it would need to wait for the Network Image to be loaded. My plan is to provide a similar method of saving an Image to a path in the future. For now you could try to load the image as byte data. Convert it to base64 and then save that as a string

Any idea on when you might add this feature? We have a similar need to somehow show a network image in the widget.

Are there any code examples for the Base64 approach?

milindgoel15 commented 1 year ago

Any idea on when you might add this feature?

Hi, the feature already exists with the renderFlutterWidget method. For now, it was not working due to a null pointer bug but I have created a PR to fix it. Once the PR gets merged, you would be able to save network images as you would with normal icons/custom paint widgets already.

You could use a fork with the included PR till then if you wish.

esDotDev commented 1 year ago

Interesting, do you need to do anything to deal with the asynchronous download time? Or can you just render NetworkImage directly? Or maybe you're relying on a cache hit since the image has presumably already been shown/downloaded in memory?

milindgoel15 commented 1 year ago

It doesn't require any extra configurations, just declare the image.network as a widget and pass it to renderFlutterWidget.

I didn't need to add any async code to handle downloading time as flutter handled it automatically. Tho, it might take some seconds to show up. And might require you to call updateWidget(unfortunately I forgot if we needed this as it's been 2 months since I touched that).

esDotDev commented 1 year ago

I ended up trying the base64 approach and it seems to be working well.

In flutter:

final bytes = await http.readBytes(Uri.parse(imageUrl));
final imageBase64 = base64Encode(bytes);
HomeWidget.saveWidgetData<String>('lastDiscoveredImageData', imageBase64);

In swiftUi:

let userDefaults = UserDefaults(suiteName: "...")
let imageData = userDefaults?.string(forKey: "lastDiscoveredImageData") ?? ""
if(imageData.isEmpty == false) {
    let uiImage = UIImage(data: Data(base64Encoded: entry.imageData)!)
    let image = Image(uiImage: uiImage!);
    ....
}
heygarvish commented 1 year ago

for anyone who is still wondering how to load the image using Image.network() widget.

here's the code i'm using:

    Image downloadImage = Image.network(
      "https://storage.googleapis.com/cms-storage-bucket/c823e53b3a1a7b0d36a9.png",
      fit: BoxFit.contain,
      height: 1080,
      width: 1080,
    );

    final ImageStream stream =
        downloadImage.image.resolve(ImageConfiguration.empty);

    final Completer<void> completer = Completer<void>();
    stream.addListener(ImageStreamListener((image, synchronousCall) {
      completer.complete();
    }));

    await completer.future;

    final result = await HomeWidget.renderFlutterWidget(
        SizedBox(height: 1080, width: 1080, child: downloadImage),
        key: "custom-flutter-widget",
        logicalSize: const Size(1080, 1080),
        pixelRatio: WidgetsBinding
            .instance.platformDispatcher.views.first.devicePixelRatio);

    debugPrint(result);

also make sure to use @milindgoel15's PR. see that here: https://github.com/ABausG/home_widget/pull/155.