package ru.ltst.u2020mvp.ui.debug; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.Button; import android.widget.LinearLayout; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import ru.ltst.u2020mvp.R; import timber.log.Timber; public class ContextualDebugActions implements ViewGroup.OnHierarchyChangeListener { public static abstract class DebugAction<T extends View> { private final Class<T> viewClass; protected DebugAction(Class<T> viewClass) { this.viewClass = viewClass; } /** Invoked when the action has been added as available to run. */ public void added() {} /** Invoked when the action has been removed as available to run. */ public void removed() {} /** Return true if action is applicable. Called each time the target view is added. */ public boolean enabled() { return true; } /** Human-readable action name. Displayed in debug drawer. */ public abstract String name(); /** Perform this action using the specified view. */ public abstract void run(T view); } private final Map<DebugAction<? extends View>, View> buttonMap; private final Map<Class<? extends View>, List<DebugAction<? extends View>>> actionMap; private final Context drawerContext; private final View contextualTitleView; private final LinearLayout contextualListView; private View.OnClickListener clickListener; public ContextualDebugActions(DebugView debugView, Set<DebugAction<?>> debugActions) { buttonMap = new LinkedHashMap<>(); actionMap = new LinkedHashMap<>(); drawerContext = debugView.getContext(); contextualTitleView = debugView.contextualTitleView; contextualListView = debugView.contextualListView; for (DebugAction<?> debugAction : debugActions) { Class cls = debugAction.viewClass; Timber.d("Adding %s action for %s.", debugAction.getClass().getSimpleName(), cls.getSimpleName()); List<DebugAction<? extends View>> actionList = actionMap.get(cls); if (actionList == null) { actionList = new ArrayList<>(2); actionMap.put(cls, actionList); } actionList.add(debugAction); } } public void setActionClickListener(View.OnClickListener clickListener) { this.clickListener = clickListener; } @Override public void onChildViewAdded(View parent, View child) { List<DebugAction<? extends View>> actions = actionMap.get(child.getClass()); if (actions != null) { for (DebugAction<? extends View> action : actions) { if (!action.enabled()) { continue; } Timber.d("Adding debug action \"%s\" for %s.", action.name(), child.getClass().getSimpleName()); View button = createButton(action, child); buttonMap.put(action, button); contextualListView.addView(button); action.added(); } updateContextualVisibility(); } } @Override public void onChildViewRemoved(View parent, View child) { List<DebugAction<? extends View>> actions = actionMap.get(child.getClass()); if (actions != null) { for (DebugAction<? extends View> action : actions) { Timber.d("Removing debug action \"%s\" for %s.", action.name(), child.getClass().getSimpleName()); View buttonView = buttonMap.remove(action); if (buttonView != null) { contextualListView.removeView(buttonView); action.removed(); } } updateContextualVisibility(); } } private Button createButton(final DebugAction action, final View child) { Button button = (Button) LayoutInflater.from(drawerContext) .inflate(R.layout.debug_drawer_contextual_action, contextualListView, false); button.setText(action.name()); button.setOnClickListener(view -> { if (clickListener != null) { clickListener.onClick(view); } action.run(child); }); return button; } private void updateContextualVisibility() { int visibility = contextualListView.getChildCount() > 0 ? View.VISIBLE : View.GONE; contextualTitleView.setVisibility(visibility); contextualListView.setVisibility(visibility); } }