[Free] ⚠ ImageNotifier

Your blocks....

My blocks for testing

Didn't work with previous version of extension, had to move the bitmap(decodeFile) command up the chain, but still not compiling....

Btw, no issue with compiling on Niotron:

hmmm ???

I imported the same app (aia) into Niotron and compiled it with no issues.

APK works fine:

But it does not compile with AI2. It used to, but something appears to have changed with the compiler and the handling of extension code ? @ewpatton

Also not with AI2Offline:

Also fails to compile on Kodular

Yes, but almost everything on Kodular fails.
Regardless of this issue, the amount of bugs with Kodular is almost uncountable. :wink:

Anyway it works with Niotron.

I can run some tests on our end to narrow down the issue, but I'll need a complete AIA file and what should happen if everything does work correctly.

With some help from @Juan_Antonio I believe we have found the issue. He had a go at building the extension the AI2 way, and this generated an error on this line

alert.setPositiveButton("OK", (dialog, whichButton) -> 
lambda expressions are not supported in -source 1.7

it used to allow projects to compile but not now ?

I can find a different way to set the positive button.

Yay, now builds and allows projects to compile :smiley:

Thanks all for help and support, especially @Juan_Antonio :clap:

JAVA
package uk.co.metricrat.imagenotifier;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.*;
import android.graphics.*;
import android.util.*;
import android.view.*;
import android.widget.*;
import android.widget.LinearLayout;
import com.google.appinventor.components.runtime.*;
import com.google.appinventor.components.annotations.SimpleEvent;
import com.google.appinventor.components.annotations.SimpleFunction;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;

public class ImageNotifier extends AndroidNonvisibleComponent {

    private final Activity activity;

    public ImageNotifier(ComponentContainer container) {
        super(container.$form());
        this.activity = this.form.$context();
    }

    @SimpleFunction(description = "Shows a provided image and an OK button, with title and caption. Use maxSize to increase or decrease image size. A value " +
            "of 600 works well for square, portrait and landscape images. An absolute path is required to all images on the device.")
    public void ShowImageNotifier(final String title, final String imagePath, final String caption, final int maxSize) {
        Bitmap bitmapPicture = BitmapFactory.decodeFile(imagePath);
        final ImageView imageView = new ImageView(this.activity);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;
        Bitmap resizedBitmap = getResizedBitmap(bitmapPicture,maxSize);

        imageView.setImageBitmap(resizedBitmap);
        imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

        AlertDialog.Builder alert = new AlertDialog.Builder(activity);

        alert.setTitle(title);
        LinearLayout layout = new LinearLayout(activity);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.addView(imageView);
        final TextView capText = new TextView(this.activity);
        capText.setText(caption);
        capText.setGravity(Gravity.CENTER);
        layout.addView(capText);
        alert.setView(layout);
        alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                AfterImageNotifier();
            }
        });
        alert.setCancelable(false);
        alert.show();
    }

    // Event raised after the user has responded to imageNotifier.
    @SimpleEvent(description = "Event raised after the user has responded to ImageNotifier.")
    public void AfterImageNotifier() {
        EventDispatcher.dispatchEvent(this, "AfterImageNotifier");
    }

    @SimpleFunction(description = "Shows a provided base64 string as an image, an OK button, a title and a caption. Use maxSize to increase or decrease " +
            "image size. A value of 600 works well for square, portrait and landscape images.")
    public void ShowImageNotifierFromBase64String(final String title, final String base64String, final String caption, final int maxSize) {

        final ImageView imageView = new ImageView(this.activity);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 8;
        byte[] decodedString = Base64.decode(base64String, Base64.DEFAULT);
        Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
        Bitmap resizedBitmap = getResizedBitmap(decodedByte,maxSize);
        imageView.setImageBitmap(resizedBitmap);
        imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

        AlertDialog.Builder alert = new AlertDialog.Builder(activity);

        alert.setTitle(title);
        LinearLayout layout = new LinearLayout(activity);
        layout.setOrientation(LinearLayout.VERTICAL);
        layout.addView(imageView);
        final TextView capText = new TextView(this.activity);
        capText.setText(caption);
        capText.setGravity(Gravity.CENTER);
        layout.addView(capText);
        alert.setView(layout);
        alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                AfterBase64ImageNotifier();
            }
        });
        alert.setCancelable(false);
        alert.show();
    }

    // Event raised after the user has responded to base64ImageNotifier.
    @SimpleEvent(description = "Event raised after the user has responded to base64ImageNotifier.")
    public void AfterBase64ImageNotifier() {
        EventDispatcher.dispatchEvent(this, "AfterBase64ImageNotifier");
    }

    //* For resize bitmap with width and height ratio.
    public static Bitmap getResizedBitmap(Bitmap image, int maxSize) {
        int width = image.getWidth();
        int height = image.getHeight();

        float bitmapRatio = (float) width / (float) height;
        if (bitmapRatio > 1) {
            width = maxSize;
            height = (int) (width / bitmapRatio);
        } else {
            height = maxSize;
            width = (int) (height * bitmapRatio);
        }
        return Bitmap.createScaledBitmap(image, width, height, true);
    }


}


uk.co.metricrat.imagenotifierV4.aix

I'll update first post in due course. (edit, link now updated)

2 Likes

App Inventor has never allowed for lambda functions in components/extensions. In the ant build.xml for components we specify Java 7 as the source/target versions and lambdas were add in Java 8. You should use an anonymous inner class instead.

My IDE, IntelliJ Idea, suggests the notifier.java way as a problem, and to convert

alert.setPositiveButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int whichButton) {
                AfterImageNotifier();
            }
        });

to a lambda expression....

alert.setPositiveButton("OK", (dialog, whichButton) -> AfterImageNotifier());

However, as this does not compile, I have used the notifier.java method for the positive button.

In the project properties you can tell IntelliJ that the project language is Java 7 so it should stop recommending Java 8 features:

1 Like

@shreyash advises that RUSH's desugaring feature (which I did not use!) will allow lambda (JAVA8) features to run in AI2

1 Like

I wanted to get this extension. SO nice!!! Thank you​:smiley::hugs:

imagenotifier runs in companion, when compiled gives error

Runtime Error, Attempt to invoke virtual method "intandroid.graphics.getwidtih()" on a null object reference.

Are you using the latest version of the extension, available from the download link?