From a7ce6e50695d05ddb546203159149c2cb237dc04 Mon Sep 17 00:00:00 2001 From: "roman.donchenko" Date: Wed, 8 Feb 2017 19:54:15 +0200 Subject: [PATCH] add ActionFireInterceptor --- actionhandler/build.gradle | 4 +- .../actionhandler/ActionHandler.java | 117 ++++++++++++++---- .../actionhandler/action/BaseAction.java | 44 +++++++ .../actionhandler/action/CompositeAction.java | 25 ++-- .../listener/ActionFireInterceptor.java | 43 +++++++ .../listener/ActionInterceptor.java | 4 +- 6 files changed, 204 insertions(+), 33 deletions(-) create mode 100644 actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionFireInterceptor.java diff --git a/actionhandler/build.gradle b/actionhandler/build.gradle index b0da345..c3fbfaa 100644 --- a/actionhandler/build.gradle +++ b/actionhandler/build.gradle @@ -1,9 +1,9 @@ apply plugin: 'com.android.library' ext { - libraryVersionRevision = 0 - libraryVersionMinor = 0 libraryVersionMajor = 1 + libraryVersionMinor = 0 + libraryVersionRevision = 1 libraryVersion = libraryVersionMajor + '.' + libraryVersionMinor + '.' + libraryVersionRevision diff --git a/actionhandler/src/main/java/com/drextended/actionhandler/ActionHandler.java b/actionhandler/src/main/java/com/drextended/actionhandler/ActionHandler.java index 84accab..680d388 100644 --- a/actionhandler/src/main/java/com/drextended/actionhandler/ActionHandler.java +++ b/actionhandler/src/main/java/com/drextended/actionhandler/ActionHandler.java @@ -23,6 +23,7 @@ import com.drextended.actionhandler.action.BaseAction; import com.drextended.actionhandler.action.Cancelable; import com.drextended.actionhandler.listener.ActionClickListener; +import com.drextended.actionhandler.listener.ActionFireInterceptor; import com.drextended.actionhandler.listener.ActionInterceptor; import com.drextended.actionhandler.listener.OnActionDismissListener; import com.drextended.actionhandler.listener.OnActionErrorListener; @@ -37,7 +38,7 @@ /** * Use ActionHandler to manage action and bind them to view */ -public class ActionHandler implements ActionClickListener, OnActionFiredListener, OnActionErrorListener, OnActionDismissListener { +public class ActionHandler implements ActionClickListener, OnActionFiredListener, OnActionErrorListener, OnActionDismissListener, ActionFireInterceptor { // Actions which was added to the handler protected final List mActions; @@ -51,9 +52,13 @@ public class ActionHandler implements ActionClickListener, OnActionFiredListener // Callbacks to be invoked when an action is executed but dismissed protected Set mOnActionDismissListeners; + // Callback to be invoked right before specific action will be fired. + // Can intercept an action to prevent it to be fired + protected Set mActionFireInterceptors; + // Callback to be invoked after a view with an action is clicked and before action handling started. // Can intercept an action to prevent it to be fired - private List mActionInterceptors; + private Set mActionInterceptors; /** * @param actions list of actions to handle by this handler @@ -67,6 +72,7 @@ protected ActionHandler(List actions) { baseAction.addActionFiredListener(this); baseAction.addActionErrorListener(this); baseAction.addActionDismissListener(this); + baseAction.addActionFireInterceptor(this); } } } @@ -191,16 +197,6 @@ public void removeAllActionDismissListeners() { } } - /** - * Remove all callbacks for action intercept, fire, error and dismiss events - */ - public void removeAllActionListeners() { - removeAllActionFiredListeners(); - removeAllActionDismissListeners(); - removeAllActionInterceptors(); - removeAllActionErrorListeners(); - } - /** * Set new callback to be invoked after a view with an action is clicked and before action handling started. * Can intercept an action to prevent it to be fired @@ -219,14 +215,14 @@ public void setActionInterceptor(ActionInterceptor actionInterceptor) { } /** - * Add new callback to be invoked after a view with an action is clicked and before action handling started. - * Can intercept an action to prevent it to be fired + * Add new callback to be invoked after a view with an action is clicked and before action type handling started. + * Can intercept an action type to prevent it to be handled * - * @param actionInterceptor The interceptor, which can prevent actions to be fired + * @param actionInterceptor The interceptor, which can prevent action type to be handled */ public void addActionInterceptor(ActionInterceptor actionInterceptor) { if (mActionInterceptors == null) { - mActionInterceptors = new ArrayList<>(1); + mActionInterceptors = new HashSet<>(1); } mActionInterceptors.add(actionInterceptor); } @@ -238,12 +234,12 @@ public void addActionInterceptor(ActionInterceptor actionInterceptor) { */ public void removeActionInterceptor(ActionInterceptor actionInterceptor) { if (mActionInterceptors != null) { - mActionInterceptors.clear(); + mActionInterceptors.remove(actionInterceptor); } } /** - * Remove all interceptors + * Remove all action interceptors */ public void removeAllActionInterceptors() { if (mActionInterceptors != null) { @@ -251,6 +247,50 @@ public void removeAllActionInterceptors() { } } + /** + * Add new callback to be invoked right before specific action will be fired.. + * Can intercept an action to prevent it to be fired + * + * @param actionFireInterceptor The interceptor, which can prevent action to be fired + */ + public void addActionFireInterceptor(ActionFireInterceptor actionFireInterceptor) { + if (mActionFireInterceptors == null) { + mActionFireInterceptors = new HashSet<>(1); + } + mActionFireInterceptors.add(actionFireInterceptor); + } + + /** + * Remove action fire interceptor + * + * @param actionFireInterceptor The interceptor to remove + */ + public void removeActionFireInterceptor(ActionFireInterceptor actionFireInterceptor) { + if (mActionFireInterceptors != null) { + mActionFireInterceptors.remove(actionFireInterceptor); + } + } + + /** + * Remove all action fire interceptors + */ + public void removeAllActionFireInterceptors() { + if (mActionFireInterceptors != null) { + mActionFireInterceptors.clear(); + } + } + + /** + * Remove all callbacks for action intercept, fire, error and dismiss events + */ + public void removeAllActionListeners() { + removeAllActionFiredListeners(); + removeAllActionDismissListeners(); + removeAllActionInterceptors(); + removeAllActionFireInterceptors(); + removeAllActionErrorListeners(); + } + @Override public void onActionFired(View view, String actionType, Object model) { if (mOnActionFiredListeners != null) { @@ -278,6 +318,11 @@ public void onActionDismiss(String reason, View view, String actionType, Object } } + @Override + public boolean onInterceptActionFire(Context context, View view, String actionType, Object model, Action action) { + return interceptActionFire(context, view, actionType, model, action); + } + /** * Check if there is at least one action that can try to handle {@code actionType} * @@ -327,6 +372,7 @@ public void fireAction(Context context, View view, String actionType, Object mod if (actionPair.actionType == null || actionPair.actionType.equals(actionType)) { final Action action = actionPair.action; if (action != null && action.isModelAccepted(model)) { + if (interceptActionFire(context, view, actionType, model, action)) continue; //noinspection unchecked action.onFireAction(context, view, actionType, model); } @@ -334,6 +380,15 @@ public void fireAction(Context context, View view, String actionType, Object mod } } + private boolean interceptActionFire(Context context, View view, String actionType, Object model, Action action) { + if (mActionFireInterceptors != null) { + for (ActionFireInterceptor interceptor : mActionFireInterceptors) { + if (interceptor.onInterceptActionFire(context, view, actionType, model, action)) return true; + } + } + return false; + } + /** * Call this method to force actions to cancel. * Usually, you may need to call this on Activity destroy to free resources which @@ -362,7 +417,8 @@ public static final class Builder { private Set mActionFiredListeners; private Set mActionErrorListeners; private Set mActionDismissListeners; - private List mActionInterceptors; + private Set mActionInterceptors; + private Set mActionFireInterceptors; public Builder() { mActions = new ArrayList<>(); @@ -452,19 +508,33 @@ public Builder setActionInterceptor(ActionInterceptor actionInterceptor) { } /** - * Add callback to be invoked after a view with an action is clicked and before action handling started. - * Can intercept an action to prevent it to be fired + * Add callback to be invoked after a view with an action is clicked and before action type handling started. + * Can intercept an action type to prevent it to be handled * * @param actionInterceptor The interceptor, which can prevent actions to be fired */ public Builder addActionInterceptor(ActionInterceptor actionInterceptor) { if (mActionInterceptors == null) { - mActionInterceptors = new ArrayList<>(1); + mActionInterceptors = new HashSet<>(1); } mActionInterceptors.add(actionInterceptor); return this; } + /** + * Add callback to be invoked before specific action will be fired. + * Can intercept an action to prevent it to be fired + * + * @param actionFireInterceptor The interceptor, which can prevent actions to be fired + */ + public Builder addActionFireInterceptor(ActionFireInterceptor actionFireInterceptor) { + if (mActionFireInterceptors == null) { + mActionFireInterceptors = new HashSet<>(1); + } + mActionFireInterceptors.add(actionFireInterceptor); + return this; + } + public ActionHandler build() { final ActionHandler actionHandler = new ActionHandler(mActions); if (mActionFiredListeners != null) { @@ -479,6 +549,9 @@ public ActionHandler build() { if (mActionInterceptors != null && mActionInterceptors.size() > 0) { actionHandler.mActionInterceptors = mActionInterceptors; } + if (mActionFireInterceptors != null && mActionFireInterceptors.size() > 0) { + actionHandler.mActionFireInterceptors = mActionFireInterceptors; + } return actionHandler; } } diff --git a/actionhandler/src/main/java/com/drextended/actionhandler/action/BaseAction.java b/actionhandler/src/main/java/com/drextended/actionhandler/action/BaseAction.java index 3d206b5..43b5fc4 100644 --- a/actionhandler/src/main/java/com/drextended/actionhandler/action/BaseAction.java +++ b/actionhandler/src/main/java/com/drextended/actionhandler/action/BaseAction.java @@ -15,8 +15,10 @@ */ package com.drextended.actionhandler.action; +import android.content.Context; import android.view.View; +import com.drextended.actionhandler.listener.ActionFireInterceptor; import com.drextended.actionhandler.listener.OnActionDismissListener; import com.drextended.actionhandler.listener.OnActionErrorListener; import com.drextended.actionhandler.listener.OnActionFiredListener; @@ -47,6 +49,12 @@ public abstract class BaseAction implements Action { */ protected Set mActionDismissListeners = new HashSet<>(1); + /** + * Callbacks to be invoked after a view with an action is clicked and before action handling started. + * Can intercept an action to prevent it to be fired + */ + protected Set mActionFireInterceptors = new HashSet<>(1); + /** * Add a listener that will be called when method {@link #notifyOnActionFired(View, String, Object)} * called. Generally if action fired successfully. @@ -126,6 +134,32 @@ public void removeAllActionDismissListeners() { mActionDismissListeners.clear(); } + /** + * Add callback to be invoked right before specific action will be fired. + * Can intercept an action to prevent it to be fired + * + * @param interceptor The interceptor. + */ + public void addActionFireInterceptor(ActionFireInterceptor interceptor) { + if (interceptor != null) mActionFireInterceptors.add(interceptor); + } + + /** + * Remove interceptor. + * + * @param interceptor The interceptor. + */ + public void removeActionFireInterceptor(ActionFireInterceptor interceptor) { + if (interceptor != null) mActionFireInterceptors.remove(interceptor); + } + + /** + * Remove all interceptors. + */ + public void removeAllActionFireInterceptors() { + mActionFireInterceptors.clear(); + } + /** * Remove all listeners for action fire, error and dismiss events. */ @@ -133,6 +167,7 @@ public void removeAllActionListeners() { mActionFiredListeners.clear(); mActionErrorListeners.clear(); mActionDismissListeners.clear(); + mActionFireInterceptors.clear(); } @@ -179,4 +214,13 @@ public void notifyOnActionDismiss(String reason, View view, String actionType, O listener.onActionDismiss(reason, view, actionType, model); } } + + protected boolean interceptActionFire(Context context, View view, String actionType, Object model, Action action) { + if (mActionFireInterceptors != null) { + for (ActionFireInterceptor interceptor : mActionFireInterceptors) { + if (interceptor.onInterceptActionFire(context, view, actionType, model, action)) return true; + } + } + return false; + } } \ No newline at end of file diff --git a/actionhandler/src/main/java/com/drextended/actionhandler/action/CompositeAction.java b/actionhandler/src/main/java/com/drextended/actionhandler/action/CompositeAction.java index 9156bf1..6b48207 100644 --- a/actionhandler/src/main/java/com/drextended/actionhandler/action/CompositeAction.java +++ b/actionhandler/src/main/java/com/drextended/actionhandler/action/CompositeAction.java @@ -40,6 +40,7 @@ import android.widget.TextView; import com.drextended.actionhandler.R; +import com.drextended.actionhandler.listener.ActionFireInterceptor; import com.drextended.actionhandler.listener.OnActionDismissListener; import com.drextended.actionhandler.listener.OnActionErrorListener; import com.drextended.actionhandler.listener.OnActionFiredListener; @@ -57,7 +58,7 @@ * * @param */ -public class CompositeAction extends BaseAction implements OnActionFiredListener, OnActionErrorListener, OnActionDismissListener { +public class CompositeAction extends BaseAction implements OnActionFiredListener, OnActionErrorListener, OnActionDismissListener, ActionFireInterceptor { /** * Actions for show in a menu (dialog or popup window) and fire if is accepted @@ -138,6 +139,7 @@ public CompositeAction(TitleProvider titleProvider, boolean displayDialogForS baseAction.addActionFiredListener(this); baseAction.addActionErrorListener(this); baseAction.addActionDismissListener(this); + baseAction.addActionFireInterceptor(this); } } } @@ -197,13 +199,19 @@ private ActionItem getFirstAcceptedActionItem(M model) { public void onFireAction(Context context, @Nullable View view, @Nullable String actionType, @Nullable M model) { if (!mDisplayDialogForSingleAction && getAcceptedActionCount(model) == 1) { final ActionItem actionItem = getFirstAcceptedActionItem(model); - if (actionItem != null) //noinspection unchecked - actionItem.action.onFireAction(context, view, actionType, model); + fireActionItem(context, view, actionType, model, actionItem); } else { showMenu(context, view, actionType, model); } } + private void fireActionItem(Context context, @Nullable View view, @Nullable String actionType, @Nullable M model, ActionItem actionItem) { + if (actionItem != null && ! interceptActionFire(context, view, actionType, model, actionItem.action)) { + //noinspection unchecked + actionItem.action.onFireAction(context, view, actionType, model); + } + } + /** * Show menu with list of actions, which can handle this {@param model}. * @@ -280,8 +288,7 @@ protected PopupMenu buildPopupMenu(final Context context, final View view, final public boolean onMenuItemClick(MenuItem item) { activated.set(true); final ActionItem actionItem = menuItems.get(item.getItemId()); - //noinspection unchecked - actionItem.action.onFireAction(context, view, actionItem.actionType, model); + fireActionItem(context, view, actionItem.actionType, model, actionItem); return true; } }); @@ -315,8 +322,7 @@ protected AlertDialog.Builder buildAlertDialog(final Context context, final View @Override public void onClick(DialogInterface dialog, int which) { final ActionItem actionItem = menuItems.get(which); - //noinspection unchecked - actionItem.action.onFireAction(context, view, actionItem.actionType, model); + fireActionItem(context, view, actionItem.actionType, model, actionItem); } }).setOnCancelListener(new DialogInterface.OnCancelListener() { @Override @@ -351,6 +357,11 @@ public void onActionDismiss(String reason, View view, String actionType, Object notifyOnActionDismiss(reason, view, actionType, model); } + @Override + public boolean onInterceptActionFire(Context context, View view, String actionType, Object model, Action action) { + return interceptActionFire(context, view, actionType, model, action); + } + /** * Action item */ diff --git a/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionFireInterceptor.java b/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionFireInterceptor.java new file mode 100644 index 0000000..7798f31 --- /dev/null +++ b/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionFireInterceptor.java @@ -0,0 +1,43 @@ +/* + * Copyright Roman Donchenko. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.drextended.actionhandler.listener; + +import android.content.Context; +import android.view.View; + +import com.drextended.actionhandler.action.Action; + +/** + * Interface definition for a callback to be invoked right before specific action will be fired. + * If {@link #onInterceptActionFire(Context, View, String, Object, Action)} return true + * then this action will not be fired. + */ +public interface ActionFireInterceptor { + /** + * Called right before specific action will be fired + * If return true then this action will not be fired. + * + * + * @param context + * @param view The view that was clicked. + * @param actionType The action type, which appointed to the view + * @param model The model, which appointed to the view and should be handled + * @param action The action, which is prepared to fire + * @return true for intercept the action, false to handle the action in normal way. + */ + boolean onInterceptActionFire(Context context, final View view, final String actionType, final Object model, final Action action); +} diff --git a/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionInterceptor.java b/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionInterceptor.java index f22751b..446aed9 100644 --- a/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionInterceptor.java +++ b/actionhandler/src/main/java/com/drextended/actionhandler/listener/ActionInterceptor.java @@ -21,8 +21,8 @@ /** * Interface definition for a callback to be invoked after a view with an action is clicked - * and before action handling started. If {@link #onInterceptAction(Context, View, String, Object)} return true - * then this action will not be handled. + * and before action type handling started. If {@link #onInterceptAction(Context, View, String, Object)} return true + * then this action type will not be handled. */ public interface ActionInterceptor { /**