diff --git a/res/values-ru/translatable.xml b/res/values-ru/translatable.xml
index d6379f0a..053ece1a 100644
--- a/res/values-ru/translatable.xml
+++ b/res/values-ru/translatable.xml
@@ -189,6 +189,8 @@
Задействовать таймер простоя
Воспроизведение остановится после определенного периода бездействия
Время ожидания
+ Прокрутка до песни
+ Прокручивать до текущей песни/альбома/исполнителя в списках библиотеки
Загружать обложки из баз Android
Запрашивать обложки из встроенной базы медиа данных ОС Android
Загружать обложки из папки
diff --git a/res/values/translatable.xml b/res/values/translatable.xml
index ad4bf1e2..a8db2288 100644
--- a/res/values/translatable.xml
+++ b/res/values/translatable.xml
@@ -215,6 +215,9 @@ THE SOFTWARE.
When active, playback will be stopped after the given period of inactivity
Idle timeout
+ Scroll to song title
+ Scroll to currently playing song/album/artist in library lists
+
Load artwork from Android
Query Androids internal media database for album artwork
diff --git a/res/xml/preference_library.xml b/res/xml/preference_library.xml
index 4fa00e2d..6aa9440e 100644
--- a/res/xml/preference_library.xml
+++ b/res/xml/preference_library.xml
@@ -42,6 +42,11 @@ THE SOFTWARE.
android:entries="@array/default_playlist_action_entries"
android:entryValues="@array/default_playlist_action_entry_values"
android:defaultValue="0" />
+
diff --git a/src/ch/blinkenlights/android/vanilla/LibraryActivity.java b/src/ch/blinkenlights/android/vanilla/LibraryActivity.java
index 3204d3ea..90aaffab 100644
--- a/src/ch/blinkenlights/android/vanilla/LibraryActivity.java
+++ b/src/ch/blinkenlights/android/vanilla/LibraryActivity.java
@@ -28,39 +28,30 @@ import android.content.ContentResolver;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
-import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.PaintDrawable;
import android.net.Uri;
-import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore;
import android.support.iosched.tabs.VanillaTabLayout;
import android.support.v4.view.ViewPager;
-import android.text.Editable;
import android.text.TextUtils;
import android.view.ContextMenu;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
-import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
-import android.view.inputmethod.InputMethodManager;
import android.widget.CheckBox;
import android.widget.HorizontalScrollView;
-import android.widget.ImageButton;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
-import android.widget.Toast;
import android.widget.SearchView;
import java.io.File;
@@ -872,8 +863,10 @@ public class LibraryActivity
super.onSongChange(song);
mBottomBarControls.setSong(song);
- if (song != null)
+ if (song != null) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_COVER, song));
+ mPagerAdapter.onSongChange(song);
+ }
}
@Override
diff --git a/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java b/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java
index 13b9773f..65d23aba 100644
--- a/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java
+++ b/src/ch/blinkenlights/android/vanilla/LibraryPagerAdapter.java
@@ -26,7 +26,7 @@ package ch.blinkenlights.android.vanilla;
import android.content.Intent;
import android.content.SharedPreferences;
import android.database.ContentObserver;
-import android.os.Build;
+import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
@@ -35,6 +35,7 @@ import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
+import android.util.TypedValue;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.LayoutInflater;
@@ -48,6 +49,8 @@ import android.widget.TextView;
import android.widget.LinearLayout;
import java.util.Arrays;
+import static android.graphics.drawable.GradientDrawable.Orientation.RIGHT_LEFT;
+
/**
* PagerAdapter that manages the library media ListViews.
*/
@@ -851,6 +854,39 @@ public class LibraryPagerAdapter
}
}
+ /**
+ * Perform usability-related actions on pager and contained lists, e.g. highlight current song
+ * or scroll to it if opted-in
+ * @param song song that is currently playing, can be null
+ */
+ public void onSongChange(Song song) {
+ int type = mTabOrder[mCurrentPage];
+ long id = MediaUtils.getCurrentIdForType(song, type);
+ if (id == -1) // unknown type
+ return;
+
+ ListView view = mLists[type];
+ if (view == null) // not initialized yet, nothing to do
+ return;
+
+ // scroll to song on song change if opted-in
+ SharedPreferences sharedPrefs = PlaybackService.getSettings(mActivity);
+ boolean shouldScroll = sharedPrefs.getBoolean(PrefKeys.ENABLE_SCROLL_TO_SONG, PrefDefaults.ENABLE_SCROLL_TO_SONG);
+ if(shouldScroll) {
+ int middlePos = (view.getFirstVisiblePosition() + view.getLastVisiblePosition()) / 2;
+ for (int pos = 0; pos < view.getCount(); pos++) {
+ if (view.getItemIdAtPosition(pos) == id) {
+ if (Math.abs(middlePos - pos) < 30) {
+ view.smoothScrollToPosition(pos);
+ } else {
+ view.setSelection(pos);
+ }
+ break;
+ }
+ }
+ }
+ }
+
/**
* LRU implementation: saves the adapter position
*/
diff --git a/src/ch/blinkenlights/android/vanilla/MediaUtils.java b/src/ch/blinkenlights/android/vanilla/MediaUtils.java
index 098581bc..c1fa48bf 100644
--- a/src/ch/blinkenlights/android/vanilla/MediaUtils.java
+++ b/src/ch/blinkenlights/android/vanilla/MediaUtils.java
@@ -341,7 +341,7 @@ public class MediaUtils {
String[] projection = { "_id" };
Uri uri = MediaStore.Audio.Genres.getContentUriForAudioId("external", (int)id);
Cursor cursor = queryResolver(resolver, uri, projection, null, null, null);
-
+
if (cursor != null) {
if (cursor.moveToNext())
return cursor.getLong(0);
@@ -381,7 +381,7 @@ public class MediaUtils {
if (albumShuffle) {
List tempList = new ArrayList(list);
Collections.sort(tempList);
-
+
// Build map of albumId to start index in sorted list
Map albumStartIndices = new HashMap();
int index = 0;
@@ -391,11 +391,11 @@ public class MediaUtils {
}
index++;
}
-
+
//Extract album list and shuffle
List shuffledAlbums = new ArrayList(albumStartIndices.keySet());
Collections.shuffle(shuffledAlbums, random);
-
+
//Build Song list from album list
list.clear();
for (Long albumId : shuffledAlbums) {
@@ -588,16 +588,16 @@ public class MediaUtils {
break;
}
}
-
+
pfx = (new File(pfx)).getParent();
if(pfx == null)
break; /* hit root */
}
}
-
+
return path;
}
-
+
/**
* Adds a final slash if the path points to an existing directory
*/
@@ -682,4 +682,28 @@ public class MediaUtils {
return matrixCursor;
}
+ /**
+ * Retrieve ID of specified media type for requested song. This works only for
+ * media-oriented types: {@link #TYPE_ARTIST}, {@link #TYPE_ALBUM}, {@link #TYPE_SONG}
+ * @param song requested song
+ * @param mType media type e.g. {@link #TYPE_ARTIST}
+ * @return ID of media type, {@link #TYPE_INVALID} if unsupported
+ */
+ public static long getCurrentIdForType(Song song, int mType)
+ {
+ if(song == null)
+ return TYPE_INVALID;
+
+ switch(mType) {
+ case TYPE_ARTIST:
+ return song.artistId;
+ case TYPE_ALBUM:
+ return song.albumId;
+ case TYPE_SONG:
+ return song.id;
+ default:
+ return TYPE_INVALID;
+ }
+ }
+
}
diff --git a/src/ch/blinkenlights/android/vanilla/PrefDefaults.java b/src/ch/blinkenlights/android/vanilla/PrefDefaults.java
index 9f5be06f..477ab629 100644
--- a/src/ch/blinkenlights/android/vanilla/PrefDefaults.java
+++ b/src/ch/blinkenlights/android/vanilla/PrefDefaults.java
@@ -68,4 +68,5 @@ public class PrefDefaults {
public static final int VOLUME_DURING_DUCKING = 50;
public static final int AUTOPLAYLIST_PLAYCOUNTS = 0;
public static final boolean IGNORE_AUDIOFOCUS_LOSS = false;
+ public static final boolean ENABLE_SCROLL_TO_SONG = false;
}
diff --git a/src/ch/blinkenlights/android/vanilla/PrefKeys.java b/src/ch/blinkenlights/android/vanilla/PrefKeys.java
index 143d1b07..7adf5819 100644
--- a/src/ch/blinkenlights/android/vanilla/PrefKeys.java
+++ b/src/ch/blinkenlights/android/vanilla/PrefKeys.java
@@ -24,7 +24,7 @@
package ch.blinkenlights.android.vanilla;
/**
- * SharedPreference keys. Must be kept in sync with PrefDefaults.java.
+ * SharedPreference keys. Must be kept in sync with {@link PrefDefaults}.
*/
public class PrefKeys {
public static final String COVER_LONGPRESS_ACTION = "cover_longpress_action";
@@ -69,4 +69,5 @@ public class PrefKeys {
public static final String VOLUME_DURING_DUCKING = "volume_during_ducking";
public static final String AUTOPLAYLIST_PLAYCOUNTS = "playcounts_autoplaylist";
public static final String IGNORE_AUDIOFOCUS_LOSS = "ignore_audiofocus_loss";
+ public static final String ENABLE_SCROLL_TO_SONG = "enable_scroll_to_song";
}