Hello,
I’m developing a custom extension called DynamicListGrid for Kodular to display a dynamic list of cards populated from a JSON API . The extension supports multi-screen component detection with a dropdown for selecting the target screen and functions to list containers and click targets. However, I’m facing an issue with the designer properties for Container and ClickTarget.
What I Want to Achieve
- Current Screen Detection: When the extension is dragged or copied to a screen in the Kodular designer, the ] I have Two designer properties : Container and ClickTarget dropdowns should list components from the current screen where the extension is placed, not only from Screen1. It fetching/getting from screen1 only.
- Multi-Screen Support: The TargetScreen dropdown property dynamically lists all screens (via GetAllScreenNames), and functions like FindAllContainers and FindAllClickTargets fetch components from the selected screen at runtime.
The Problem
In the Kodular designer, when I drag or copy the DynamicListGrid extension to a screen (e.g., Screen2), the Container and ClickTarget properties only show components from Screen1 in their dropdowns. This forces me to manually use SetContainerByName and SetClickTargetByName at runtime to select components from other screens, which is inconvenient. I want these properties to automatically detect and list components from the current screen where the extension is placed in the designer.
Current Code
Here’s the relevant part of my DynamicListGrid.java (full code available if needed):
@DesignerComponent(
version = 18,
description = "Dynamic ListView with multi-screen support and screen selection",
category = ComponentCategory.EXTENSION,
nonVisible = true,
iconName = "")
@SimpleObject(external = true)
@UsesPermissions(permissionNames = "android.permission.INTERNET")
public class DynamicListGrid extends AndroidNonvisibleComponent {
private final Context context;
private AndroidViewComponent parentContainer;
private Component clickTarget;
private TinyDB tinyDB;
private ComponentContainer container;
private String targetScreen = "Screen1";
private Form targetForm;
public DynamicListGrid(ComponentContainer container) {
super(container.$form());
this.context = container.$context();
this.container = container;
this.tinyDB = new TinyDB(container.$form());
this.targetForm = container.$form(); // Default to current form
loadImageCache();
}
@DesignerProperty(
editorType = PropertyTypeConstants.PROPERTY_TYPE_COMPONENT,
defaultValue = ""
)
@SimpleProperty(description = "The container to hold the list items. For multi-screen, use SetContainerByName.")
public void Container(AndroidViewComponent container) {
this.parentContainer = container;
if (autoLoad && !apiUrl.isEmpty()) {
LoadItems();
}
}
@SimpleProperty
public AndroidViewComponent Container() {
return parentContainer;
}
@DesignerProperty(
editorType = PropertyTypeConstants.PROPERTY_TYPE_COMPONENT,
defaultValue = ""
)
@SimpleProperty(description = "Component to receive click text. For multi-screen, use SetClickTargetByName.")
public void ClickTarget(Component component) {
this.clickTarget = component;
}
@SimpleProperty
public Component ClickTarget() {
return clickTarget;
}
@DesignerProperty(
editorType = PropertyTypeConstants.PROPERTY_TYPE_CHOICES,
defaultValue = "Screen1",
editorArgs = {}
)
@SimpleProperty(description = "Select the target screen to get components from")
public void TargetScreen(String screenName) {
this.targetScreen = screenName;
updateTargetForm();
List<String> containers = FindAllContainers();
List<String> clickTargets = FindAllClickTargets();
ComponentsFound(containers.toString(), clickTargets.toString());
}
@SimpleFunction(description = "Get all available screen names")
public List<String> GetAllScreenNames() {
List<String> screenNames = new ArrayList<>();
try {
Class<?> appClass = container.$form().getClass().getSuperclass();
java.lang.reflect.Field[] fields = appClass.getDeclaredFields();
for (java.lang.reflect.Field field : fields) {
field.setAccessible(true);
Object obj = field.get(null);
if (obj instanceof Form) {
screenNames.add(field.getName());
}
}
} catch (Exception e) {
ErrorOccurred("Error getting screen names: " + e.getMessage());
}
return screenNames;
}
// ... (other methods for FindAllContainers, FindAllClickTargets, SmartAutoDetect, etc.)
}
What I’ve Tried
- Implemented Multi-Screen Support: Added TargetScreen with PROPERTY_TYPE_CHOICES and GetAllScreenNames to dynamically list all screens. This works at runtime for fetching components via SetContainerByName and SetClickTargetByName.
- Fixed Compilation Errors: Corrected syntax errors in @DesignerProperty annotations (added parentheses) and a typo in AutoLoad (changed voids to void).
- Tested Component Detection: Verified that FindAllContainers and FindAllClickTargets correctly list components from the selected TargetScreen at runtime using the ComponentsFound event.
- Checked Designer Behavior: Confirmed that dragging the extension to Screen2 still shows only Screen1 components in the Container and ClickTarget dropdowns in the designer.
Questions
- How can I make the Container and ClickTarget designer properties dynamically list components from the current screen where the extension is dragged or copied in the Kodular designer?
- Is there a specific way to configure PROPERTY_TYPE_COMPONENT in App Inventor/Kodular to fetch components from the current screen instead of Screen1?