/******************************************************************************* * Copyright 2013 Comcast Cable Communications Management, LLC * * 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.marshalchen.common.uimodule.freeflow.core; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import com.marshalchen.common.uimodule.freeflow.layouts.FreeFlowLayout; import android.content.Context; import android.util.AttributeSet; import android.view.ContextMenu; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; public abstract class AbsLayoutContainer extends ViewGroup { protected Map<Object, FreeFlowItem> frames = null; protected ArrayList<FreeFlowEventListener> listeners = new ArrayList<FreeFlowEventListener>(); public AbsLayoutContainer(Context context) { super(context); init(context); } public AbsLayoutContainer(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public AbsLayoutContainer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } protected void init(Context c) { } // //////////////////CLICK BEHAVIOR ////// protected FreeFlowItem selectedFreeFlowItem; public interface OnItemClickListener { /** * Callback method to be invoked when an item in this AdapterView has * been clicked. * <p> * Implementers can call getItemAtPosition(position) if they need to * access the data associated with the selected item. * * @param parent * The AdapterView where the click happened. * @param view * The view within the AdapterView that was clicked (this * will be a view provided by the adapter) * @param position * The position of the view in the adapter. * @param id * The row id of the item that was clicked. */ void onItemClick(AbsLayoutContainer parent, FreeFlowItem proxy); } protected OnItemClickListener mOnItemClickListener; /** * Register a callback to be invoked when an item in this AdapterView has * been clicked. * * @param listener * The callback that will be invoked. */ public void setOnItemClickListener(OnItemClickListener listener) { mOnItemClickListener = listener; } /** * @return The callback to be invoked with an item in this AdapterView has * been clicked, or null id no callback has been set. */ public final OnItemClickListener getOnItemClickListener() { return mOnItemClickListener; } /** * Call the OnItemClickListener, if it is defined. Performs all normal * actions associated with clicking: reporting accessibility event, playing * a sound, etc. * * @param view * The view within the AdapterView that was clicked. * @param position * The position of the view in the adapter. * @param id * The row id of the item that was clicked. * @return True if there was an assigned OnItemClickListener that was * called, false otherwise is returned. */ public boolean performItemClick(View view, int sectionIndex, int positionInSection, long id) { if (mOnItemClickListener != null) { // playSoundEffect(SoundEffectConstants.CLICK); if (view != null) { view.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); } mOnItemClickListener.onItemClick(this, getFreeFlowItemForVisibleItemAt(sectionIndex, positionInSection)); return true; } return false; } OnItemSelectedListener mOnItemSelectedListener; /** * Interface definition for a callback to be invoked when an item in this * view has been selected. */ public interface OnItemSelectedListener { /** * <p> * Callback method to be invoked when an item in this view has been * selected. This callback is invoked only when the newly selected * position is different from the previously selected position or if * there was no selected item. * </p> * * Impelmenters can call getItemAtPosition(position) if they need to * access the data associated with the selected item. * * @param parent * The AdapterView where the selection happened * @param proxy * The FreeFlowItem instance representing the item selected * @param id * The row id of the item that is selected */ void onItemSelected(AbsLayoutContainer parent, FreeFlowItem proxy); /** * Callback method to be invoked when the selection disappears from this * view. The selection can disappear for instance when touch is * activated or when the adapter becomes empty. * * @param parent * The AdapterView that now contains no selected item. */ void onNothingSelected(AbsLayoutContainer parent); } /** * Register a callback to be invoked when an item in this AdapterView has * been selected. * * @param listener * The callback that will run */ public void setOnItemSelectedListener(OnItemSelectedListener listener) { mOnItemSelectedListener = listener; } public final OnItemSelectedListener getOnItemSelectedListener() { return mOnItemSelectedListener; } public void addFreeFlowEventListener(FreeFlowEventListener listener) { if(listeners.indexOf(listener) != -1) return; listeners.add(listener); } public void removeFreeFlowEventListener(FreeFlowEventListener listener) { listeners.remove(listener); } protected void dispatchAnimationsStarting() { for (FreeFlowEventListener listener : listeners) { listener.layoutChangeAnimationsStarting(); } } protected void dispatchLayoutChangeAnimationsComplete() { for (FreeFlowEventListener listener : listeners) { listener.layoutChangeAnimationsComplete(); } } protected void dispatchLayoutComplete(boolean areTransitionAnimationsPlaying) { for (FreeFlowEventListener listener : listeners) { listener.layoutComplete(areTransitionAnimationsPlaying); } } protected void dispatchLayoutComputed() { for (FreeFlowEventListener listener : listeners) { listener.layoutComputed(); } } protected void dispatchDataChanged() { for (FreeFlowEventListener listener : listeners) { listener.dataChanged(); } } protected void dispatchLayoutChanging(FreeFlowLayout oldLayout, FreeFlowLayout newLayout) { for (FreeFlowEventListener listener : listeners) { listener.onLayoutChanging(oldLayout, newLayout); } } OnItemLongClickListener mOnItemLongClickListener; /** * Interface definition for a callback to be invoked when an item in this * view has been clicked and held. */ public interface OnItemLongClickListener { /** * Callback method to be invoked when an item in this view has been * clicked and held. * * Implementers can call getItemAtPosition(position) if they need to access * the data associated with the selected item. * * @param parent The AbsListView where the click happened * @param view The view within the AbsListView that was clicked * @param position The position of the view in the list * @param id The row id of the item that was clicked * * @return true if the callback consumed the long click, false otherwise */ boolean onItemLongClick(AbsLayoutContainer parent, View view, int sectionIndex, int positionInSection, long id); } /** * Register a callback to be invoked when an item in this AdapterView has * been clicked and held * * @param listener The callback that will run */ public void setOnItemLongClickListener(OnItemLongClickListener listener) { if (!isLongClickable()) { setLongClickable(true); } mOnItemLongClickListener = listener; } /** * @return The callback to be invoked with an item in this AdapterView has * been clicked and held, or null id no callback as been set. */ public final OnItemLongClickListener getOnItemLongClickListener() { return mOnItemLongClickListener; } public static class AbsLayoutContainerContextMenuInfo implements ContextMenu.ContextMenuInfo { public View targetView; public int sectionIndex; public int positionInSection; public long id; public AbsLayoutContainerContextMenuInfo(View targetView, int sectionIndex, int positionInSection, long id) { this.targetView = targetView; this.sectionIndex = sectionIndex; this.positionInSection = positionInSection; this.id = id; } } /** * Returns the FreeFlowItem instance of a view at position if that * view is visible or null if thats not currently visible * @param section The section index of the item * @param position The position of the item in the particular section * @return The <code>FreeFlowItem</code> instance representing that section and index. The proxy is guaranteed to have a view associated with it */ public FreeFlowItem getFreeFlowItemForVisibleItemAt(int section, int position) { Iterator<?> it = frames.entrySet().iterator(); FreeFlowItem proxy = null; while (it.hasNext()) { Map.Entry<?, FreeFlowItem> pairs = (Map.Entry<?, FreeFlowItem>) it.next(); proxy = pairs.getValue(); if (proxy.itemSection == section && proxy.itemIndex == position) { return proxy; } } return null; } }