/***************************************************************************** * AudioPlaylistView.java ***************************************************************************** * Copyright © 2011-2012 VLC authors and VideoLAN * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ package org.videolan.vlc.gui.audio; import android.content.Context; import android.graphics.Canvas; import android.graphics.Rect; import android.support.annotation.NonNull; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import org.videolan.vlc.R; public class AudioPlaylistView extends ListView { private View mDragShadow; private boolean mIsDragging; private int mPositionDragStart; private float mTouchY; private OnItemDraggedListener mOnItemDraggedListener; private OnItemRemovedListener mOnItemRemovedListener; private OnItemLongClickListener mOnItemLongClickListener; public AudioPlaylistView(Context context, AttributeSet attrs) { super(context, attrs); mIsDragging = false; LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); mDragShadow = inflater.inflate(R.layout.audio_playlist_item_drag_shadow, this, false); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); mDragShadow.layout(l, t, l + mDragShadow.getMeasuredWidth(), t + mDragShadow.getMeasuredHeight()); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); mDragShadow.measure(widthMeasureSpec, MeasureSpec.UNSPECIFIED); } @Override public boolean onInterceptTouchEvent(@NonNull MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: mTouchY = event.getY(); break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mIsDragging) { dragAborted(); } break; default: break; } return mIsDragging || super.onInterceptTouchEvent(event); } @Override public boolean onTouchEvent(@NonNull MotionEvent event) { boolean handleEvent = false; // Save the position of the touch event. mTouchY = event.getY(); if (mIsDragging) { handleEvent = true; switch (event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: dragging(); break; case MotionEvent.ACTION_UP: dragDropped(); break; case MotionEvent.ACTION_CANCEL: dragAborted(); break; default: handleEvent = false; break; } invalidate(); } return handleEvent || super.onTouchEvent(event); } @Override protected void dispatchDraw (@NonNull Canvas canvas) { super.dispatchDraw(canvas); if (mIsDragging) { canvas.save(); // Position the drag shadow. float posY = mTouchY - (float)mDragShadow.getMeasuredHeight() / 2f; canvas.translate(0, posY); mDragShadow.draw(canvas); canvas.restore(); } } public void startDrag(int positionDragStart, String title, String artist) { mPositionDragStart = positionDragStart; if (mDragShadow != null) { TextView titleView = (TextView)mDragShadow.findViewById(R.id.title); TextView artistView = (TextView)mDragShadow.findViewById(R.id.artist); titleView.setText(title); artistView.setText(artist); mIsDragging = true; } } private void dragging() { // Find the child view that is currently touched (perform a hit test) Rect rect = new Rect(); for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); AudioPlaylistAdapter.ViewHolder holder = (AudioPlaylistAdapter.ViewHolder)child.getTag(); if (holder.position == mPositionDragStart) { holder.layoutItem.setVisibility(LinearLayout.GONE); holder.layoutFooter.setVisibility(LinearLayout.GONE); } else { child.getHitRect(rect); if (rect.contains(getWidth() / 2, (int)mTouchY)) holder.expansion.setVisibility(LinearLayout.VISIBLE); else holder.expansion.setVisibility(LinearLayout.GONE); } } } public void dragDropped() { mIsDragging = false; // Find the child view that was touched (perform a hit test) Rect rect = new Rect(); boolean b_foundHitChild = false; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); child.getHitRect(rect); if (rect.contains(getWidth() / 2, (int)mTouchY)) { // Send back the performed change thanks to the listener. AudioPlaylistAdapter.ViewHolder holder = (AudioPlaylistAdapter.ViewHolder)child.getTag(); if (mOnItemDraggedListener != null) mOnItemDraggedListener.onItemDragged(mPositionDragStart, holder.position); b_foundHitChild = true; break; } } if (!b_foundHitChild) mOnItemDraggedListener.onItemDragged(mPositionDragStart, this.getCount()); } public void dragAborted() { mIsDragging = false; for (int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); AudioPlaylistAdapter.ViewHolder holder = (AudioPlaylistAdapter.ViewHolder)child.getTag(); holder.layoutItem.setVisibility(LinearLayout.VISIBLE); holder.layoutFooter.setVisibility(LinearLayout.VISIBLE); holder.expansion.setVisibility(LinearLayout.GONE); } } public interface OnItemDraggedListener { void onItemDragged(int positionStart, int positionEnd); } public void setOnItemDraggedListener(OnItemDraggedListener l) { mOnItemDraggedListener = l; } public interface OnItemRemovedListener { void onItemRemoved(int position); } public void setOnItemRemovedListener(OnItemRemovedListener l) { mOnItemRemovedListener = l; } public void removeItem(int position) { if (mOnItemRemovedListener != null) mOnItemRemovedListener.onItemRemoved(position); } public void performItemLongClick(View view, int position, long id) { if (mOnItemLongClickListener != null) mOnItemLongClickListener.onItemLongClick(this, view, position, id); } public void setOnItemLongClickListener(OnItemLongClickListener l) { mOnItemLongClickListener = l; } }