/* * Copyright 2008-2013, ETH Zürich, Samuel Welten, Michael Kuhn, Tobias Langner, * Sandro Affentranger, Lukas Bossard, Michael Grob, Rahul Jain, * Dominic Langenegger, Sonia Mayor Alonso, Roger Odermatt, Tobias Schlueter, * Yannick Stucki, Sebastian Wendland, Samuel Zehnder, Samuel Zihlmann, * Samuel Zweifel * * This file is part of Jukefox. * * Jukefox 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 3 of the License, or any later version. Jukefox 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 * Jukefox. If not, see <http://www.gnu.org/licenses/>. */ package ch.ethz.dcg.pancho3.tablet.view; import java.util.ArrayList; import java.util.List; import android.content.ClipData; import android.util.SparseBooleanArray; import android.view.DragEvent; import android.view.View; import android.view.View.DragShadowBuilder; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ListView; import ch.ethz.dcg.jukefox.model.collection.AllAlbumsRepresentative; import ch.ethz.dcg.jukefox.model.collection.AllRelatedAlbumsRepresentative; import ch.ethz.dcg.jukefox.model.collection.AllSongsRepresentative; import ch.ethz.dcg.jukefox.model.collection.BaseAlbum; import ch.ethz.dcg.jukefox.model.collection.BaseArtist; import ch.ethz.dcg.jukefox.model.collection.BaseSong; import ch.ethz.dcg.jukefox.model.collection.ListAlbum; import ch.ethz.dcg.jukefox.model.collection.PlaylistSong; import ch.ethz.dcg.jukefox.model.collection.PlaylistSong.SongSource; import ch.ethz.dcg.pancho3.tablet.interfaces.AlbumAdapter; import ch.ethz.dcg.pancho3.tablet.interfaces.ISongAdapter; import ch.ethz.dcg.pancho3.tablet.model.DataFetcher; import ch.ethz.dcg.pancho3.tablet.model.DataFetcher.OnDataFetchedListener; import ch.ethz.dcg.pancho3.tablet.presenter.TabletPresenter; import ch.ethz.dcg.pancho3.tablet.view.lists.ArtistListAdapter; import ch.ethz.dcg.pancho3.tablet.view.lists.ImageAlbumListAdapter; public class DragManager { private final DataFetcher dataFetcher; private final TabletPresenter tabletPresenter; private ViewFactory viewFactory; private static final ClipData EMPTY_CLIP_DATA = ClipData.newPlainText("", ""); private float lastX, lastY; private final float screenDensityScale; private final float touchSlop; public DragManager(DataFetcher dataFetcher, TabletPresenter tabletPresenter, float screenDensityScale, float touchSlop) { this.dataFetcher = dataFetcher; this.tabletPresenter = tabletPresenter; this.screenDensityScale = screenDensityScale; this.touchSlop = touchSlop; } public static class DragDataContainer<T> implements OnDataFetchedListener<List<T>> { private List<T> data; public DragDataContainer() { } public DragDataContainer(T item) { data = new ArrayList<T>(); data.add(item); } public DragDataContainer(List<T> items) { this.data = items; } public List<T> getData() { return data; } public boolean isReady() { return data != null; } @Override public void onDataFetched(List<T> data) { this.data = data; } } private void startDraggingSong(View view, BaseSong<BaseArtist, BaseAlbum> song) { PlaylistSong<BaseArtist, BaseAlbum> playlistSong = new PlaylistSong<BaseArtist, BaseAlbum>( song, SongSource.MANUALLY_SELECTED); startDraggingImpl(view, new DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>>( playlistSong), viewFactory.createDragShadowBuilderSongs(1)); } public void startDraggingSongs(View view, List<BaseSong<BaseArtist, BaseAlbum>> songs) { List<PlaylistSong<BaseArtist, BaseAlbum>> playlistSongs = new ArrayList<PlaylistSong<BaseArtist, BaseAlbum>>(); for (BaseSong<BaseArtist, BaseAlbum> song : songs) { playlistSongs.add(new PlaylistSong<BaseArtist, BaseAlbum>( song, SongSource.MANUALLY_SELECTED)); } startDraggingImpl(view, new DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>>( playlistSongs), viewFactory.createDragShadowBuilderSongs(songs.size())); } private void startDraggingArtist(View view, BaseArtist artist) { DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>> dragDataContainer = new DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>>(); dataFetcher.fetchPlaylistSongsOfArtist(artist, dragDataContainer, SongSource.MANUALLY_SELECTED); startDraggingImpl(view, dragDataContainer, viewFactory.createDragShadowBuilderArtist()); } private void startDraggingAlbum(View view, ListAlbum album) { if (album instanceof AllAlbumsRepresentative) { startDraggingArtist(view, album.getFirstArtist()); } else if (album instanceof AllSongsRepresentative) { startDraggingAllSongs(view); } else if (album instanceof AllRelatedAlbumsRepresentative) { startDraggingAlbums(view, ((AllRelatedAlbumsRepresentative) album).getRepresentedAlbums()); } else { DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>> dragDataContainer = new DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>>(); dataFetcher.fetchPlaylistSongsOfAlbum(album, dragDataContainer, SongSource.MANUALLY_SELECTED); startDraggingImpl(view, dragDataContainer, viewFactory.createDragShadowBuilderAlbums(1)); } } private void startDraggingAlbums(View view, List<? extends ListAlbum> albums) { DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>> dragDataContainer = new DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>>(); dataFetcher.fetchPlaylistSongsOfAlbums(albums, dragDataContainer, SongSource.MANUALLY_SELECTED); startDraggingImpl(view, dragDataContainer, viewFactory.createDragShadowBuilderAlbums(albums.size())); } private void startDraggingAllSongs(View view) { DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>> dragDataContainer = new DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>>(); dataFetcher.fetchAllPlaylistSongs(dragDataContainer, SongSource.MANUALLY_SELECTED); startDraggingImpl(view, dragDataContainer, viewFactory.createDragShadowBuilderAllSongs()); } private void startDraggingImpl(View view, DragDataContainer<PlaylistSong<BaseArtist, BaseAlbum>> dragDataContainer, DragShadowBuilder dragShadowBuilder) { tabletPresenter.highlight(); view.startDrag(EMPTY_CLIP_DATA, dragShadowBuilder, dragDataContainer, 0); } public boolean onDragEvent(DragEvent event) { switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: return true; case DragEvent.ACTION_DRAG_ENDED: tabletPresenter.unhighlight(event.getResult()); return true; } return false; } public void registerSongListViewDragging(final ListView listView, final ISongAdapter adapter) { // Drag and drop on long click. listView.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { if (view == null) { return false; } if (listView.getChoiceMode() == ListView.CHOICE_MODE_MULTIPLE) { if (!listView.getCheckedItemPositions().get(position)) { listView.performItemClick(listView, position, id); } ArrayList<BaseSong<BaseArtist, BaseAlbum>> songs = new ArrayList<BaseSong<BaseArtist, BaseAlbum>>(); SparseBooleanArray checkedItems = listView.getCheckedItemPositions(); int count = checkedItems.size(); for (int i = 0; i < count; i++) { int key = checkedItems.keyAt(i); if (checkedItems.get(key)) { songs.add(adapter.getSong(key)); } } startDraggingSongs(view, songs); } else { startDraggingSong(view, adapter.getSong(position)); } return true; } }); } public void registerArtistListViewDragging(final ListView listView, final ArtistListAdapter adapter) { // Drag and drop on long click. listView.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { if (view == null) { return false; } startDraggingArtist(view, adapter.getItem(position)); return true; } }); } public void registerAlbumViewDragging(final AdapterView<?> albumView, final ImageAlbumListAdapter adapter) { // Drag and drop on long click. albumView.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // TODO: this shouldn't be null, but it becomes null from // this touch listener when we perform long click. investigate, also // the three time same code above. if (view == null) { return false; } startDraggingAlbum(view, adapter.getItem(position)); return true; } }); } public void registerAlbumViewDragging(final AlbumAdapter adapter) { // Drag and drop on long click. adapter.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { // TODO: this shouldn't be null, but it becomes null from // this touch listener when we perform long click. investigate, also // the three time same code above. if (view == null) { return false; } startDraggingAlbum(view, adapter.getItem(position)); return true; } }); } public float getDensitiyScreenScale() { return screenDensityScale; } public void setLatestXY(float lastX, float lastY) { this.lastX = lastX; this.lastY = lastY; } public void setViewFactory(ViewFactory viewFactory) { this.viewFactory = viewFactory; } public float getTouchSlop() { return touchSlop; } }