[FREE] 🍗 DaffyMenu - Popup Menus For Your Components!

:computer: Introduction

A non-visible extension that creates popup menus.

:clock8: Version: 1

:package: Package name: com.gordonlu.daffymenu

:date: Release date: 2022-03-31T12:30:00Z

Shout-out to AI2 Popup Menu Extension, I took reference from this extension.

:open_book: Documentation

Event blocks

Dismiss

image

This event is fired when the user has dismissed a popup menu.

Parameters: id = numbr (int)

ItemSelected

image

This event is fired when the user has selected an item in a popup menu.

Parameters: id = number (int), item = text

Method blocks

CreateMenu

image

Creates a popup menu with the given items and shows it next to the given component.

Parameters: id = number (int), items = list, component = component

Property blocks

AlignHorizontal (designer, blocks, read, write)

image

image

image

This property specifies the horizontal alignment of the popup menu. 1 is left, 2 is center, 3 is right, and 0 is no gravity.

Accepts: number (int)

AlignVertical (designer, blocks, read, write)

image

image

image

This property specifies the vertical alignment of the popup menu. 1 is top, 2 is center, 3 is bottom, and 0 is no gravity.

Accepts: number (int)

HtmlFormat

image

image

image

This property specifies whether HTML format should be enabled for the text of the popup menu. For example, an item with HTML enabled that has its text as <b>Test will result in a bold Test. Note that if you have HTML enabled and that user selects the <b>Test item, the event will only give you Test as the item selected.

Accepts: boolean

:bookmark: Why this extension?

As you know, we have a lot of popup menu extensions currently available.

However, what's special about this extension is that you can enable/disable HTML for your popup texts, so you can not just set the color of the text, but also size, strikethrough, bold, underline, italic, etc. This extension also has ID support, so you can create 2+ menus with the same extension!

:inbox_tray: Downloads

AIX:
com.gordonlu.daffymenu.aix (10.6 KB)

:lock: Open Source

Here you go, have fun.

package com.gordonlu.daffymenu;

import android.app.Activity;
import android.content.Context;
import com.google.appinventor.components.annotations.*;
import com.google.appinventor.components.common.ComponentCategory;
import com.google.appinventor.components.runtime.AndroidNonvisibleComponent;
import com.google.appinventor.components.runtime.ComponentContainer;
import com.google.appinventor.components.runtime.EventDispatcher;

import com.google.appinventor.components.common.PropertyTypeConstants;
import com.google.appinventor.components.annotations.DesignerComponent;
import com.google.appinventor.components.annotations.DesignerProperty;
import com.google.appinventor.components.annotations.PropertyCategory;

import android.widget.PopupMenu.OnMenuItemClickListener;
import android.widget.PopupMenu.OnDismissListener;
import android.widget.PopupMenu;
import android.view.View;
import com.google.appinventor.components.runtime.AndroidViewComponent;
import com.google.appinventor.components.runtime.util.YailList;
import android.view.MenuItem;
import android.text.Html;
import android.os.Build;

import android.view.Gravity;

@DesignerComponent(
        version = 1,
        description = "A non-visible extension that creates popup menus.",
        category = ComponentCategory.EXTENSION,
        nonVisible = true,
        iconName = "https://docs.google.com/drawings/d/e/2PACX-1vQCI87PHLBF0jb8QWyYmIRQSjjNW3EFXf-qpsWCvBYkUQ9vEgPAB8SpxcMpblxNpbIYrjCjLrRLIU2c/pub?w=16&h=16")

@SimpleObject(external = true)
//Libraries
@UsesLibraries(libraries = "")
//Permissions
@UsesPermissions(permissionNames = "")

public class DaffyMenu extends AndroidNonvisibleComponent {

    //Activity and Context
    private Context context;
    private Activity activity;

    public boolean check = true;
    public boolean html = false;
    public int horizontal = 1;
    public int vertical = 1;

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

    @SimpleFunction(description = "Creates a popup menu with the given items and shows it next to the given component.")
    public void CreateMenu(final int id, YailList items, AndroidViewComponent component) {
        View view = component.getView();
        PopupMenu menu = new PopupMenu (this.context, view);
        if (!html) {
            for (int i = 1; i < items.size() + 1; i++) {
            menu.getMenu().add(String.valueOf(items.get(i)));
            }
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                for (int i = 1; i < items.size() + 1; i++) {
                    menu.getMenu().add(Html.fromHtml(String.valueOf(items.get(i)), Html.FROM_HTML_MODE_COMPACT));
                } 
            } else { 
                for (int i = 1; i < items.size() + 1; i++) {
                    menu.getMenu().add(Html.fromHtml(String.valueOf(items.get(i))));
                } 
            }           
        }
        int av = 48;
        if (vertical == 1) {
            av = 48;
        } else if (vertical == 2) {
            av = 17;
        } else if (vertical == 3) {
            av = 80;
        } else if (vertical == 0) {
            av = 0;
        } else {
            av = 48;
        }
        if (horizontal == 1) {
            menu.setGravity(Gravity.LEFT | av);
        } else if (horizontal == 2) {
            menu.setGravity(Gravity.CENTER | av);
        } else if (horizontal == 3) {
            menu.setGravity(Gravity.RIGHT | av);
        } else if (horizontal == 0) {
            menu.setGravity(0 | av);
        } else {
            menu.setGravity(Gravity.LEFT | av);
        }
        menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
            @Override
            public boolean onMenuItemClick(MenuItem menuItem) {
                ItemSelected(id, String.valueOf(menuItem.getTitle()));
                check = false;
                return true;
                }
            });
        menu.setOnDismissListener(new PopupMenu.OnDismissListener() {
            @Override
            public void onDismiss(PopupMenu menu) {
                if (check) {
                    Dismiss(id);
                }
                check = true;
                }
            });
        menu.show();
    }

    @SimpleEvent(description = "This event is fired when the user has selected an item in a popup menu.")
    public void ItemSelected(int id, String item) {
        EventDispatcher.dispatchEvent(this, "ItemSelected", id, item);
    }

    @SimpleEvent(description = "This event is fired when the user has dismissed a popup menu.")
    public void Dismiss(int id) {
        EventDispatcher.dispatchEvent(this, "Dismiss", id);
    }

    @SimpleProperty(category = PropertyCategory.APPEARANCE, description = "This property specifies whether HTML format should be enabled for the text of the" + 
    " popup menu.")
    public boolean HtmlFormat() {
        return html;
    }

    @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_BOOLEAN, defaultValue = "false")
    @SimpleProperty(description = "This property specifies whether HTML format should be enabled for the text of the popup menu.")
    public void HtmlFormat(boolean h) {
    html = h;
  }

    @SimpleProperty(category = PropertyCategory.APPEARANCE, description = "This property specifies the horizontal alignment of the popup menu." + 
    " 1 is left, 2 is center and 3 is right. 0 is no gravity.")
    public int AlignHorizontal() {
        return horizontal;
    }

    @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_HORIZONTAL_ALIGNMENT, defaultValue = "1")
    @SimpleProperty(description = "This property specifies the horizontal alignment of the popup menu. 1 is left, 2 is center and 3 is right. 0 is no gravity.")
    public void AlignHorizontal(int h) {
    horizontal = h;
  }

    @SimpleProperty(category = PropertyCategory.APPEARANCE, description = "This property specifies the vertical alignment of the popup menu." + 
    " 1 is top, 2 is center and 3 is bottom. 0 is no gravity.")
    public int AlignVertical() {
        return vertical;
    }

    @DesignerProperty(editorType = PropertyTypeConstants.PROPERTY_TYPE_VERTICAL_ALIGNMENT, defaultValue = "1")
    @SimpleProperty(description = "This property specifies the vertical alignment of the popup menu. 1 is top, 2 is center and 3 is bottom. 0 is no gravity.")
    public void AlignVertical(int h) {
    vertical = h;
  }

}

:+1: Rate my extension! :-1:

  • Good extension!
  • Bad extension.
0 voters

Made with Niotron IDE.

Kindly :email: PM me if you have any questions! Also, if you like my extension, please :heart: like it! It takes some effort for me to make it...

Votes and likes tell me the general user feedback of my extension. If you read this extension, please take 20 seconds to drop by and give a vote / like!

If you have any features that you want to add and you know the code, PM me or directly reply below using the image button.

If you find any :lady_beetle: bugs, please reply below.


Gordon Lu

:speech_balloon: Message :earth_africa: Website :e-mail: E-mail

15 Likes

This ALL already done here:

2 Likes

I have used that extension for some time, and took that extension as reference. That extension does have a lot of functions that this one, unfortunately, that extension does not have the function to detect whether the user has dismissed the popup (when it is necessary), nor it has functions to set the gravity.

Glad to see your additional features you provided for a popup menu. Both you and Ulli share valuable open source extensions from which extension developers can learn. App Inventor is a learning tool.

There are many ways to code a Procedure with Blocks. Often community members post alternate code that produces a similar result. Anyone is free to chose the solution that works best for them for a Block algorithm or extension :slight_smile: .

3 Likes

Strange that you did not reference it in your original post then ?

1 Like

Woops, I forgot. Added it.

@gordonlu310
image

these options doesn't seems to be working for me. please help what can I do

The gravity also depends on your button location. For example, if your button is at the bottom of the screen, even though if you set AlignVertical to Bottom, the popup may still show above the button. For HtmlFormat, you cannot use tags like <p style="font-size:30px">. Remember: you have to set the properties before you show the menu.

1 Like

Also is there any way to set it to dark theme? can you make another extension just like you gave me one for daffy dialog??

Can you try that extension I sent you earlier?

I tried it just now it isn't allowing me to use text to set dark or light how should I use it??

Edit: No need I decided to use timai's extension it's just amazing.

Hmmm...can you show your blocks? It is working fine for me here.

image image

Demo:

blocks (1)

Video:

AIA:

Test.aia (15.5 KB)

3 Likes

yes it works now perfectly. :slight_smile:

Nice


1 Like

There's one cool thing that in one ui this type of dialogs are on title bar only in others and in stock android this popup comes a bit down.
Here you go:

One Ui

image

Stock Android 12

In a PM you asked me what is gravity. Gravity is the location of the popup. For example, if you have set AlignVertical to Bottom, the popup will show below the button. However, if you have the button at the very low position of the screen, it still may not show the gravity as bottom.

1 Like

but gravity doesn't even works on a12 and in one ui also it looks same.

As I said, there is no gravity the popup will show exactly where you want. The system will also decide automatically.

Sorry one question, why in some cases the pop up shows in a "square" shape and in others in a more rounded way? I would like to use the rounded but when apply in my project it shows square style, and if I open your test.aia it shows rounded, it may be some configuration?

No this extension gives same rounded in both companion and apk,

Can you confirm in which you faced the issue?
Companion or Build apk