All smart playlists are working now.
This commit is contained in:
parent
a95e71c52c
commit
50f73c1dde
19 changed files with 1019 additions and 271 deletions
|
|
@ -132,15 +132,12 @@
|
|||
android:resource="@xml/music_player_widget_info" />
|
||||
</receiver>
|
||||
|
||||
<activity
|
||||
android:name=".ui.activities.PlaylistDetailActivity"
|
||||
android:label="@string/title_activity_playlist_detail" />
|
||||
<activity
|
||||
android:name=".ui.activities.SettingsActivity"
|
||||
android:label="@string/title_activity_settings" />
|
||||
<activity
|
||||
android:name=".ui.activities.SmartPlaylistDetailActivity"
|
||||
android:label="@string/title_activity_smart_playlist_detail"></activity>
|
||||
android:name=".ui.activities.PlaylistDetailActivity"
|
||||
android:label="@string/title_activity_smart_playlist_detail" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ public class LastFMAlbumImageUrlLoader {
|
|||
|
||||
public static void loadAlbumImageUrl(Context context, String queryAlbum, String queryArtist, final AlbumImageUrlLoaderCallback callback) {
|
||||
if (queryAlbum != null) {
|
||||
String albumJSON = AlbumJSONStore.getInstance(context).getAlbumJSON(queryAlbum + queryArtist);
|
||||
String albumJSON = AlbumJSONStore.getInstance(context).getJSONData(queryAlbum + queryArtist);
|
||||
if (albumJSON != null) {
|
||||
try {
|
||||
loadAlbumImageUrlFromJSON(new JSONObject(albumJSON), callback);
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class LastFMAlbumInfoUtil {
|
|||
try {
|
||||
return rootJSON.getJSONObject("album").getString("name");
|
||||
} catch (JSONException e) {
|
||||
//Log.e(TAG, "Error while getting album name from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting album name from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ public class LastFMAlbumInfoUtil {
|
|||
}
|
||||
return images.getJSONObject(0).getString("#text");
|
||||
} catch (JSONException | NullPointerException e) {
|
||||
//Log.e(TAG, "Error while getting album thumbnail image from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting album thumbnail image from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ public class LastFMAlbumInfoUtil {
|
|||
try {
|
||||
return rootJSON.getJSONObject("album").getJSONArray("image");
|
||||
} catch (JSONException e) {
|
||||
//Log.e(TAG, "Error while getting album image array from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting album image array from JSON_DATA parameter!", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ public class LastFMAlbumInfoUtil {
|
|||
JSONArray images = getAlbumImageArrayFromJSON(rootJSON);
|
||||
return images.getJSONObject(images.length() - 1).getString("#text");
|
||||
} catch (JSONException | NullPointerException e) {
|
||||
//Log.e(TAG, "Error while getting album image from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting album image from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ public class LastFMArtistInfoUtil {
|
|||
try {
|
||||
return rootJSON.getJSONObject("artist").getString("name");
|
||||
} catch (JSONException e) {
|
||||
//Log.e(TAG, "Error while getting artist name from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting artist name from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ public class LastFMArtistInfoUtil {
|
|||
}
|
||||
return images.getJSONObject(0).getString("#text");
|
||||
} catch (JSONException | NullPointerException e) {
|
||||
//Log.e(TAG, "Error while getting artist thumbnail image from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting artist thumbnail image from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ public class LastFMArtistInfoUtil {
|
|||
try {
|
||||
return rootJSON.getJSONObject("artist").getJSONArray("image");
|
||||
} catch (JSONException e) {
|
||||
//Log.e(TAG, "Error while getting artist image array from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting artist image array from JSON_DATA parameter!", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +79,7 @@ public class LastFMArtistInfoUtil {
|
|||
JSONArray images = getArtistImageArrayFromJSON(rootJSON);
|
||||
return images.getJSONObject(images.length() - 1).getString("#text");
|
||||
} catch (JSONException | NullPointerException e) {
|
||||
//Log.e(TAG, "Error while getting artist image from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting artist image from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
|
@ -88,13 +88,13 @@ public class LastFMArtistInfoUtil {
|
|||
try {
|
||||
return rootJSON.getJSONObject("artist").getJSONObject("bio").getString("content");
|
||||
} catch (JSONException e) {
|
||||
//Log.e(TAG, "Error while getting artist biography from JSON parameter!", e);
|
||||
//Log.e(TAG, "Error while getting artist biography from JSON_DATA parameter!", e);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void saveArtistJSONDataToCacheAndDisk(Context context, String artist, JSONObject jsonObject) {
|
||||
ArtistJSONStore.getInstance(context).removeItem(artist);
|
||||
ArtistJSONStore.getInstance(context).removeArtistJSON(artist);
|
||||
ArtistJSONStore.getInstance(context).addArtistJSON(artist, jsonObject.toString());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* 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.kabouzeid.gramophone.loader;
|
||||
|
||||
import android.database.AbstractCursor;
|
||||
import android.database.Cursor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* This cursor basically wraps a song cursor and is given a list of the order of the ids of the
|
||||
* contents of the cursor. It wraps the Cursor and simulates the internal cursor being sorted
|
||||
* by moving the point to the appropriate spot
|
||||
*/
|
||||
public class SortedCursor extends AbstractCursor {
|
||||
// cursor to wrap
|
||||
private final Cursor mCursor;
|
||||
// the map of external indices to internal indices
|
||||
private ArrayList<Integer> mOrderedPositions;
|
||||
// this contains the ids that weren't found in the underlying cursor
|
||||
private ArrayList<Long> mMissingIds;
|
||||
// this contains the mapped cursor positions and afterwards the extra ids that weren't found
|
||||
private HashMap<Long, Integer> mMapCursorPositions;
|
||||
// extra we want to store with the cursor
|
||||
private ArrayList<Object> mExtraData;
|
||||
|
||||
/**
|
||||
* @param cursor to wrap
|
||||
* @param order the list of unique ids in sorted order to display
|
||||
* @param columnName the column name of the id to look up in the internal cursor
|
||||
*/
|
||||
public SortedCursor(final Cursor cursor, final long[] order, final String columnName,
|
||||
final List<? extends Object> extraData) {
|
||||
if (cursor == null) {
|
||||
throw new IllegalArgumentException("Non-null cursor is needed");
|
||||
}
|
||||
|
||||
mCursor = cursor;
|
||||
mMissingIds = buildCursorPositionMapping(order, columnName, extraData);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function populates mOrderedPositions with the cursor positions in the order based
|
||||
* on the order passed in
|
||||
*
|
||||
* @param order the target order of the internal cursor
|
||||
* @param extraData Extra data we want to add to the cursor
|
||||
* @return returns the ids that aren't found in the underlying cursor
|
||||
*/
|
||||
private ArrayList<Long> buildCursorPositionMapping(final long[] order,
|
||||
final String columnName, final List<? extends Object> extraData) {
|
||||
ArrayList<Long> missingIds = new ArrayList<Long>();
|
||||
|
||||
mOrderedPositions = new ArrayList<Integer>(mCursor.getCount());
|
||||
mExtraData = new ArrayList<Object>();
|
||||
|
||||
mMapCursorPositions = new HashMap<Long, Integer>(mCursor.getCount());
|
||||
final int idPosition = mCursor.getColumnIndex(columnName);
|
||||
|
||||
if (mCursor.moveToFirst()) {
|
||||
// first figure out where each of the ids are in the cursor
|
||||
do {
|
||||
mMapCursorPositions.put(mCursor.getLong(idPosition), mCursor.getPosition());
|
||||
} while (mCursor.moveToNext());
|
||||
|
||||
// now create the ordered positions to map to the internal cursor given the
|
||||
// external sort order
|
||||
for (int i = 0; order != null && i < order.length; i++) {
|
||||
final long id = order[i];
|
||||
if (mMapCursorPositions.containsKey(id)) {
|
||||
mOrderedPositions.add(mMapCursorPositions.get(id));
|
||||
mMapCursorPositions.remove(id);
|
||||
if (extraData != null) {
|
||||
mExtraData.add(extraData.get(i));
|
||||
}
|
||||
} else {
|
||||
missingIds.add(id);
|
||||
}
|
||||
}
|
||||
|
||||
mCursor.moveToFirst();
|
||||
}
|
||||
|
||||
return missingIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of ids that weren't found in the underlying cursor
|
||||
*/
|
||||
public ArrayList<Long> getMissingIds() {
|
||||
return mMissingIds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the list of ids that were in the underlying cursor but not part of the ordered list
|
||||
*/
|
||||
public Collection<Long> getExtraIds() {
|
||||
return mMapCursorPositions.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the extra object data that was passed in to be attached to the current row
|
||||
*/
|
||||
public Object getExtraData() {
|
||||
int position = getPosition();
|
||||
return position < mExtraData.size() ? mExtraData.get(position) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mCursor.close();
|
||||
|
||||
super.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mOrderedPositions.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getColumnNames() {
|
||||
return mCursor.getColumnNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(int column) {
|
||||
return mCursor.getString(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public short getShort(int column) {
|
||||
return mCursor.getShort(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(int column) {
|
||||
return mCursor.getInt(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(int column) {
|
||||
return mCursor.getLong(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(int column) {
|
||||
return mCursor.getFloat(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDouble(int column) {
|
||||
return mCursor.getDouble(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNull(int column) {
|
||||
return mCursor.isNull(column);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(int oldPosition, int newPosition) {
|
||||
if (newPosition >= 0 && newPosition < getCount()) {
|
||||
mCursor.moveToPosition(mOrderedPositions.get(newPosition));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* 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.kabouzeid.gramophone.loader;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.provider.BaseColumns;
|
||||
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.provider.RecentlyPlayedStore;
|
||||
import com.kabouzeid.gramophone.provider.SongPlayCountStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class TopAndRecentlyPlayedTracksLoader {
|
||||
public static final int NUMBER_OF_TOP_TRACKS = 99;
|
||||
|
||||
public static ArrayList<Song> getRecentlyPlayedTracks(Context context) {
|
||||
return SongLoader.getSongs(makeRecentTracksCursorAndClearUpDatabase(context));
|
||||
}
|
||||
|
||||
public static ArrayList<Song> getTopTracks(Context context) {
|
||||
return SongLoader.getSongs(makeTopTracksCursorAndClearUpDatabase(context));
|
||||
}
|
||||
|
||||
public static Cursor makeRecentTracksCursorAndClearUpDatabase(final Context context) {
|
||||
SortedCursor retCursor = makeRecentTracksCursorImpl(context);
|
||||
|
||||
// clean up the databases with any ids not found
|
||||
if (retCursor != null) {
|
||||
ArrayList<Long> missingIds = retCursor.getMissingIds();
|
||||
if (missingIds != null && missingIds.size() > 0) {
|
||||
for (long id : missingIds) {
|
||||
RecentlyPlayedStore.getInstance(context).removeSongId(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retCursor;
|
||||
}
|
||||
|
||||
public static Cursor makeTopTracksCursorAndClearUpDatabase(final Context context) {
|
||||
SortedCursor retCursor = makeTopTracksCursorImpl(context);
|
||||
|
||||
// clean up the databases with any ids not found
|
||||
if (retCursor != null) {
|
||||
ArrayList<Long> missingIds = retCursor.getMissingIds();
|
||||
if (missingIds != null && missingIds.size() > 0) {
|
||||
for (long id : missingIds) {
|
||||
SongPlayCountStore.getInstance(context).removeItem(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retCursor;
|
||||
}
|
||||
|
||||
private static SortedCursor makeRecentTracksCursorImpl(final Context context) {
|
||||
// first get the top results ids from the internal database
|
||||
Cursor songs = RecentlyPlayedStore.getInstance(context).queryRecentIds();
|
||||
|
||||
try {
|
||||
return makeSortedCursor(context, songs,
|
||||
songs.getColumnIndex(RecentlyPlayedStore.RecentStoreColumns.ID));
|
||||
} finally {
|
||||
if (songs != null) {
|
||||
songs.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SortedCursor makeTopTracksCursorImpl(final Context context) {
|
||||
// first get the top results ids from the internal database
|
||||
Cursor songs = SongPlayCountStore.getInstance(context).getTopPlayedResults(NUMBER_OF_TOP_TRACKS);
|
||||
|
||||
try {
|
||||
return makeSortedCursor(context, songs,
|
||||
songs.getColumnIndex(SongPlayCountStore.SongPlayCountColumns.ID));
|
||||
} finally {
|
||||
if (songs != null) {
|
||||
songs.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static SortedCursor makeSortedCursor(final Context context, final Cursor cursor,
|
||||
final int idColumn) {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// create the list of ids to select against
|
||||
StringBuilder selection = new StringBuilder();
|
||||
selection.append(BaseColumns._ID);
|
||||
selection.append(" IN (");
|
||||
|
||||
// this tracks the order of the ids
|
||||
long[] order = new long[cursor.getCount()];
|
||||
|
||||
long id = cursor.getLong(idColumn);
|
||||
selection.append(id);
|
||||
order[cursor.getPosition()] = id;
|
||||
|
||||
while (cursor.moveToNext()) {
|
||||
selection.append(",");
|
||||
|
||||
id = cursor.getLong(idColumn);
|
||||
order[cursor.getPosition()] = id;
|
||||
selection.append(String.valueOf(id));
|
||||
}
|
||||
|
||||
selection.append(")");
|
||||
|
||||
// get a list of songs with the data given the selection statement
|
||||
Cursor songCursor = SongLoader.makeSongCursor(context, selection.toString(), null);
|
||||
if (songCursor != null) {
|
||||
// now return the wrapped TopTracksCursor to handle sorting given order
|
||||
return new SortedCursor(songCursor, order, BaseColumns._ID, null);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -4,12 +4,15 @@ import android.content.Context;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.kabouzeid.gramophone.App;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.smartplaylist.CannotDeleteSingleSongsSongAdapter;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.smartplaylist.SmartPlaylistSongAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.CabHolder;
|
||||
import com.kabouzeid.gramophone.loader.LastAddedLoader;
|
||||
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
|
||||
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.provider.SongPlayCountStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -24,8 +27,7 @@ public class MyTopTracksPlaylist extends SmartPlaylist {
|
|||
|
||||
@Override
|
||||
public ArrayList<Song> getSongs(Context context) {
|
||||
// TODO replace with getSongs() for top tracks. This is just a place holder
|
||||
return LastAddedLoader.getLastAddedSongs(context);
|
||||
return TopAndRecentlyPlayedTracksLoader.getTopTracks(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -35,6 +37,7 @@ public class MyTopTracksPlaylist extends SmartPlaylist {
|
|||
|
||||
@Override
|
||||
public void clear(Context context) {
|
||||
// TODO
|
||||
SongPlayCountStore.getInstance(context).clear();
|
||||
App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,15 @@ import android.content.Context;
|
|||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import com.kabouzeid.gramophone.App;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.smartplaylist.CannotDeleteSingleSongsSongAdapter;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.smartplaylist.SmartPlaylistSongAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.CabHolder;
|
||||
import com.kabouzeid.gramophone.loader.LastAddedLoader;
|
||||
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
|
||||
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.provider.RecentlyPlayedStore;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
|
|
@ -24,8 +27,7 @@ public class RecentlyPlayedPlaylist extends SmartPlaylist {
|
|||
|
||||
@Override
|
||||
public ArrayList<Song> getSongs(Context context) {
|
||||
// TODO replace with getSongs() for recently played. This is just a place holder
|
||||
return LastAddedLoader.getLastAddedSongs(context);
|
||||
return TopAndRecentlyPlayedTracksLoader.getRecentlyPlayedTracks(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -35,6 +37,7 @@ public class RecentlyPlayedPlaylist extends SmartPlaylist {
|
|||
|
||||
@Override
|
||||
public void clear(Context context) {
|
||||
// TODO
|
||||
RecentlyPlayedStore.getInstance(context).clear();
|
||||
App.bus.post(new DataBaseChangedEvent(DataBaseChangedEvent.PLAYLISTS_CHANGED));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
|||
|
||||
public class AlbumJSONStore extends SQLiteOpenHelper {
|
||||
|
||||
public static final String DATABASE_NAME = "albumJSONLastFM.db";
|
||||
public static final String DATABASE_NAME = "albums_last_fm.db";
|
||||
private static final int VERSION = 1;
|
||||
private static AlbumJSONStore sInstance = null;
|
||||
|
||||
|
|
@ -23,12 +23,8 @@ public class AlbumJSONStore extends SQLiteOpenHelper {
|
|||
return sInstance;
|
||||
}
|
||||
|
||||
public static void deleteDatabase(final Context context) {
|
||||
context.deleteDatabase(DATABASE_NAME);
|
||||
}
|
||||
|
||||
public void addAlbumJSON(final String albumAndArtistName, final String JSON) {
|
||||
if (albumAndArtistName == null || JSON == null) {
|
||||
public void addAlbumJSON(final String albumAndArtistName, final String json) {
|
||||
if (albumAndArtistName == null || json == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -37,34 +33,34 @@ public class AlbumJSONStore extends SQLiteOpenHelper {
|
|||
|
||||
database.beginTransaction();
|
||||
|
||||
values.put(AlbumJSONColumns.ALBUMANDARTIST_NAME, albumAndArtistName.trim().toLowerCase());
|
||||
values.put(AlbumJSONColumns.JSON, JSON);
|
||||
values.put(AlbumJSONColumns.ALBUM_PLUS_ARTIST_NAME, albumAndArtistName.trim().toLowerCase());
|
||||
values.put(AlbumJSONColumns.JSON_DATA, json);
|
||||
|
||||
database.insert(AlbumJSONColumns.NAME, null, values);
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
public String getAlbumJSON(final String albumAndArtistName) {
|
||||
public String getJSONData(final String albumAndArtistName) {
|
||||
if (albumAndArtistName == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
final String[] projection = new String[]{
|
||||
AlbumJSONColumns.JSON,
|
||||
AlbumJSONColumns.ALBUMANDARTIST_NAME
|
||||
AlbumJSONColumns.JSON_DATA,
|
||||
AlbumJSONColumns.ALBUM_PLUS_ARTIST_NAME
|
||||
};
|
||||
final String selection = AlbumJSONColumns.ALBUMANDARTIST_NAME + "=?";
|
||||
final String selection = AlbumJSONColumns.ALBUM_PLUS_ARTIST_NAME + "=?";
|
||||
final String[] having = new String[]{
|
||||
albumAndArtistName.trim().toLowerCase()
|
||||
};
|
||||
Cursor cursor = database.query(AlbumJSONColumns.NAME, projection, selection, having, null,
|
||||
null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final String JSON = cursor.getString(cursor.getColumnIndexOrThrow(AlbumJSONColumns.JSON));
|
||||
final String json = cursor.getString(cursor.getColumnIndexOrThrow(AlbumJSONColumns.JSON_DATA));
|
||||
cursor.close();
|
||||
return JSON;
|
||||
return json;
|
||||
}
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
|
|
@ -72,25 +68,25 @@ public class AlbumJSONStore extends SQLiteOpenHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void removeItem(final String albumAndArtistName) {
|
||||
public void removeAlbumJSON(final String albumAndArtistName) {
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
database.delete(AlbumJSONColumns.NAME, AlbumJSONColumns.ALBUMANDARTIST_NAME + " = ?", new String[]{
|
||||
database.delete(AlbumJSONColumns.NAME, AlbumJSONColumns.ALBUM_PLUS_ARTIST_NAME + " = ?", new String[]{
|
||||
albumAndArtistName.trim().toLowerCase()
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public interface AlbumJSONColumns {
|
||||
String NAME = "AlbumJSON";
|
||||
String ALBUMANDARTIST_NAME = "AlbumAndArtistName";
|
||||
String JSON = "JSON";
|
||||
String NAME = "album_json";
|
||||
String ALBUM_PLUS_ARTIST_NAME = "album_plus_artist_name";
|
||||
String JSON_DATA = "json_data";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS " + AlbumJSONColumns.NAME +
|
||||
" (" + AlbumJSONColumns.ALBUMANDARTIST_NAME + " TEXT NOT NULL," +
|
||||
AlbumJSONColumns.JSON + " TEXT NOT NULL);"
|
||||
" (" + AlbumJSONColumns.ALBUM_PLUS_ARTIST_NAME + " TEXT NOT NULL," +
|
||||
AlbumJSONColumns.JSON_DATA + " TEXT NOT NULL);"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import android.database.sqlite.SQLiteOpenHelper;
|
|||
|
||||
public class ArtistJSONStore extends SQLiteOpenHelper {
|
||||
|
||||
public static final String DATABASE_NAME = "artistJSONLastFM.db";
|
||||
public static final String DATABASE_NAME = "artists_last_fm.db";
|
||||
private static final int VERSION = 1;
|
||||
private static ArtistJSONStore sInstance = null;
|
||||
|
||||
|
|
@ -23,12 +23,8 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
return sInstance;
|
||||
}
|
||||
|
||||
public static void deleteDatabase(final Context context) {
|
||||
context.deleteDatabase(DATABASE_NAME);
|
||||
}
|
||||
|
||||
public void addArtistJSON(final String artistName, final String JSON) {
|
||||
if (artistName == null || JSON == null) {
|
||||
public void addArtistJSON(final String artistName, final String json) {
|
||||
if (artistName == null || json == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -38,7 +34,7 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
database.beginTransaction();
|
||||
|
||||
values.put(ArtistJSONColumns.ARTIST_NAME, artistName.trim().toLowerCase());
|
||||
values.put(ArtistJSONColumns.JSON, JSON);
|
||||
values.put(ArtistJSONColumns.JSON_DATA, json);
|
||||
|
||||
database.insert(ArtistJSONColumns.NAME, null, values);
|
||||
database.setTransactionSuccessful();
|
||||
|
|
@ -52,7 +48,7 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
final String[] projection = new String[]{
|
||||
ArtistJSONColumns.JSON,
|
||||
ArtistJSONColumns.JSON_DATA,
|
||||
ArtistJSONColumns.ARTIST_NAME
|
||||
};
|
||||
final String selection = ArtistJSONColumns.ARTIST_NAME + "=?";
|
||||
|
|
@ -62,9 +58,9 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
Cursor cursor = database.query(ArtistJSONColumns.NAME, projection, selection, having, null,
|
||||
null, null, null);
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
final String JSON = cursor.getString(cursor.getColumnIndexOrThrow(ArtistJSONColumns.JSON));
|
||||
final String json = cursor.getString(cursor.getColumnIndexOrThrow(ArtistJSONColumns.JSON_DATA));
|
||||
cursor.close();
|
||||
return JSON;
|
||||
return json;
|
||||
}
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
|
|
@ -72,7 +68,7 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
return null;
|
||||
}
|
||||
|
||||
public void removeItem(final String artistName) {
|
||||
public void removeArtistJSON(final String artistName) {
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
database.delete(ArtistJSONColumns.NAME, ArtistJSONColumns.ARTIST_NAME + "=?", new String[]{
|
||||
artistName.trim().toLowerCase()
|
||||
|
|
@ -81,16 +77,16 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
public interface ArtistJSONColumns {
|
||||
String NAME = "ArtistJSON";
|
||||
String ARTIST_NAME = "ArtistName";
|
||||
String JSON = "JSON";
|
||||
String NAME = "artist_json";
|
||||
String ARTIST_NAME = "artist_name";
|
||||
String JSON_DATA = "json_data";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS " + ArtistJSONColumns.NAME +
|
||||
" (" + ArtistJSONColumns.ARTIST_NAME + " TEXT NOT NULL," +
|
||||
ArtistJSONColumns.JSON + " TEXT NOT NULL);"
|
||||
ArtistJSONColumns.JSON_DATA + " TEXT NOT NULL);"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +96,4 @@ public class ArtistJSONStore extends SQLiteOpenHelper {
|
|||
db.execSQL("DROP TABLE IF EXISTS " + ArtistJSONColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* 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.kabouzeid.gramophone.provider;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
public class RecentlyPlayedStore extends SQLiteOpenHelper {
|
||||
private static final int MAX_ITEMS_IN_DB = 100;
|
||||
|
||||
public static final String DATABASE_NAME = "recently_played.db";
|
||||
private static final int VERSION = 1;
|
||||
private static RecentlyPlayedStore sInstance = null;
|
||||
|
||||
public RecentlyPlayedStore(final Context context) {
|
||||
super(context, DATABASE_NAME, null, VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
db.execSQL("CREATE TABLE IF NOT EXISTS " + RecentStoreColumns.NAME + " ("
|
||||
+ RecentStoreColumns.ID + " LONG NOT NULL," + RecentStoreColumns.TIME_PLAYED
|
||||
+ " LONG NOT NULL);");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// nothing to do here yet
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
db.execSQL("DROP TABLE IF EXISTS " + RecentStoreColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
public static synchronized RecentlyPlayedStore getInstance(final Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new RecentlyPlayedStore(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public void addSongId(final long songId) {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.beginTransaction();
|
||||
|
||||
try {
|
||||
removeSongId(songId);
|
||||
|
||||
// add the entry
|
||||
final ContentValues values = new ContentValues(2);
|
||||
values.put(RecentStoreColumns.ID, songId);
|
||||
values.put(RecentStoreColumns.TIME_PLAYED, System.currentTimeMillis());
|
||||
database.insert(RecentStoreColumns.NAME, null, values);
|
||||
|
||||
// if our db is too large, delete the extra items
|
||||
Cursor oldest = null;
|
||||
try {
|
||||
oldest = database.query(RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.TIME_PLAYED}, null, null, null, null,
|
||||
RecentStoreColumns.TIME_PLAYED + " ASC");
|
||||
|
||||
if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) {
|
||||
oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB);
|
||||
long timeOfRecordToKeep = oldest.getLong(0);
|
||||
|
||||
database.delete(RecentStoreColumns.NAME,
|
||||
RecentStoreColumns.TIME_PLAYED + " < ?",
|
||||
new String[]{String.valueOf(timeOfRecordToKeep)});
|
||||
|
||||
}
|
||||
} finally {
|
||||
if (oldest != null) {
|
||||
oldest.close();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeSongId(final long songId) {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.delete(RecentStoreColumns.NAME, RecentStoreColumns.ID + " = ?", new String[]{
|
||||
String.valueOf(songId)
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.delete(RecentStoreColumns.NAME, null, null);
|
||||
}
|
||||
|
||||
public boolean contains(long id) {
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
Cursor cursor = database.query(RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.ID},
|
||||
RecentStoreColumns.ID + "=?",
|
||||
new String[]{String.valueOf(id)},
|
||||
null, null, null, null);
|
||||
|
||||
boolean containsId = cursor != null && cursor.moveToFirst();
|
||||
if (cursor != null) {
|
||||
cursor.close();
|
||||
}
|
||||
return containsId;
|
||||
}
|
||||
|
||||
public Cursor queryRecentIds() {
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
return database.query(RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.ID}, null, null, null, null,
|
||||
RecentStoreColumns.TIME_PLAYED + " DESC");
|
||||
}
|
||||
|
||||
public interface RecentStoreColumns {
|
||||
String NAME = "recent_history";
|
||||
|
||||
String ID = "song_id";
|
||||
|
||||
String TIME_PLAYED = "time_played";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,400 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* 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.kabouzeid.gramophone.provider;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This database tracks the number of play counts for an individual song. This is used to drive
|
||||
* the top played tracks as well as the playlist images
|
||||
*/
|
||||
public class SongPlayCountStore extends SQLiteOpenHelper {
|
||||
private static SongPlayCountStore sInstance = null;
|
||||
|
||||
public static final String DATABASE_NAME = "song_play_count.db";
|
||||
private static final int VERSION = 1;
|
||||
|
||||
// interpolator curve applied for measuring the curve
|
||||
private static Interpolator sInterpolator = new AccelerateInterpolator(1.5f);
|
||||
|
||||
// how many weeks worth of playback to track
|
||||
private static final int NUM_WEEKS = 52;
|
||||
|
||||
// how high to multiply the interpolation curve
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static int INTERPOLATOR_HEIGHT = 50;
|
||||
|
||||
// how high the base value is. The ratio of the Height to Base is what really matters
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static int INTERPOLATOR_BASE = 25;
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7;
|
||||
|
||||
private static String WHERE_ID_EQUALS = SongPlayCountColumns.ID + "=?";
|
||||
|
||||
// number of weeks since epoch time
|
||||
private int mNumberOfWeeksSinceEpoch;
|
||||
|
||||
// used to track if we've walked through the db and updated all the rows
|
||||
private boolean mDatabaseUpdated;
|
||||
|
||||
public SongPlayCountStore(final Context context) {
|
||||
super(context, DATABASE_NAME, null, VERSION);
|
||||
|
||||
long msSinceEpoch = System.currentTimeMillis();
|
||||
mNumberOfWeeksSinceEpoch = (int) (msSinceEpoch / ONE_WEEK_IN_MS);
|
||||
|
||||
mDatabaseUpdated = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(final SQLiteDatabase db) {
|
||||
// create the play count table
|
||||
// WARNING: If you change the order of these columns
|
||||
// please update getColumnIndexForWeek
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("CREATE TABLE IF NOT EXISTS ");
|
||||
builder.append(SongPlayCountColumns.NAME);
|
||||
builder.append("(");
|
||||
builder.append(SongPlayCountColumns.ID);
|
||||
builder.append(" INT UNIQUE,");
|
||||
|
||||
for (int i = 0; i < NUM_WEEKS; i++) {
|
||||
builder.append(getColumnNameForWeek(i));
|
||||
builder.append(" INT DEFAULT 0,");
|
||||
}
|
||||
|
||||
builder.append(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX);
|
||||
builder.append(" INT NOT NULL,");
|
||||
|
||||
builder.append(SongPlayCountColumns.PLAY_COUNT_SCORE);
|
||||
builder.append(" REAL DEFAULT 0);");
|
||||
|
||||
db.execSQL(builder.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(final SQLiteDatabase db, final int oldVersion, final int newVersion) {
|
||||
// No upgrade path needed yet
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
// If we ever have downgrade, drop the table to be safe
|
||||
db.execSQL("DROP TABLE IF EXISTS " + SongPlayCountColumns.NAME);
|
||||
onCreate(db);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param context The {@link Context} to use
|
||||
* @return A new instance of this class.
|
||||
*/
|
||||
public static synchronized SongPlayCountStore getInstance(final Context context) {
|
||||
if (sInstance == null) {
|
||||
sInstance = new SongPlayCountStore(context.getApplicationContext());
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases the play count of a song by 1
|
||||
*
|
||||
* @param songId The song id to increase the play count
|
||||
*/
|
||||
public void bumpSongCount(final long songId) {
|
||||
if (songId < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
updateExistingRow(database, songId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* This creates a new entry that indicates a song has been played once as well as its score
|
||||
*
|
||||
* @param database a write able database
|
||||
* @param songId the id of the track
|
||||
*/
|
||||
private void createNewPlayedEntry(final SQLiteDatabase database, final long songId) {
|
||||
// no row exists, create a new one
|
||||
float newScore = getScoreMultiplierForWeek(0);
|
||||
int newPlayCount = 1;
|
||||
|
||||
final ContentValues values = new ContentValues(3);
|
||||
values.put(SongPlayCountColumns.ID, songId);
|
||||
values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, newScore);
|
||||
values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch);
|
||||
values.put(getColumnNameForWeek(0), newPlayCount);
|
||||
|
||||
database.insert(SongPlayCountColumns.NAME, null, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will take a song entry and update it to the latest week and increase the count
|
||||
* for the current week by 1 if necessary
|
||||
*
|
||||
* @param database a writeable database
|
||||
* @param id the id of the track to bump
|
||||
* @param bumpCount whether to bump the current's week play count by 1 and adjust the score
|
||||
*/
|
||||
private void updateExistingRow(final SQLiteDatabase database, final long id, boolean bumpCount) {
|
||||
String stringId = String.valueOf(id);
|
||||
|
||||
// begin the transaction
|
||||
database.beginTransaction();
|
||||
|
||||
// get the cursor of this content inside the transaction
|
||||
final Cursor cursor = database.query(SongPlayCountColumns.NAME, null, WHERE_ID_EQUALS,
|
||||
new String[]{stringId}, null, null, null);
|
||||
|
||||
// if we have a result
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// figure how many weeks since we last updated
|
||||
int lastUpdatedIndex = cursor.getColumnIndex(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX);
|
||||
int lastUpdatedWeek = cursor.getInt(lastUpdatedIndex);
|
||||
int weekDiff = mNumberOfWeeksSinceEpoch - lastUpdatedWeek;
|
||||
|
||||
// if it's more than the number of weeks we track, delete it and create a new entry
|
||||
if (Math.abs(weekDiff) >= NUM_WEEKS) {
|
||||
// this entry needs to be dropped since it is too outdated
|
||||
deleteEntry(database, stringId);
|
||||
if (bumpCount) {
|
||||
createNewPlayedEntry(database, id);
|
||||
}
|
||||
} else if (weekDiff != 0) {
|
||||
// else, shift the weeks
|
||||
int[] playCounts = new int[NUM_WEEKS];
|
||||
|
||||
if (weekDiff > 0) {
|
||||
// time is shifted forwards
|
||||
for (int i = 0; i < NUM_WEEKS - weekDiff; i++) {
|
||||
playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i));
|
||||
}
|
||||
} else if (weekDiff < 0) {
|
||||
// time is shifted backwards (by user) - nor typical behavior but we
|
||||
// will still handle it
|
||||
|
||||
// since weekDiff is -ve, NUM_WEEKS + weekDiff is the real # of weeks we have to
|
||||
// transfer. Then we transfer the old week i - weekDiff to week i
|
||||
// for example if the user shifted back 2 weeks, ie -2, then for 0 to
|
||||
// NUM_WEEKS + (-2) we set the new week i = old week i - (-2) or i+2
|
||||
for (int i = 0; i < NUM_WEEKS + weekDiff; i++) {
|
||||
playCounts[i] = cursor.getInt(getColumnIndexForWeek(i - weekDiff));
|
||||
}
|
||||
}
|
||||
|
||||
// bump the count
|
||||
if (bumpCount) {
|
||||
playCounts[0]++;
|
||||
}
|
||||
|
||||
float score = calculateScore(playCounts);
|
||||
|
||||
// if the score is non-existant, then delete it
|
||||
if (score < .01f) {
|
||||
deleteEntry(database, stringId);
|
||||
} else {
|
||||
// create the content values
|
||||
ContentValues values = new ContentValues(NUM_WEEKS + 2);
|
||||
values.put(SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX, mNumberOfWeeksSinceEpoch);
|
||||
values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score);
|
||||
|
||||
for (int i = 0; i < NUM_WEEKS; i++) {
|
||||
values.put(getColumnNameForWeek(i), playCounts[i]);
|
||||
}
|
||||
|
||||
// update the entry
|
||||
database.update(SongPlayCountColumns.NAME, values, WHERE_ID_EQUALS,
|
||||
new String[]{stringId});
|
||||
}
|
||||
} else if (bumpCount) {
|
||||
// else no shifting, just update the scores
|
||||
ContentValues values = new ContentValues(2);
|
||||
|
||||
// increase the score by a single score amount
|
||||
int scoreIndex = cursor.getColumnIndex(SongPlayCountColumns.PLAY_COUNT_SCORE);
|
||||
float score = cursor.getFloat(scoreIndex) + getScoreMultiplierForWeek(0);
|
||||
values.put(SongPlayCountColumns.PLAY_COUNT_SCORE, score);
|
||||
|
||||
// increase the play count by 1
|
||||
values.put(getColumnNameForWeek(0), cursor.getInt(getColumnIndexForWeek(0)) + 1);
|
||||
|
||||
// update the entry
|
||||
database.update(SongPlayCountColumns.NAME, values, WHERE_ID_EQUALS,
|
||||
new String[]{stringId});
|
||||
}
|
||||
|
||||
cursor.close();
|
||||
} else if (bumpCount) {
|
||||
// if we have no existing results, create a new one
|
||||
createNewPlayedEntry(database, id);
|
||||
}
|
||||
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
database.delete(SongPlayCountColumns.NAME, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a cursor containing the top songs played. Note this only returns songs that have been
|
||||
* played at least once in the past NUM_WEEKS
|
||||
*
|
||||
* @param numResults number of results to limit by. If <= 0 it returns all results
|
||||
* @return the top tracks
|
||||
*/
|
||||
public Cursor getTopPlayedResults(int numResults) {
|
||||
updateResults();
|
||||
|
||||
final SQLiteDatabase database = getReadableDatabase();
|
||||
return database.query(SongPlayCountColumns.NAME, new String[]{SongPlayCountColumns.ID},
|
||||
null, null, null, null, SongPlayCountColumns.PLAY_COUNT_SCORE + " DESC",
|
||||
(numResults <= 0 ? null : String.valueOf(numResults)));
|
||||
}
|
||||
|
||||
/**
|
||||
* This updates all the results for the getTopPlayedResults so that we can get an
|
||||
* accurate list of the top played results
|
||||
*/
|
||||
private synchronized void updateResults() {
|
||||
if (mDatabaseUpdated) {
|
||||
return;
|
||||
}
|
||||
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
|
||||
database.beginTransaction();
|
||||
|
||||
int oldestWeekWeCareAbout = mNumberOfWeeksSinceEpoch - NUM_WEEKS + 1;
|
||||
// delete rows we don't care about anymore
|
||||
database.delete(SongPlayCountColumns.NAME, SongPlayCountColumns.LAST_UPDATED_WEEK_INDEX
|
||||
+ " < " + oldestWeekWeCareAbout, null);
|
||||
|
||||
// get the remaining rows
|
||||
Cursor cursor = database.query(SongPlayCountColumns.NAME,
|
||||
new String[]{SongPlayCountColumns.ID},
|
||||
null, null, null, null, null);
|
||||
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
// for each row, update it
|
||||
do {
|
||||
updateExistingRow(database, cursor.getLong(0), false);
|
||||
} while (cursor.moveToNext());
|
||||
|
||||
cursor.close();
|
||||
}
|
||||
|
||||
mDatabaseUpdated = true;
|
||||
database.setTransactionSuccessful();
|
||||
database.endTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param songId The song Id to remove.
|
||||
*/
|
||||
public void removeItem(final long songId) {
|
||||
final SQLiteDatabase database = getWritableDatabase();
|
||||
deleteEntry(database, String.valueOf(songId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes the entry
|
||||
*
|
||||
* @param database database to use
|
||||
* @param stringId id to delete
|
||||
*/
|
||||
private void deleteEntry(final SQLiteDatabase database, final String stringId) {
|
||||
database.delete(SongPlayCountColumns.NAME, WHERE_ID_EQUALS, new String[]{stringId});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the score of the song given the play counts
|
||||
*
|
||||
* @param playCounts an array of the # of times a song has been played for each week
|
||||
* where playCounts[N] is the # of times it was played N weeks ago
|
||||
* @return the score
|
||||
*/
|
||||
private static float calculateScore(final int[] playCounts) {
|
||||
if (playCounts == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
float score = 0;
|
||||
for (int i = 0; i < Math.min(playCounts.length, NUM_WEEKS); i++) {
|
||||
score += playCounts[i] * getScoreMultiplierForWeek(i);
|
||||
}
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column name for each week #
|
||||
*
|
||||
* @param week number
|
||||
* @return the column name
|
||||
*/
|
||||
private static String getColumnNameForWeek(final int week) {
|
||||
return SongPlayCountColumns.WEEK_PLAY_COUNT + String.valueOf(week);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the score multiplier for each week
|
||||
*
|
||||
* @param week number
|
||||
* @return the multiplier to apply
|
||||
*/
|
||||
private static float getScoreMultiplierForWeek(final int week) {
|
||||
return sInterpolator.getInterpolation(1 - (week / (float) NUM_WEEKS)) * INTERPOLATOR_HEIGHT
|
||||
+ INTERPOLATOR_BASE;
|
||||
}
|
||||
|
||||
/**
|
||||
* For some performance gain, return a static value for the column index for a week
|
||||
* WARNING: This function assumes you have selected all columns for it to work
|
||||
*
|
||||
* @param week number
|
||||
* @return column index of that week
|
||||
*/
|
||||
private static int getColumnIndexForWeek(final int week) {
|
||||
// ID, followed by the weeks columns
|
||||
return 1 + week;
|
||||
}
|
||||
|
||||
public interface SongPlayCountColumns {
|
||||
|
||||
String NAME = "song_play_count";
|
||||
|
||||
String ID = "song_id";
|
||||
|
||||
String WEEK_PLAY_COUNT = "week";
|
||||
|
||||
String LAST_UPDATED_WEEK_INDEX = "week_index";
|
||||
|
||||
String PLAY_COUNT_SCORE = "play_count_score";
|
||||
}
|
||||
}
|
||||
|
|
@ -33,6 +33,8 @@ import com.kabouzeid.gramophone.helper.PlayingNotificationHelper;
|
|||
import com.kabouzeid.gramophone.helper.ShuffleHelper;
|
||||
import com.kabouzeid.gramophone.misc.AppKeys;
|
||||
import com.kabouzeid.gramophone.model.Song;
|
||||
import com.kabouzeid.gramophone.provider.RecentlyPlayedStore;
|
||||
import com.kabouzeid.gramophone.provider.SongPlayCountStore;
|
||||
import com.kabouzeid.gramophone.util.InternalStorageUtil;
|
||||
import com.kabouzeid.gramophone.util.MusicUtil;
|
||||
import com.kabouzeid.gramophone.util.PreferenceUtils;
|
||||
|
|
@ -110,6 +112,8 @@ public class MusicService extends Service {
|
|||
private MusicPlayerHandler playerHandler;
|
||||
private boolean isFadingDown = false;
|
||||
private HandlerThread handlerThread;
|
||||
private RecentlyPlayedStore recentlyPlayedStore;
|
||||
private SongPlayCountStore songPlayCountStore;
|
||||
|
||||
private final BroadcastReceiver becomingNoisyReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
|
|
@ -145,6 +149,9 @@ public class MusicService extends Service {
|
|||
|
||||
playingNotificationHelper = new PlayingNotificationHelper(this);
|
||||
|
||||
recentlyPlayedStore = RecentlyPlayedStore.getInstance(this);
|
||||
songPlayCountStore = SongPlayCountStore.getInstance(this);
|
||||
|
||||
shuffleMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(AppKeys.SP_SHUFFLE_MODE, 0);
|
||||
repeatMode = PreferenceManager.getDefaultSharedPreferences(this).getInt(AppKeys.SP_REPEAT_MODE, 0);
|
||||
|
||||
|
|
@ -543,7 +550,9 @@ public class MusicService extends Service {
|
|||
this.originalPlayingQueue = restoredOriginalQueue;
|
||||
this.playingQueue = restoredQueue;
|
||||
|
||||
openTrackAndPrepareNextAt(restoredPosition);
|
||||
setPosition(restoredPosition);
|
||||
openCurrent();
|
||||
prepareNext();
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
|
@ -808,6 +817,8 @@ public class MusicService extends Service {
|
|||
updateNotification();
|
||||
updateWidgets();
|
||||
updateRemoteControlClient();
|
||||
recentlyPlayedStore.addSongId(currentSong.id);
|
||||
songPlayCountStore.bumpSongCount(currentSong.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -438,6 +438,9 @@ public class AlbumDetailActivity extends AbsFabActivity implements PaletteColorH
|
|||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
else super.onBackPressed();
|
||||
else {
|
||||
recyclerView.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -69,7 +69,7 @@ import butterknife.InjectView;
|
|||
|
||||
/**
|
||||
* A lot of hackery is done in this activity. Changing things may will brake the whole activity.
|
||||
* <p>
|
||||
* <p/>
|
||||
* Should be kinda stable ONLY AS IT IS!!!
|
||||
*/
|
||||
public class ArtistDetailActivity extends AbsFabActivity implements PaletteColorHolder, CabHolder {
|
||||
|
|
@ -423,6 +423,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
|
|||
super.enableViews();
|
||||
songListView.setEnabled(true);
|
||||
toolbar.setEnabled(true);
|
||||
albumRecyclerView.setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -430,6 +431,7 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
|
|||
super.disableViews();
|
||||
songListView.setEnabled(false);
|
||||
toolbar.setEnabled(false);
|
||||
albumRecyclerView.setEnabled(false);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -524,6 +526,9 @@ public class ArtistDetailActivity extends AbsFabActivity implements PaletteColor
|
|||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
else super.onBackPressed();
|
||||
else {
|
||||
albumRecyclerView.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,17 +7,21 @@ import android.support.v7.widget.Toolbar;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.kabouzeid.gramophone.App;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.AbsPlaylistSongAdapter;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.PlaylistSongAdapter;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.smartplaylist.SmartPlaylistSongAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.CabHolder;
|
||||
import com.kabouzeid.gramophone.loader.PlaylistSongLoader;
|
||||
import com.kabouzeid.gramophone.misc.DragSortRecycler;
|
||||
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
|
||||
import com.kabouzeid.gramophone.model.Playlist;
|
||||
import com.kabouzeid.gramophone.model.PlaylistSong;
|
||||
import com.kabouzeid.gramophone.model.smartplaylist.SmartPlaylist;
|
||||
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
|
||||
import com.kabouzeid.gramophone.util.NavigationUtil;
|
||||
import com.kabouzeid.gramophone.util.PlaylistsUtil;
|
||||
|
|
@ -26,56 +30,40 @@ import com.squareup.otto.Subscribe;
|
|||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
|
||||
public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder {
|
||||
|
||||
public static final String TAG = PlaylistDetailActivity.class.getSimpleName();
|
||||
|
||||
public static String EXTRA_PLAYLIST = "extra_playlist";
|
||||
|
||||
@InjectView(R.id.recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
@InjectView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
@InjectView(android.R.id.empty)
|
||||
TextView empty;
|
||||
|
||||
private Playlist playlist;
|
||||
private MaterialCab cab;
|
||||
private PlaylistSongAdapter adapter;
|
||||
private AbsPlaylistSongAdapter adapter;
|
||||
private ArrayList<PlaylistSong> songs;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_playlist_detail);
|
||||
ButterKnife.inject(this);
|
||||
|
||||
getIntentExtras();
|
||||
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
|
||||
songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
|
||||
adapter = new PlaylistSongAdapter(this, songs, this);
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
recyclerView.setAdapter(adapter);
|
||||
setUpRecyclerView();
|
||||
|
||||
findViewById(android.R.id.empty).setVisibility(
|
||||
songs.size() == 0 ? View.VISIBLE : View.GONE
|
||||
);
|
||||
checkIsEmpty();
|
||||
|
||||
DragSortRecycler dragSortRecycler = new DragSortRecycler();
|
||||
dragSortRecycler.setViewHandleId(R.id.album_art);
|
||||
|
||||
dragSortRecycler.setOnItemMovedListener(new DragSortRecycler.OnItemMovedListener() {
|
||||
@Override
|
||||
public void onItemMoved(int from, int to) {
|
||||
PlaylistSong song = songs.remove(from);
|
||||
songs.add(to, song);
|
||||
adapter.notifyDataSetChanged();
|
||||
PlaylistsUtil.moveItem(PlaylistDetailActivity.this, playlist.id, from, to);
|
||||
}
|
||||
});
|
||||
|
||||
recyclerView.addItemDecoration(dragSortRecycler);
|
||||
recyclerView.addOnItemTouchListener(dragSortRecycler);
|
||||
recyclerView.setOnScrollListener(dragSortRecycler.getScrollListener());
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
toolbar.setBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimary());
|
||||
setSupportActionBar(toolbar);
|
||||
getSupportActionBar().setTitle(playlist.name);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
setUpToolBar();
|
||||
|
||||
if (PreferenceUtils.getInstance(this).coloredNavigationBarPlaylist())
|
||||
setNavigationBarThemeColor();
|
||||
|
|
@ -84,6 +72,41 @@ public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder
|
|||
App.bus.register(this);
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
if (playlist instanceof SmartPlaylist) {
|
||||
adapter = ((SmartPlaylist) playlist).createAdapter(this, this);
|
||||
} else {
|
||||
songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
|
||||
adapter = new PlaylistSongAdapter(this, songs, this);
|
||||
|
||||
DragSortRecycler dragSortRecycler = new DragSortRecycler();
|
||||
dragSortRecycler.setViewHandleId(R.id.album_art);
|
||||
dragSortRecycler.setOnItemMovedListener(new DragSortRecycler.OnItemMovedListener() {
|
||||
@Override
|
||||
public void onItemMoved(int from, int to) {
|
||||
PlaylistSong song = songs.remove(from);
|
||||
songs.add(to, song);
|
||||
adapter.notifyDataSetChanged();
|
||||
PlaylistsUtil.moveItem(PlaylistDetailActivity.this, playlist.id, from, to);
|
||||
}
|
||||
});
|
||||
|
||||
recyclerView.addItemDecoration(dragSortRecycler);
|
||||
recyclerView.addOnItemTouchListener(dragSortRecycler);
|
||||
recyclerView.setOnScrollListener(dragSortRecycler.getScrollListener());
|
||||
}
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void setUpToolBar() {
|
||||
toolbar.setBackgroundColor(getThemeColorPrimary());
|
||||
setSupportActionBar(toolbar);
|
||||
//noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(playlist.name);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void getIntentExtras() {
|
||||
Bundle intentExtras = getIntent().getExtras();
|
||||
try {
|
||||
|
|
@ -114,7 +137,7 @@ public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder
|
|||
NavigationUtil.openEqualizer(this);
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
super.onBackPressed();
|
||||
onBackPressed();
|
||||
return true;
|
||||
case R.id.action_current_playing:
|
||||
NavigationUtil.openCurrentPlayingIfPossible(this, getSharedViewsWithFab(null));
|
||||
|
|
@ -147,11 +170,14 @@ public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder
|
|||
switch (event.getAction()) {
|
||||
case DataBaseChangedEvent.PLAYLISTS_CHANGED:
|
||||
case DataBaseChangedEvent.DATABASE_CHANGED:
|
||||
songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
|
||||
adapter.updateDataSet(songs);
|
||||
findViewById(android.R.id.empty).setVisibility(
|
||||
songs.size() == 0 ? View.VISIBLE : View.GONE
|
||||
);
|
||||
if (adapter instanceof SmartPlaylistSongAdapter) {
|
||||
((SmartPlaylistSongAdapter) adapter).updateDataSet();
|
||||
} else {
|
||||
songs = PlaylistSongLoader.getPlaylistSongList(this, playlist.id);
|
||||
//noinspection unchecked
|
||||
adapter.updateDataSet(songs);
|
||||
}
|
||||
checkIsEmpty();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -159,6 +185,15 @@ public class PlaylistDetailActivity extends AbsFabActivity implements CabHolder
|
|||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
else super.onBackPressed();
|
||||
else {
|
||||
recyclerView.stopScroll();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
empty.setVisibility(
|
||||
adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,158 +0,0 @@
|
|||
package com.kabouzeid.gramophone.ui.activities;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.widget.GridLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialcab.MaterialCab;
|
||||
import com.kabouzeid.gramophone.App;
|
||||
import com.kabouzeid.gramophone.R;
|
||||
import com.kabouzeid.gramophone.adapter.songadapter.smartplaylist.SmartPlaylistSongAdapter;
|
||||
import com.kabouzeid.gramophone.interfaces.CabHolder;
|
||||
import com.kabouzeid.gramophone.model.DataBaseChangedEvent;
|
||||
import com.kabouzeid.gramophone.model.smartplaylist.SmartPlaylist;
|
||||
import com.kabouzeid.gramophone.ui.activities.base.AbsFabActivity;
|
||||
import com.kabouzeid.gramophone.util.NavigationUtil;
|
||||
import com.kabouzeid.gramophone.util.PreferenceUtils;
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
|
||||
public class SmartPlaylistDetailActivity extends AbsFabActivity implements CabHolder {
|
||||
|
||||
public static final String TAG = SmartPlaylistDetailActivity.class.getSimpleName();
|
||||
|
||||
@InjectView(R.id.recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
@InjectView(R.id.toolbar)
|
||||
Toolbar toolbar;
|
||||
@InjectView(android.R.id.empty)
|
||||
TextView empty;
|
||||
|
||||
private SmartPlaylist playlist;
|
||||
private MaterialCab cab;
|
||||
private SmartPlaylistSongAdapter adapter;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_playlist_detail);
|
||||
ButterKnife.inject(this);
|
||||
|
||||
getIntentExtras();
|
||||
|
||||
setUpRecyclerView();
|
||||
|
||||
checkIsEmpty();
|
||||
|
||||
setUpToolBar();
|
||||
|
||||
if (PreferenceUtils.getInstance(this).coloredNavigationBarPlaylist())
|
||||
setNavigationBarThemeColor();
|
||||
setStatusBarThemeColor();
|
||||
|
||||
App.bus.register(this);
|
||||
}
|
||||
|
||||
private void setUpRecyclerView() {
|
||||
adapter = playlist.createAdapter(this, this);
|
||||
|
||||
recyclerView.setLayoutManager(new GridLayoutManager(this, 1));
|
||||
recyclerView.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void setUpToolBar() {
|
||||
toolbar.setBackgroundColor(getThemeColorPrimary());
|
||||
setSupportActionBar(toolbar);
|
||||
//noinspection ConstantConditions
|
||||
getSupportActionBar().setTitle(playlist.name);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
private void getIntentExtras() {
|
||||
Bundle intentExtras = getIntent().getExtras();
|
||||
try {
|
||||
playlist = (SmartPlaylist) intentExtras.getSerializable(PlaylistDetailActivity.EXTRA_PLAYLIST);
|
||||
} catch (ClassCastException ignored) {
|
||||
}
|
||||
if (playlist == null) {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTag() {
|
||||
return TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_playlist_detail, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
int id = item.getItemId();
|
||||
switch (id) {
|
||||
case R.id.action_equalizer:
|
||||
NavigationUtil.openEqualizer(this);
|
||||
return true;
|
||||
case android.R.id.home:
|
||||
super.onBackPressed();
|
||||
return true;
|
||||
case R.id.action_current_playing:
|
||||
NavigationUtil.openCurrentPlayingIfPossible(this, getSharedViewsWithFab(null));
|
||||
return true;
|
||||
case R.id.action_playing_queue:
|
||||
NavigationUtil.openPlayingQueueDialog(this);
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MaterialCab openCab(final int menu, final MaterialCab.Callback callback) {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
cab = new MaterialCab(this, R.id.cab_stub)
|
||||
.setMenu(menu)
|
||||
.setBackgroundColor(PreferenceUtils.getInstance(this).getThemeColorPrimary())
|
||||
.start(callback);
|
||||
return cab;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
App.bus.unregister(this);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onDataBaseEvent(DataBaseChangedEvent event) {
|
||||
switch (event.getAction()) {
|
||||
case DataBaseChangedEvent.PLAYLISTS_CHANGED:
|
||||
case DataBaseChangedEvent.DATABASE_CHANGED:
|
||||
adapter.updateDataSet();
|
||||
checkIsEmpty();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (cab != null && cab.isActive()) cab.finish();
|
||||
else super.onBackPressed();
|
||||
}
|
||||
|
||||
private void checkIsEmpty() {
|
||||
empty.setVisibility(
|
||||
adapter.getItemCount() == 0 ? View.VISIBLE : View.GONE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@ package com.kabouzeid.gramophone.ui.fragments.mainactivityfragments;
|
|||
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.LayoutRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.StringRes;
|
||||
import android.support.design.widget.AppBarLayout;
|
||||
import android.support.design.widget.AppBarLayout.OnOffsetChangedListener;
|
||||
|
|
@ -29,9 +30,11 @@ public abstract class AbsMainActivityRecyclerViewFragment extends AbsMainActivit
|
|||
|
||||
@InjectView(R.id.recycler_view)
|
||||
RecyclerView recyclerView;
|
||||
@Nullable
|
||||
@Optional
|
||||
@InjectView(android.R.id.empty)
|
||||
TextView empty;
|
||||
@Nullable
|
||||
@Optional
|
||||
@InjectView(R.id.fast_scroller)
|
||||
FastScroller fastScroller;
|
||||
|
|
|
|||
|
|
@ -16,12 +16,10 @@ import com.kabouzeid.gramophone.helper.MusicPlayerRemote;
|
|||
import com.kabouzeid.gramophone.interfaces.KabViewsDisableAble;
|
||||
import com.kabouzeid.gramophone.misc.AppKeys;
|
||||
import com.kabouzeid.gramophone.model.Playlist;
|
||||
import com.kabouzeid.gramophone.model.smartplaylist.SmartPlaylist;
|
||||
import com.kabouzeid.gramophone.ui.activities.AlbumDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.ArtistDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.MusicControllerActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.PlaylistDetailActivity;
|
||||
import com.kabouzeid.gramophone.ui.activities.SmartPlaylistDetailActivity;
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
|
|
@ -72,11 +70,7 @@ public class NavigationUtil {
|
|||
((KabViewsDisableAble) activity).disableViews();
|
||||
|
||||
final Intent intent;
|
||||
if (playlist instanceof SmartPlaylist) {
|
||||
intent = new Intent(activity, SmartPlaylistDetailActivity.class);
|
||||
} else {
|
||||
intent = new Intent(activity, PlaylistDetailActivity.class);
|
||||
}
|
||||
intent = new Intent(activity, PlaylistDetailActivity.class);
|
||||
intent.putExtra(PlaylistDetailActivity.EXTRA_PLAYLIST, playlist);
|
||||
|
||||
if (sharedViews != null) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue