declex icon indicating copy to clipboard operation
declex copied to clipboard

Actions adding content to another Actions (@ExtendAction mechanism)

Open smaugho opened this issue 7 years ago • 0 comments

When working with network connections, a classical scenario it is to report to the user if any error occurred, and to dismiss some loading dialog... for instance:

        Dialog progressDialog = $ProgressDialog().message("Logging In...").dialog();

        $PutModel(login);
        if ($PutModel.Failed) {
            progressDialog.dismiss();
            $Toast("An error occurred");
        }

        progressDialog.dismiss();

Here $ProgressDialog and $Toast are actions themselves that are built inside the action mechanism of DecleX. An Extend Action mechanism would permit to reduce this code and make it clearer, for instance:

$PutModel(login).onFailed().toast("An error occurred")
                .always().dismiss(progressDialog);

For achieving this, a good approach would be that the Actions ($Toast in the first case, $ProgressDialog in the second) write to $PutModel how to make these actions and in which circumstances.

So, all the actions should have a quickActions mechanism which would permit to other actions to write specific events on them. This mechanism would be declared in the Action Holder... a possible implementation would be, in ToastActionHolder, to declare:

@ExtendAction(value="PutModel", selector="Failed")
static void toast(final PutModelActionHolder_ action, final String message) {
    final Runnable showToast = new Runnable() {
        @Override
        public void run() {
            Context context = action.getContext();
            Toast.makeText(context, text, Toast.LENGTH_LONG).show();
        }
    }
    
    final Runnable failed = action.getFailed();
    if (failed == null) {
        action.setFailed(showToast);
    } else {
        action.setFailed(new Runnable() {
            @Override
            public void run() {
                failed.run();
                showToast.run();
            }
        });
    }
}

DecleX ActionProcessor would create a method "toast" inside an action infocation method named "onFailed". (so "on" + Selector name).

About @ExtendAction

This annotation can be used in anyplace in the framework, since it is a static method, so this can be used to make libraries that add functionalities to the existing actions.

The "selector" parameter of the action can be any selector, but also it can be "always", "all" and "include"... "Always" it is a special kind of Action that would be executed in any circumstance. "All" will insert the extension in all the selectors. "Include" will include the method in the action itself, this would be the default value of "selector". An example for "include":

@ExtendAction(value="PutModel", selector="include")
static void withProgress(final PutModelActionHolder_ action, String message) {
    //Show progress dialog, and add a dismiss mechanism for when the Action $PutModel is concluded.
}

This would permit that all the code above be reduced to a simple:

$PutModel(login).withProgress("Logging In...")
                .onFailed().toast("An error occurred");

The "value" parameter of the action should be a String array, in order to permit place the extension in multiple actions at the same time.

Action can be any object compatible with the action selector (so it can be an interface, or super class), like this we can declare interfaces commons to all actions that can be used to make the extensions.. also super object for actions, but the action mechanism should be updated to read the methods of the super class.

The value paramter and the action parameter (first parameter of the method) should be checked for the validity (if the first parameter is not compatible with any of the objects in the extension, a validity error should be shown to the user).

smaugho avatar Mar 11 '17 11:03 smaugho