4646 helpUrl = "https://github.com/ysfchn/DynamicComponents-AI2/blob/main/README.md" ,
4747 iconName = "aiwebres/icon.png" ,
4848 nonVisible = true ,
49- version = 8 ,
50- versionName = "2.2.1 "
49+ version = 9 ,
50+ versionName = "2.2.2 "
5151)
5252@ SimpleObject (external = true )
5353public class DynamicComponents extends AndroidNonvisibleComponent {
@@ -58,10 +58,10 @@ public class DynamicComponents extends AndroidNonvisibleComponent {
5858 private boolean postOnUiThread = false ;
5959
6060 // Components created with Dynamic Components
61- private final HashMap <String , Component > COMPONENTS = new HashMap <String , Component >();
61+ private final HashMap <String , Component > COMPONENTS = new HashMap <String , Component >();
6262
6363 // IDs of components created with Dynamic Components
64- private final HashMap <Component , String > COMPONENT_IDS = new HashMap <Component , String >();
64+ private final HashMap <Component , String > COMPONENT_IDS = new HashMap <Component , String >();
6565
6666 private Object lastUsedId = "" ;
6767 private ArrayList <ComponentListener > componentListeners = new ArrayList <ComponentListener >();
@@ -84,11 +84,11 @@ public boolean exists(Component component) {
8484 public boolean exists (String id ) {
8585 return COMPONENTS .containsKey (id );
8686 }
87-
87+
8888 public String getClassName (Object componentName ) {
8989 String regex = "[^.$@a-zA-Z0-9]" ;
9090 String componentNameString = componentName .toString ().replaceAll (regex , "" );
91-
91+
9292 if (componentName instanceof String && componentNameString .contains ("." )) {
9393 return componentNameString ;
9494 } else if (componentName instanceof String ) {
@@ -120,7 +120,7 @@ public void newInstance(Constructor<?> constructor, String id, AndroidViewCompon
120120 } catch (Exception e ) {
121121 throw new YailRuntimeError (e .getMessage (), "DynamicComponents" );
122122 } finally {
123- if (mComponent != null ) {
123+ if (! isEmptyOrNull ( mComponent ) ) {
124124 String mComponentClassName = mComponent .getClass ().getSimpleName ();
125125 if (mComponentClassName == "ImageSprite" || mComponentClassName == "Sprite" ) {
126126 Invoke (mComponent , "Initialize" , new YailList ());
@@ -158,6 +158,16 @@ public void notifyListenersOfCreation(Component component, String id) {
158158 }
159159 }
160160
161+ public boolean isEmptyOrNull (Object item ) {
162+ if (item instanceof String ) {
163+ String mItem = item .toString ();
164+ mItem = mItem .replace (" " , "" );
165+ return mItem .isEmpty ();
166+ }
167+
168+ return item == null ;
169+ }
170+
161171 @ DesignerProperty (
162172 defaultValue = "UI" ,
163173 editorArgs = {"Main" , "UI" },
@@ -167,21 +177,25 @@ public void notifyListenersOfCreation(Component component, String id) {
167177 public void Thread (String thread ) {
168178 postOnUiThread = (thread == "UI" );
169179 }
170-
171- @ Deprecated
172- @ SimpleEvent (description = "Do NOT use this event. Use 'ComponentBuilt' as a replacement." )
173- public void ComponentCreated (String id , String type ) {
174- EventDispatcher .dispatchEvent (this , "ComponentCreated" , id , type );
175- }
176180
177181 @ SimpleEvent (description = "Is called after a component has been created." )
178- public void ComponentBuilt (Component component , String id , String type ) {
179- EventDispatcher .dispatchEvent (this , "ComponentBuilt" , component , id , type );
182+ public void ComponentBuilt (final Component component , final String id , final String type ) {
183+ new Handler (Looper .getMainLooper ()).post (new Runnable () {
184+ @ Override
185+ public void run () {
186+ EventDispatcher .dispatchEvent (DynamicComponents .this , "ComponentBuilt" , component , id , type );
187+ }
188+ });
180189 }
181190
182191 @ SimpleEvent (description = "Is called after a schema has/mostly finished component creation." )
183- public void SchemaCreated (String name , YailList parameters ) {
184- EventDispatcher .dispatchEvent (this , "SchemaCreated" , name , parameters );
192+ public void SchemaCreated (final String name , final YailList parameters ) {
193+ new Handler (Looper .getMainLooper ()).post (new Runnable () {
194+ @ Override
195+ public void run () {
196+ EventDispatcher .dispatchEvent (DynamicComponents .this , "SchemaCreated" , name , parameters );
197+ }
198+ });
185199 }
186200
187201 @ SimpleFunction (description = "Assign a new ID to a previously created dynamic component." )
@@ -220,10 +234,8 @@ public void run() {
220234 } else {
221235 UTIL_INSTANCE .newInstance (mConstructor , id , in );
222236 }
223-
224- ComponentCreated (id .toString (), mClass .getSimpleName ());
225237 } else {
226- throw new YailRuntimeError ("ID must be unique ." , "DynamicComponents" );
238+ throw new YailRuntimeError ("Expected a unique ID, got '" + id + "' ." , "DynamicComponents" );
227239 }
228240 }
229241
@@ -247,10 +259,14 @@ public Object GetComponent(String id) {
247259 public YailDictionary GetComponentMeta (Component component ) {
248260 Class <?> mClass = component .getClass ();
249261 DesignerComponent mDesignerAnnotation = mClass .getAnnotation (DesignerComponent .class );
262+ boolean mHasDesigner = !isEmptyOrNull (mDesignerAnnotation );
263+ boolean mHasObject = false ;
250264 SimpleObject mObjectAnnotation = mClass .getAnnotation (SimpleObject .class );
251265 YailDictionary mMeta = new YailDictionary ();
266+ mHasObject = !isEmptyOrNull (mObjectAnnotation );
252267
253- if (mDesignerAnnotation != null ) {
268+ if (mHasDesigner && mHasObject ) {
269+ // Return all metadata
254270 mMeta .put ("androidMinSdk" , mDesignerAnnotation .androidMinSdk ());
255271 mMeta .put ("category" , mDesignerAnnotation .category ());
256272 mMeta .put ("dateBuilt" , mDesignerAnnotation .dateBuilt ());
@@ -265,6 +281,17 @@ public YailDictionary GetComponentMeta(Component component) {
265281 mMeta .put ("type" , mClass .getSimpleName ());
266282 mMeta .put ("version" , mDesignerAnnotation .version ());
267283 mMeta .put ("versionName" , mDesignerAnnotation .versionName ());
284+ } else if (!mHasDesigner && mHasObject ) {
285+ // Return some amount of metadata even if there is no
286+ // @DesignerComponent annotation provided
287+ mMeta .put ("external" , mObjectAnnotation .external ());
288+ mMeta .put ("package" , mClass .getName ());
289+ mMeta .put ("type" , mClass .getSimpleName ());
290+ } else {
291+ // Return the least amount of metadata if no
292+ // annotation is provided
293+ mMeta .put ("package" , mClass .getName ());
294+ mMeta .put ("type" , mClass .getSimpleName ());
268295 }
269296
270297 return mMeta ;
@@ -277,15 +304,22 @@ public YailDictionary GetEventMeta(Component component) {
277304
278305 for (Method mMethod : mMethods ) {
279306 SimpleEvent mAnnotation = mMethod .getAnnotation (SimpleEvent .class );
307+ boolean mIsDeprecated = !isEmptyOrNull (mMethod .getAnnotation (Deprecated .class ));
280308 String mName = mMethod .getName ();
281309 YailDictionary mEventMeta = new YailDictionary ();
282310
283- if (mAnnotation != null ) {
311+ if (!isEmptyOrNull (mAnnotation )) {
312+ // Return all metadata
284313 mEventMeta .put ("description" , mAnnotation .description ());
285- mEventMeta .put ("isDeprecated" , ( mMethod . getAnnotation ( Deprecated . class ) != null ) );
314+ mEventMeta .put ("isDeprecated" , mIsDeprecated );
286315 mEventMeta .put ("userVisible" , mAnnotation .userVisible ());
287- mEvents .put (mName , mEventMeta );
316+ } else {
317+ // Return the least amount of metadata if no
318+ // annotation is provided
319+ mEventMeta .put ("isDeprecated" , mIsDeprecated );
288320 }
321+
322+ mEvents .put (mName , mEventMeta );
289323 }
290324
291325 return mEvents ;
@@ -298,23 +332,30 @@ public YailDictionary GetFunctionMeta(Component component) {
298332
299333 for (Method mMethod : mMethods ) {
300334 SimpleFunction mAnnotation = mMethod .getAnnotation (SimpleFunction .class );
335+ boolean mIsDeprecated = !isEmptyOrNull (mMethod .getAnnotation (Deprecated .class ));
301336 String mName = mMethod .getName ();
302337 YailDictionary mFunctionMeta = new YailDictionary ();
303338
304- if (mAnnotation != null ) {
339+ if (!isEmptyOrNull (mAnnotation )) {
340+ // Return all metadata
305341 mFunctionMeta .put ("description" , mAnnotation .description ());
306- mFunctionMeta .put ("isDeprecated" , ( mMethod . getAnnotation ( Deprecated . class ) != null ) );
342+ mFunctionMeta .put ("isDeprecated" , mIsDeprecated );
307343 mFunctionMeta .put ("userVisible" , mAnnotation .userVisible ());
308- mFunctions .put (mName , mFunctionMeta );
344+ } else {
345+ // Return the least amount of metadata if no
346+ // annotation is provided
347+ mFunctionMeta .put ("isDeprecated" , mIsDeprecated );
309348 }
349+
350+ mFunctions .put (mName , mFunctionMeta );
310351 }
311352
312353 return mFunctions ;
313354 }
314355
315356 @ SimpleFunction (description = "Returns the ID of the specified component." )
316357 public String GetId (Component component ) {
317- if (component != null || COMPONENT_IDS .containsKey (component )) {
358+ if (! isEmptyOrNull ( component ) || COMPONENT_IDS .containsKey (component )) {
318359 return COMPONENT_IDS .get (component );
319360 }
320361
@@ -331,9 +372,9 @@ public String GetName(Component component) {
331372 public int GetOrder (AndroidViewComponent component ) {
332373 View mComponent = (View ) component .getView ();
333374 int mIndex = 0 ;
334- ViewGroup mParent = (mComponent != null ? (ViewGroup ) mComponent .getParent () : null );
375+ ViewGroup mParent = (! isEmptyOrNull ( mComponent ) ? (ViewGroup ) mComponent .getParent () : null );
335376
336- if (mComponent != null && mParent != null ) {
377+ if (! isEmptyOrNull ( mComponent ) && ! isEmptyOrNull ( mParent ) ) {
337378 mIndex = mParent .indexOfChild (mComponent ) + 1 ;
338379 }
339380
@@ -352,25 +393,28 @@ public YailDictionary GetPropertyMeta(Component component) {
352393
353394 for (Method mMethod : mMethods ) {
354395 DesignerProperty mDesignerAnnotation = mMethod .getAnnotation (DesignerProperty .class );
396+ boolean mHasDesigner = !isEmptyOrNull (mDesignerAnnotation );
397+ boolean mHasProperty = false ;
355398 SimpleProperty mPropertyAnnotation = mMethod .getAnnotation (SimpleProperty .class );
356399 String mName = mMethod .getName ();
357400 YailDictionary mPropertyMeta = new YailDictionary ();
358- Object mValue = Invoke (component , mName , new YailList ());;
401+ Object mValue = Invoke (component , mName , new YailList ());
402+ mHasProperty = !isEmptyOrNull (mPropertyAnnotation );
359403
360- if (mPropertyAnnotation != null ) {
404+ if (mHasProperty ) {
361405 mPropertyMeta .put ("description" , mPropertyAnnotation .description ());
362406 mPropertyMeta .put ("category" , mPropertyAnnotation .category ());
363407
364- if (mDesignerAnnotation != null ) {
408+ if (mHasDesigner ) {
365409 YailDictionary mDesignerMeta = new YailDictionary ();
366410 mDesignerMeta .put ("defaultValue" , mDesignerAnnotation .defaultValue ());
367411 mDesignerMeta .put ("editorArgs" , mDesignerAnnotation .editorArgs ());
368412 mDesignerMeta .put ("editorType" , mDesignerAnnotation .editorType ());
369413 mPropertyMeta .put ("designer" , mDesignerMeta );
370414 }
371415
372- mPropertyMeta .put ("isDeprecated" , (mMethod .getAnnotation (Deprecated .class ) != null ));
373- mPropertyMeta .put ("isDesignerProperty" , ( mDesignerAnnotation != null ) );
416+ mPropertyMeta .put ("isDeprecated" , (! isEmptyOrNull ( mMethod .getAnnotation (Deprecated .class )) ));
417+ mPropertyMeta .put ("isDesignerProperty" , mHasDesigner );
374418 mPropertyMeta .put ("userVisible" , mPropertyAnnotation .userVisible ());
375419 mPropertyMeta .put ("value" , mValue );
376420 mProperties .put (mName , mPropertyMeta );
@@ -382,7 +426,7 @@ public YailDictionary GetPropertyMeta(Component component) {
382426
383427 @ SimpleFunction (description = "Invokes a method with parameters." )
384428 public Object Invoke (Component component , String name , YailList parameters ) {
385- if (component != null ) {
429+ if (! isEmptyOrNull ( component ) ) {
386430 Object mInvokedMethod = null ;
387431 Method [] mMethods = component .getClass ().getMethods ();
388432
@@ -412,7 +456,7 @@ public Object Invoke(Component component, String name, YailList parameters) {
412456 } catch (Exception e ) {
413457 throw new YailRuntimeError (e .getMessage (), "DynamicComponents" );
414458 } finally {
415- if (mInvokedMethod != null ) {
459+ if (! isEmptyOrNull ( mInvokedMethod ) ) {
416460 return mInvokedMethod ;
417461 } else {
418462 return "" ;
@@ -442,7 +486,7 @@ public String ListDetails(Component component) {
442486 @ SimpleFunction (description = "Moves the specified component to the specified view." )
443487 public void Move (AndroidViewComponent arrangement , AndroidViewComponent component ) {
444488 View mComponent = (View ) component .getView ();
445- ViewGroup mParent = (mComponent != null ? (ViewGroup ) mComponent .getParent () : null );
489+ ViewGroup mParent = (! isEmptyOrNull ( mComponent ) ? (ViewGroup ) mComponent .getParent () : null );
446490
447491 mParent .removeView (mComponent );
448492
@@ -462,7 +506,7 @@ public String RandomUUID() {
462506 public void Remove (String id ) {
463507 Object component = COMPONENTS .get (id );
464508
465- if (component != null ) {
509+ if (! isEmptyOrNull ( component ) ) {
466510 try {
467511 Method mMethod = component .getClass ().getMethod ("getView" );
468512 final View mComponent = (View ) mMethod .invoke (component );
@@ -481,7 +525,7 @@ public void run() {
481525 } catch (Exception e ) {
482526 e .printStackTrace ();
483527 }
484-
528+
485529 COMPONENTS .remove (id );
486530 COMPONENT_IDS .remove (component );
487531 }
@@ -525,12 +569,12 @@ public void Schema(AndroidViewComponent in, final String template, final YailLis
525569 JSONObject mScheme = new JSONObject (template );
526570 String newTemplate = template ;
527571
528- if (!template . replace ( " " , "" ). isEmpty ( ) && mScheme .has ("components" )) {
572+ if (!isEmptyOrNull ( template ) && mScheme .has ("components" )) {
529573 propertiesArray = new JSONArray ();
530574
531575 JSONArray mKeys = (mScheme .has ("keys" ) ? mScheme .getJSONArray ("keys" ) : null );
532576
533- if (mKeys != null && mKeys .length () == parameters .length () - 1 ) {
577+ if (! isEmptyOrNull ( mKeys ) && mKeys .length () == parameters .length () - 1 ) {
534578 for (int i = 0 ; i < mKeys .length (); i ++) {
535579 String keyPercent = "%" + mKeys .getString (i );
536580 String keyBracket = "{" + mKeys .getString (i ) + "}" ;
@@ -563,8 +607,8 @@ public void onCreation(Component component, String id) {
563607
564608 for (int k = 0 ; k < keys .length (); k ++) {
565609 Invoke (
566- (Component ) GetComponent (mId ),
567- keys .getString (k ),
610+ (Component ) GetComponent (mId ),
611+ keys .getString (k ),
568612 YailList .makeList (new Object [] {
569613 mProperties .get (keys .getString (k ))
570614 })
@@ -577,7 +621,7 @@ public void onCreation(Component component, String id) {
577621 };
578622
579623 componentListeners .add (listener );
580-
624+
581625 Create (mRoot , mType , mId );
582626 }
583627
0 commit comments