Add a new smart playlist "Not played lately" playlist (#613)
* Add "Not played lately" playlist (#1) * Fix bad recent playlist construction (#6) * Revert History rename * Code review
This commit is contained in:
parent
71f5072624
commit
764751381a
9 changed files with 126 additions and 8 deletions
|
|
@ -18,7 +18,7 @@ public class LastAddedLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Cursor makeLastAddedCursor(@NonNull final Context context) {
|
public static Cursor makeLastAddedCursor(@NonNull final Context context) {
|
||||||
long cutoff = PreferenceUtil.getInstance(context).getLastAddedCutoff();
|
long cutoff = PreferenceUtil.getInstance(context).getLastAddedCutoffTimeSecs();
|
||||||
|
|
||||||
return SongLoader.makeSongCursor(
|
return SongLoader.makeSongCursor(
|
||||||
context,
|
context,
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ package com.kabouzeid.gramophone.loader;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.database.Cursor;
|
import android.database.Cursor;
|
||||||
import android.provider.BaseColumns;
|
import android.provider.BaseColumns;
|
||||||
|
import android.provider.MediaStore;
|
||||||
import android.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
|
@ -26,6 +27,8 @@ import com.kabouzeid.gramophone.model.Song;
|
||||||
import com.kabouzeid.gramophone.provider.HistoryStore;
|
import com.kabouzeid.gramophone.provider.HistoryStore;
|
||||||
import com.kabouzeid.gramophone.provider.SongPlayCountStore;
|
import com.kabouzeid.gramophone.provider.SongPlayCountStore;
|
||||||
|
|
||||||
|
import com.kabouzeid.gramophone.util.PreferenceUtil;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public class TopAndRecentlyPlayedTracksLoader {
|
public class TopAndRecentlyPlayedTracksLoader {
|
||||||
|
|
@ -36,6 +39,23 @@ public class TopAndRecentlyPlayedTracksLoader {
|
||||||
return SongLoader.getSongs(makeRecentTracksCursorAndClearUpDatabase(context));
|
return SongLoader.getSongs(makeRecentTracksCursorAndClearUpDatabase(context));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static ArrayList<Song> getNotRecentlyPlayedTracks
|
||||||
|
(@NonNull Context context) {
|
||||||
|
ArrayList<Song> allSongs = SongLoader.getSongs(
|
||||||
|
SongLoader.makeSongCursor(
|
||||||
|
context,
|
||||||
|
null, null,
|
||||||
|
MediaStore.Audio.Media.DATE_ADDED + " ASC"));
|
||||||
|
|
||||||
|
ArrayList<Song> recentlyPlayedSongs = SongLoader.getSongs(
|
||||||
|
makeRecentTracksCursorAndClearUpDatabase(context));
|
||||||
|
|
||||||
|
allSongs.removeAll(recentlyPlayedSongs);
|
||||||
|
|
||||||
|
return allSongs;
|
||||||
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public static ArrayList<Song> getTopTracks(@NonNull Context context) {
|
public static ArrayList<Song> getTopTracks(@NonNull Context context) {
|
||||||
return SongLoader.getSongs(makeTopTracksCursorAndClearUpDatabase(context));
|
return SongLoader.getSongs(makeTopTracksCursorAndClearUpDatabase(context));
|
||||||
|
|
@ -76,7 +96,8 @@ public class TopAndRecentlyPlayedTracksLoader {
|
||||||
@Nullable
|
@Nullable
|
||||||
private static SortedLongCursor makeRecentTracksCursorImpl(@NonNull final Context context) {
|
private static SortedLongCursor makeRecentTracksCursorImpl(@NonNull final Context context) {
|
||||||
// first get the top results ids from the internal database
|
// first get the top results ids from the internal database
|
||||||
Cursor songs = HistoryStore.getInstance(context).queryRecentIds();
|
final long cutoff = PreferenceUtil.getInstance(context).getRecentlyPlayedCutoffTimeMillis();
|
||||||
|
Cursor songs = HistoryStore.getInstance(context).queryRecentIds(cutoff);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return makeSortedCursor(context, songs,
|
return makeSortedCursor(context, songs,
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
package com.kabouzeid.gramophone.model.smartplaylist;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import com.kabouzeid.gramophone.R;
|
||||||
|
import com.kabouzeid.gramophone.loader.TopAndRecentlyPlayedTracksLoader;
|
||||||
|
import com.kabouzeid.gramophone.model.Song;
|
||||||
|
import com.kabouzeid.gramophone.provider.HistoryStore;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author SC (soncaokim)
|
||||||
|
*/
|
||||||
|
public class NotRecentlyPlayedPlaylist extends AbsSmartPlaylist {
|
||||||
|
|
||||||
|
public NotRecentlyPlayedPlaylist(@NonNull Context context) {
|
||||||
|
super(context.getString(R.string.not_recently_played), R.drawable.ic_library_music_white_24dp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public ArrayList<Song> getSongs(@NonNull Context context) {
|
||||||
|
return TopAndRecentlyPlayedTracksLoader.getNotRecentlyPlayedTracks(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear(@NonNull Context context) {
|
||||||
|
HistoryStore.getInstance(context).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int describeContents() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NotRecentlyPlayedPlaylist(Parcel in) {
|
||||||
|
super(in);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final Creator<NotRecentlyPlayedPlaylist> CREATOR = new Creator<NotRecentlyPlayedPlaylist>() {
|
||||||
|
public NotRecentlyPlayedPlaylist createFromParcel(Parcel source) {
|
||||||
|
return new NotRecentlyPlayedPlaylist(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotRecentlyPlayedPlaylist[] newArray(int size) {
|
||||||
|
return new NotRecentlyPlayedPlaylist[size];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -25,7 +25,7 @@ import android.support.annotation.NonNull;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
public class HistoryStore extends SQLiteOpenHelper {
|
public class HistoryStore extends SQLiteOpenHelper {
|
||||||
private static final int MAX_ITEMS_IN_DB = 100;
|
private static final int MAX_ITEMS_IN_DB = 5000;
|
||||||
|
|
||||||
public static final String DATABASE_NAME = "history.db";
|
public static final String DATABASE_NAME = "history.db";
|
||||||
private static final int VERSION = 1;
|
private static final int VERSION = 1;
|
||||||
|
|
@ -136,10 +136,14 @@ public class HistoryStore extends SQLiteOpenHelper {
|
||||||
return containsId;
|
return containsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Cursor queryRecentIds() {
|
public Cursor queryRecentIds(long cutoff) {
|
||||||
final SQLiteDatabase database = getReadableDatabase();
|
final SQLiteDatabase database = getReadableDatabase();
|
||||||
|
|
||||||
return database.query(RecentStoreColumns.NAME,
|
return database.query(RecentStoreColumns.NAME,
|
||||||
new String[]{RecentStoreColumns.ID}, null, null, null, null,
|
new String[]{RecentStoreColumns.ID},
|
||||||
|
RecentStoreColumns.TIME_PLAYED + ">?",
|
||||||
|
new String[]{String.valueOf(cutoff)},
|
||||||
|
null, null,
|
||||||
RecentStoreColumns.TIME_PLAYED + " DESC");
|
RecentStoreColumns.TIME_PLAYED + " DESC");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import com.kabouzeid.gramophone.model.Playlist;
|
||||||
import com.kabouzeid.gramophone.model.smartplaylist.HistoryPlaylist;
|
import com.kabouzeid.gramophone.model.smartplaylist.HistoryPlaylist;
|
||||||
import com.kabouzeid.gramophone.model.smartplaylist.LastAddedPlaylist;
|
import com.kabouzeid.gramophone.model.smartplaylist.LastAddedPlaylist;
|
||||||
import com.kabouzeid.gramophone.model.smartplaylist.MyTopTracksPlaylist;
|
import com.kabouzeid.gramophone.model.smartplaylist.MyTopTracksPlaylist;
|
||||||
|
import com.kabouzeid.gramophone.model.smartplaylist.NotRecentlyPlayedPlaylist;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
|
@ -80,6 +81,7 @@ public class PlaylistsFragment extends AbsLibraryPagerRecyclerViewFragment<Playl
|
||||||
|
|
||||||
playlists.add(new LastAddedPlaylist(context));
|
playlists.add(new LastAddedPlaylist(context));
|
||||||
playlists.add(new HistoryPlaylist(context));
|
playlists.add(new HistoryPlaylist(context));
|
||||||
|
playlists.add(new NotRecentlyPlayedPlaylist(context));
|
||||||
playlists.add(new MyTopTracksPlaylist(context));
|
playlists.add(new MyTopTracksPlaylist(context));
|
||||||
|
|
||||||
playlists.addAll(PlaylistLoader.getAllPlaylists(context));
|
playlists.addAll(PlaylistLoader.getAllPlaylists(context));
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ public final class PreferenceUtil {
|
||||||
public static final String GAPLESS_PLAYBACK = "gapless_playback";
|
public static final String GAPLESS_PLAYBACK = "gapless_playback";
|
||||||
|
|
||||||
public static final String LAST_ADDED_CUTOFF = "last_added_interval";
|
public static final String LAST_ADDED_CUTOFF = "last_added_interval";
|
||||||
|
public static final String RECENTLY_PLAYED_CUTOFF = "recently_played_interval";
|
||||||
|
|
||||||
public static final String ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen";
|
public static final String ALBUM_ART_ON_LOCKSCREEN = "album_art_on_lockscreen";
|
||||||
public static final String BLURRED_ALBUM_ART = "blurred_album_art";
|
public static final String BLURRED_ALBUM_ART = "blurred_album_art";
|
||||||
|
|
@ -266,11 +267,21 @@ public final class PreferenceUtil {
|
||||||
return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.GENRE_A_Z);
|
return mPreferences.getString(GENRE_SORT_ORDER, SortOrder.GenreSortOrder.GENRE_A_Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
public long getLastAddedCutoff() {
|
// The last added cutoff time is compared against the Android media store timestamps, which is seconds based.
|
||||||
|
public long getLastAddedCutoffTimeSecs() {
|
||||||
|
return getCutoffTimeMillis(LAST_ADDED_CUTOFF) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The recently played cutoff time is compared against the internal (private) database timestamps, which is milliseconds based.
|
||||||
|
public long getRecentlyPlayedCutoffTimeMillis() {
|
||||||
|
return getCutoffTimeMillis(RECENTLY_PLAYED_CUTOFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
private long getCutoffTimeMillis(final String cutoff) {
|
||||||
final CalendarUtil calendarUtil = new CalendarUtil();
|
final CalendarUtil calendarUtil = new CalendarUtil();
|
||||||
long interval;
|
long interval;
|
||||||
|
|
||||||
switch (mPreferences.getString(LAST_ADDED_CUTOFF, "")) {
|
switch (mPreferences.getString(cutoff, "")) {
|
||||||
case "today":
|
case "today":
|
||||||
interval = calendarUtil.getElapsedToday();
|
interval = calendarUtil.getElapsedToday();
|
||||||
break;
|
break;
|
||||||
|
|
@ -293,7 +304,7 @@ public final class PreferenceUtil {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (System.currentTimeMillis() - interval) / 1000;
|
return (System.currentTimeMillis() - interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getLastSleepTimerValue() {
|
public int getLastSleepTimerValue() {
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,7 @@
|
||||||
<string name="pref_title_ignore_media_store_artwork">Ignore Media Store covers</string>
|
<string name="pref_title_ignore_media_store_artwork">Ignore Media Store covers</string>
|
||||||
<string name="pref_title_gapless_playback">Gapless playback</string>
|
<string name="pref_title_gapless_playback">Gapless playback</string>
|
||||||
<string name="pref_title_audio_ducking">Reduce volume on focus loss</string>
|
<string name="pref_title_audio_ducking">Reduce volume on focus loss</string>
|
||||||
|
<string name="pref_title_recently_played_interval">Recently played playlist interval</string>
|
||||||
<string name="pref_title_last_added_interval">Last added playlist interval</string>
|
<string name="pref_title_last_added_interval">Last added playlist interval</string>
|
||||||
<string name="pref_title_synchronized_lyrics_show">Show synchronized lyrics</string>
|
<string name="pref_title_synchronized_lyrics_show">Show synchronized lyrics</string>
|
||||||
<string name="pref_title_remember_last_tab">Remember last tab</string>
|
<string name="pref_title_remember_last_tab">Remember last tab</string>
|
||||||
|
|
@ -174,6 +175,7 @@
|
||||||
<string name="last_added">Last added</string>
|
<string name="last_added">Last added</string>
|
||||||
<string name="history">History</string>
|
<string name="history">History</string>
|
||||||
<string name="my_top_tracks">My top tracks</string>
|
<string name="my_top_tracks">My top tracks</string>
|
||||||
|
<string name="not_recently_played">Not recently played</string>
|
||||||
<string name="remove_cover">Remove cover</string>
|
<string name="remove_cover">Remove cover</string>
|
||||||
<string name="download_from_last_fm">Download from Last.fm</string>
|
<string name="download_from_last_fm">Download from Last.fm</string>
|
||||||
<string name="pick_from_local_storage">Pick from local storage</string>
|
<string name="pick_from_local_storage">Pick from local storage</string>
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,22 @@
|
||||||
<item>never</item>
|
<item>never</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="pref_playlists_recently_played_interval_titles">
|
||||||
|
<item>@string/today</item>
|
||||||
|
<item>@string/this_week</item>
|
||||||
|
<item>@string/this_month</item>
|
||||||
|
<item>@string/past_three_months</item>
|
||||||
|
<item>@string/this_year</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<string-array name="pref_playlists_recently_played_interval_values">
|
||||||
|
<item>today</item>
|
||||||
|
<item>this_week</item>
|
||||||
|
<item>this_month</item>
|
||||||
|
<item>past_three_months</item>
|
||||||
|
<item>this_year</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
<string-array name="pref_playlists_last_added_interval_titles">
|
<string-array name="pref_playlists_last_added_interval_titles">
|
||||||
<item>@string/today</item>
|
<item>@string/today</item>
|
||||||
<item>@string/this_week</item>
|
<item>@string/this_week</item>
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,15 @@
|
||||||
|
|
||||||
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory android:title="@string/pref_header_playlists">
|
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEPreferenceCategory android:title="@string/pref_header_playlists">
|
||||||
|
|
||||||
|
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEListPreference
|
||||||
|
android:defaultValue="this_month"
|
||||||
|
android:entries="@array/pref_playlists_recently_played_interval_titles"
|
||||||
|
android:entryValues="@array/pref_playlists_recently_played_interval_values"
|
||||||
|
android:key="recently_played_interval"
|
||||||
|
android:negativeButtonText="@null"
|
||||||
|
android:positiveButtonText="@null"
|
||||||
|
android:title="@string/pref_title_recently_played_interval" />
|
||||||
|
|
||||||
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEListPreference
|
<com.kabouzeid.appthemehelper.common.prefs.supportv7.ATEListPreference
|
||||||
android:defaultValue="this_month"
|
android:defaultValue="this_month"
|
||||||
android:entries="@array/pref_playlists_last_added_interval_titles"
|
android:entries="@array/pref_playlists_last_added_interval_titles"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue