diff options
65 files changed, 461 insertions, 444 deletions
diff --git a/DSub Featured.png b/DSub Featured.png Binary files differindex c54fe16c..b9e48acb 100644 --- a/DSub Featured.png +++ b/DSub Featured.png diff --git a/res/drawable-hdpi/ic_action_rating_bad_dark.png b/res/drawable-hdpi/ic_action_rating_bad_dark.png Binary files differnew file mode 100644 index 00000000..855709e9 --- /dev/null +++ b/res/drawable-hdpi/ic_action_rating_bad_dark.png diff --git a/res/drawable-hdpi/ic_action_rating_bad_light.png b/res/drawable-hdpi/ic_action_rating_bad_light.png Binary files differnew file mode 100644 index 00000000..34199d3a --- /dev/null +++ b/res/drawable-hdpi/ic_action_rating_bad_light.png diff --git a/res/drawable-hdpi/ic_action_rating_bad_selected.png b/res/drawable-hdpi/ic_action_rating_bad_selected.png Binary files differnew file mode 100644 index 00000000..c57aba50 --- /dev/null +++ b/res/drawable-hdpi/ic_action_rating_bad_selected.png diff --git a/res/drawable-hdpi/ic_action_rating_good_dark.png b/res/drawable-hdpi/ic_action_rating_good_dark.png Binary files differnew file mode 100644 index 00000000..fa91e699 --- /dev/null +++ b/res/drawable-hdpi/ic_action_rating_good_dark.png diff --git a/res/drawable-hdpi/ic_action_rating_good_light.png b/res/drawable-hdpi/ic_action_rating_good_light.png Binary files differnew file mode 100644 index 00000000..3427d770 --- /dev/null +++ b/res/drawable-hdpi/ic_action_rating_good_light.png diff --git a/res/drawable-hdpi/ic_action_rating_good_selected.png b/res/drawable-hdpi/ic_action_rating_good_selected.png Binary files differnew file mode 100644 index 00000000..34d53153 --- /dev/null +++ b/res/drawable-hdpi/ic_action_rating_good_selected.png diff --git a/res/drawable-hdpi/ic_menu_bookmark_selected.png b/res/drawable-hdpi/ic_menu_bookmark_selected.png Binary files differnew file mode 100644 index 00000000..5a33d60c --- /dev/null +++ b/res/drawable-hdpi/ic_menu_bookmark_selected.png diff --git a/res/drawable-mdpi/ic_action_rating_bad_dark.png b/res/drawable-mdpi/ic_action_rating_bad_dark.png Binary files differnew file mode 100644 index 00000000..64f3cd1f --- /dev/null +++ b/res/drawable-mdpi/ic_action_rating_bad_dark.png diff --git a/res/drawable-mdpi/ic_action_rating_bad_light.png b/res/drawable-mdpi/ic_action_rating_bad_light.png Binary files differnew file mode 100644 index 00000000..d6c8d42a --- /dev/null +++ b/res/drawable-mdpi/ic_action_rating_bad_light.png diff --git a/res/drawable-mdpi/ic_action_rating_bad_selected.png b/res/drawable-mdpi/ic_action_rating_bad_selected.png Binary files differnew file mode 100644 index 00000000..34f5a9de --- /dev/null +++ b/res/drawable-mdpi/ic_action_rating_bad_selected.png diff --git a/res/drawable-mdpi/ic_action_rating_good_dark.png b/res/drawable-mdpi/ic_action_rating_good_dark.png Binary files differnew file mode 100644 index 00000000..cadfbe1e --- /dev/null +++ b/res/drawable-mdpi/ic_action_rating_good_dark.png diff --git a/res/drawable-mdpi/ic_action_rating_good_light.png b/res/drawable-mdpi/ic_action_rating_good_light.png Binary files differnew file mode 100644 index 00000000..75711920 --- /dev/null +++ b/res/drawable-mdpi/ic_action_rating_good_light.png diff --git a/res/drawable-mdpi/ic_action_rating_good_selected.png b/res/drawable-mdpi/ic_action_rating_good_selected.png Binary files differnew file mode 100644 index 00000000..97d279be --- /dev/null +++ b/res/drawable-mdpi/ic_action_rating_good_selected.png diff --git a/res/drawable-mdpi/ic_menu_bookmark_selected.png b/res/drawable-mdpi/ic_menu_bookmark_selected.png Binary files differnew file mode 100644 index 00000000..efcc1afa --- /dev/null +++ b/res/drawable-mdpi/ic_menu_bookmark_selected.png diff --git a/res/drawable-xhdpi/ic_action_rating_bad_dark.png b/res/drawable-xhdpi/ic_action_rating_bad_dark.png Binary files differnew file mode 100644 index 00000000..1393be0c --- /dev/null +++ b/res/drawable-xhdpi/ic_action_rating_bad_dark.png diff --git a/res/drawable-xhdpi/ic_action_rating_bad_light.png b/res/drawable-xhdpi/ic_action_rating_bad_light.png Binary files differnew file mode 100644 index 00000000..fc1959b6 --- /dev/null +++ b/res/drawable-xhdpi/ic_action_rating_bad_light.png diff --git a/res/drawable-xhdpi/ic_action_rating_bad_selected.png b/res/drawable-xhdpi/ic_action_rating_bad_selected.png Binary files differnew file mode 100644 index 00000000..cf7802d5 --- /dev/null +++ b/res/drawable-xhdpi/ic_action_rating_bad_selected.png diff --git a/res/drawable-xhdpi/ic_action_rating_good_dark.png b/res/drawable-xhdpi/ic_action_rating_good_dark.png Binary files differnew file mode 100644 index 00000000..249ea9ec --- /dev/null +++ b/res/drawable-xhdpi/ic_action_rating_good_dark.png diff --git a/res/drawable-xhdpi/ic_action_rating_good_light.png b/res/drawable-xhdpi/ic_action_rating_good_light.png Binary files differnew file mode 100644 index 00000000..c8a776b0 --- /dev/null +++ b/res/drawable-xhdpi/ic_action_rating_good_light.png diff --git a/res/drawable-xhdpi/ic_action_rating_good_selected.png b/res/drawable-xhdpi/ic_action_rating_good_selected.png Binary files differnew file mode 100644 index 00000000..c6770221 --- /dev/null +++ b/res/drawable-xhdpi/ic_action_rating_good_selected.png diff --git a/res/drawable-xhdpi/ic_menu_bookmark_selected.png b/res/drawable-xhdpi/ic_menu_bookmark_selected.png Binary files differnew file mode 100644 index 00000000..353b7b79 --- /dev/null +++ b/res/drawable-xhdpi/ic_menu_bookmark_selected.png diff --git a/res/drawable-xxhdpi/ic_action_rating_bad_dark.png b/res/drawable-xxhdpi/ic_action_rating_bad_dark.png Binary files differnew file mode 100644 index 00000000..d784b239 --- /dev/null +++ b/res/drawable-xxhdpi/ic_action_rating_bad_dark.png diff --git a/res/drawable-xxhdpi/ic_action_rating_bad_light.png b/res/drawable-xxhdpi/ic_action_rating_bad_light.png Binary files differnew file mode 100644 index 00000000..a1484d25 --- /dev/null +++ b/res/drawable-xxhdpi/ic_action_rating_bad_light.png diff --git a/res/drawable-xxhdpi/ic_action_rating_bad_selected.png b/res/drawable-xxhdpi/ic_action_rating_bad_selected.png Binary files differnew file mode 100644 index 00000000..13218a08 --- /dev/null +++ b/res/drawable-xxhdpi/ic_action_rating_bad_selected.png diff --git a/res/drawable-xxhdpi/ic_action_rating_good_dark.png b/res/drawable-xxhdpi/ic_action_rating_good_dark.png Binary files differnew file mode 100644 index 00000000..a332a632 --- /dev/null +++ b/res/drawable-xxhdpi/ic_action_rating_good_dark.png diff --git a/res/drawable-xxhdpi/ic_action_rating_good_light.png b/res/drawable-xxhdpi/ic_action_rating_good_light.png Binary files differnew file mode 100644 index 00000000..2ef75765 --- /dev/null +++ b/res/drawable-xxhdpi/ic_action_rating_good_light.png diff --git a/res/drawable-xxhdpi/ic_action_rating_good_selected.png b/res/drawable-xxhdpi/ic_action_rating_good_selected.png Binary files differnew file mode 100644 index 00000000..bb444806 --- /dev/null +++ b/res/drawable-xxhdpi/ic_action_rating_good_selected.png diff --git a/res/drawable-xxhdpi/ic_menu_bookmark_selected.png b/res/drawable-xxhdpi/ic_menu_bookmark_selected.png Binary files differnew file mode 100644 index 00000000..a1890fbb --- /dev/null +++ b/res/drawable-xxhdpi/ic_menu_bookmark_selected.png diff --git a/res/layout-land/download.xml b/res/layout-land/download.xml index eb876be0..e97db866 100644 --- a/res/layout-land/download.xml +++ b/res/layout-land/download.xml @@ -41,16 +41,6 @@ android:background="@android:color/transparent">
<LinearLayout
- android:id="@+id/download_visualizer_view_layout"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="60dip"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="12dip"
- android:layout_gravity="center_horizontal"
- android:layout_above="@+id/download_other_controls_wrapper"/>
-
- <LinearLayout
android:id="@+id/download_other_controls_wrapper"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -64,15 +54,10 @@ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
- <Button
- android:id="@+id/download_equalizer"
- android:text="EQ"
- style="@style/DownloadActionButton"/>
-
- <Button
- android:id="@+id/download_visualizer"
- android:text="VIS"
- style="@style/DownloadActionButton"/>
+ <ImageButton
+ android:id="@+id/download_rating_bad"
+ style="@style/DownloadActionImageButton"
+ android:src="?attr/rating_bad"/>
<ImageButton
android:id="@+id/download_star"
@@ -83,6 +68,11 @@ android:id="@+id/download_bookmark"
style="@style/DownloadActionImageButton"
android:src="?attr/bookmark"/>
+
+ <ImageButton
+ android:id="@+id/download_rating_good"
+ style="@style/DownloadActionImageButton"
+ android:src="?attr/rating_good"/>
</LinearLayout>
</LinearLayout>
diff --git a/res/layout-large-land/download.xml b/res/layout-large-land/download.xml index e1572890..18b560bc 100644 --- a/res/layout-large-land/download.xml +++ b/res/layout-large-land/download.xml @@ -44,15 +44,6 @@ android:orientation="vertical">
<LinearLayout
- android:id="@+id/download_visualizer_view_layout"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="60dip"
- android:layout_marginLeft="12dip"
- android:layout_marginRight="12dip"
- android:layout_above="@+id/download_other_controls_layout"/>
-
- <LinearLayout
android:id="@+id/download_other_controls_layout"
android:orientation="horizontal"
android:layout_width="wrap_content"
@@ -60,15 +51,10 @@ android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true">
- <Button
- android:id="@+id/download_equalizer"
- android:text="EQ"
- style="@style/DownloadActionButton"/>
-
- <Button
- android:id="@+id/download_visualizer"
- android:text="VIS"
- style="@style/DownloadActionButton"/>
+ <ImageButton
+ android:id="@+id/download_rating_bad"
+ style="@style/DownloadActionImageButton"
+ android:src="?attr/rating_bad"/>
<ImageButton
android:id="@+id/download_star"
@@ -79,6 +65,11 @@ android:id="@+id/download_bookmark"
style="@style/DownloadActionImageButton"
android:src="?attr/bookmark"/>
+
+ <ImageButton
+ android:id="@+id/download_rating_good"
+ style="@style/DownloadActionImageButton"
+ android:src="?attr/rating_good"/>
</LinearLayout>
</RelativeLayout>
diff --git a/res/layout-port/download.xml b/res/layout-port/download.xml index f2a1df1c..b7d047c6 100644 --- a/res/layout-port/download.xml +++ b/res/layout-port/download.xml @@ -55,15 +55,10 @@ android:layout_height="wrap_content"
android:layout_gravity="center_horizontal">
- <Button
- android:id="@+id/download_equalizer"
- android:text="EQ"
- style="@style/DownloadActionButton"/>
-
- <Button
- android:id="@+id/download_visualizer"
- android:text="VIS"
- style="@style/DownloadActionButton"/>
+ <ImageButton
+ android:id="@+id/download_rating_bad"
+ style="@style/DownloadActionImageButton"
+ android:src="@drawable/ic_action_rating_bad_dark"/>
<ImageButton
android:id="@+id/download_star"
@@ -74,18 +69,14 @@ android:id="@+id/download_bookmark"
style="@style/DownloadActionImageButton"
android:src="@drawable/ic_menu_bookmark_dark"/>
+
+ <ImageButton
+ android:id="@+id/download_rating_good"
+ style="@style/DownloadActionImageButton"
+ android:src="@drawable/ic_action_rating_good_dark"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
-
- <LinearLayout
- android:id="@+id/download_visualizer_view_layout"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="60dip"
- android:layout_marginLeft="16dip"
- android:layout_marginRight="16dip"
- android:layout_gravity="center_horizontal|bottom"/>
</FrameLayout>
<TextView
diff --git a/res/layout/rating.xml b/res/layout/rating.xml new file mode 100644 index 00000000..cf38fba1 --- /dev/null +++ b/res/layout/rating.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <RatingBar
+ android:id="@+id/rating_bar"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:numStars="5"
+ android:stepSize="1"
+ android:layout_gravity="center_horizontal"/>
+
+</LinearLayout>
\ No newline at end of file diff --git a/res/layout/song_list_item.xml b/res/layout/song_list_item.xml index fddc714f..8febace9 100644 --- a/res/layout/song_list_item.xml +++ b/res/layout/song_list_item.xml @@ -36,6 +36,17 @@ android:drawablePadding="6dip"
android:paddingLeft="6dip"
android:paddingRight="6dip"/>
+
+ <ImageButton
+ android:id="@+id/song_bookmark"
+ android:layout_width="24dp"
+ android:layout_height="24dp"
+ android:layout_gravity="right|center_vertical"
+ android:src="@drawable/ic_menu_bookmark_selected"
+ android:background="@null"
+ android:focusable="false"
+ android:scaleType="fitCenter"
+ android:visibility="gone"/>
<ImageButton
android:id="@+id/song_star"
diff --git a/res/menu/nowplaying.xml b/res/menu/nowplaying.xml index 48528b43..60255692 100644 --- a/res/menu/nowplaying.xml +++ b/res/menu/nowplaying.xml @@ -28,6 +28,11 @@ android:title="@string/download.menu_save" compat:showAsAction="ifRoom|withText"/> + <item + android:id="@+id/menu_equalizer" + android:title="@string/equalizer.label" + android:checkable="true"/> + <item android:id="@+id/menu_screen_on_off" android:title="@string/download.menu_screen_on" diff --git a/res/menu/nowplaying_offline.xml b/res/menu/nowplaying_offline.xml index f3912b0c..bba5ba00 100644 --- a/res/menu/nowplaying_offline.xml +++ b/res/menu/nowplaying_offline.xml @@ -20,10 +20,16 @@ android:icon="?attr/remove" android:title="@string/download.menu_remove_all" compat:showAsAction="ifRoom|withText"/> + + <item + android:id="@+id/menu_equalizer" + android:title="@string/equalizer.label" + android:checkable="true"/> <item android:id="@+id/menu_screen_on_off" - android:title="@string/download.menu_screen_on"/> + android:title="@string/download.menu_screen_on" + android:checkable="true"/> <item android:id="@+id/menu_remove_played" diff --git a/res/menu/select_album_context.xml b/res/menu/select_album_context.xml index 216e8910..5b2529e7 100644 --- a/res/menu/select_album_context.xml +++ b/res/menu/select_album_context.xml @@ -58,4 +58,10 @@ android:id="@+id/album_menu_share" android:title="@string/menu.share"/> </group> + + <group android:id="@+id/hide_rating"> + <item + android:id="@+id/menu_rate" + android:title="@string/menu.rate"/> + </group> </menu> diff --git a/res/menu/select_song_context.xml b/res/menu/select_song_context.xml index 5123a0ae..d8fc211c 100644 --- a/res/menu/select_song_context.xml +++ b/res/menu/select_song_context.xml @@ -59,6 +59,12 @@ android:id="@+id/song_menu_share" android:title="@string/menu.share"/> </group> + + <group android:id="@+id/hide_rating"> + <item + android:id="@+id/menu_rate" + android:title="@string/menu.rate"/> + </group> <group android:id="@+id/server_1.9"> <item diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml index a9362206..ebfe7377 100644 --- a/res/values-de/strings.xml +++ b/res/values-de/strings.xml @@ -191,8 +191,6 @@ <string name="download.repeat_off">Keine Wiederholung</string>
<string name="download.repeat_all">Wiederhole alle</string>
<string name="download.repeat_single">Aktuelles Lied wiederholen</string>
- <string name="download.visualizer_on">Visualisierung aktiviert.</string>
- <string name="download.visualizer_off">Visualisierung deaktiviert.</string>
<string name="download.jukebox_on">Fernbedienung aktiviert. Musik wird auf dem Computer abgespielt.</string>
<string name="download.jukebox_off">Fernbedienung deaktiviert. Musik wird auf dem Telefon abgespielt.</string>
<string name="download.jukebox_volume">Lautstärke</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml index 43396da8..6364bf72 100644 --- a/res/values-es/strings.xml +++ b/res/values-es/strings.xml @@ -186,8 +186,6 @@ <string name="download.repeat_off">Repetir off</string> <string name="download.repeat_all">Repetir todo</string> <string name="download.repeat_single">Repetir canción</string> - <string name="download.visualizer_on">Visualizador encendido.</string> - <string name="download.visualizer_off">Visualizador apagado.</string> <string name="download.jukebox_on">Control remoto encendido. La música se está reproduciendo en el ordenador.</string> <string name="download.jukebox_off">Control remoto apagado. La música se está reproduciendo en el dispositivo móvil.</string> <string name="download.jukebox_volume">Volumen remoto</string> diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml index b72e3f9a..ab4c187d 100644 --- a/res/values-fr/strings.xml +++ b/res/values-fr/strings.xml @@ -191,8 +191,6 @@ <string name="download.repeat_off">Répéter inactif</string>
<string name="download.repeat_all">Répéter tout</string>
<string name="download.repeat_single">Répéter titre</string>
- <string name="download.visualizer_on">Activer visualisation.</string>
- <string name="download.visualizer_off">Désactiver visualisation.</string>
<string name="download.jukebox_on">Télécommande activée. La musique est diffusée sur l\'ordinateur.</string>
<string name="download.jukebox_off">Télécommande désactivée. La musique est diffusée sur le mobile.</string>
<string name="download.jukebox_volume">Volume distant</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml index cd8f9dfd..80d509be 100644 --- a/res/values-hu/strings.xml +++ b/res/values-hu/strings.xml @@ -191,8 +191,6 @@ <string name="download.repeat_off">Ismétlés ki</string>
<string name="download.repeat_all">Összes ismétlése</string>
<string name="download.repeat_single">Dal ismétlése</string>
- <string name="download.visualizer_on">Visualizer bekapcsolva.</string>
- <string name="download.visualizer_off">Visualizer kikapcsolva.</string>
<string name="download.jukebox_on">Távvezérlés bekapcsolása. A zenelejátszás a számítógépen történik.</string>
<string name="download.jukebox_off">Távvezérlés kikapcsolása. A zenelejátszás az eszközön történik.</string>
<string name="download.jukebox_volume">Hangerő távvezérlése</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml index 1888bf5f..9e9bc211 100644 --- a/res/values-ru/strings.xml +++ b/res/values-ru/strings.xml @@ -124,8 +124,6 @@ <string name="download.repeat_off">Повторение отключено</string>
<string name="download.repeat_all">Повторять все</string>
<string name="download.repeat_single">Повторять композицию</string>
- <string name="download.visualizer_on">Визуализация включена</string>
- <string name="download.visualizer_off">Визуализация отключена</string>
<string name="download.jukebox_on">Удаленное управление включено. Музыка воспроизводится на компьютере.</string>
<string name="download.jukebox_off">Удаленное управление отключено. Музыка воспроизводится на устройстве.</string>
<string name="download.jukebox_volume">Удаленное управление громкостью</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml index ac535487..13456e18 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -23,5 +23,7 @@ <attr name="share" format="reference"/> <attr name="add_person" format="reference"/> <attr name="password" format="reference"/> + <attr name="rating_bad" format="reference"/> + <attr name="rating_good" format="reference"/> <attr name="drawerItemsIcons" format="reference"/> </resources> diff --git a/res/values/strings.xml b/res/values/strings.xml index b02cdc9d..b31efda1 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -103,6 +103,7 @@ <string name="menu.faq">FAQ</string>
<string name="menu.add_user">Add User</string>
<string name="menu.rescan">Rescan Server</string>
+ <string name="menu.rate">Set Rating</string>
<string name="playlist.label">Playlists</string>
<string name="playlist.update_info">Update Information</string>
@@ -191,8 +192,6 @@ <string name="download.repeat_off">Repeat off</string>
<string name="download.repeat_all">Repeat all</string>
<string name="download.repeat_single">Repeat song</string>
- <string name="download.visualizer_on">Turned on visualizer.</string>
- <string name="download.visualizer_off">Turned off visualizer.</string>
<string name="download.jukebox_on">Turned on remote control. Music is played on the computer.</string>
<string name="download.jukebox_off">Turned off remote control. Music is played on the phone.</string>
<string name="download.jukebox_volume">Remote volume</string>
@@ -242,6 +241,12 @@ <string name="bookmark.action_resume">Resume</string>
<string name="bookmark.action_start_over">Start Over</string>
+ <string name="rating.title">Rate \"%s\"</string>
+ <string name="rating.set_rating">Rating set for \"%s\"</string>
+ <string name="rating.set_rating_failed">Failed to set rating for \"%s\"</string>
+ <string name="rating.remove_rating">Rating removed for \"%s\"</string>
+ <string name="rating.remove_rating_failed">Failed to remove rating for \"%s\"</string>
+
<string name="song_details.error">Error</string>
<string name="song_details.skipped">Skipped</string>
<string name="song_details.downloading">Downloading</string>
@@ -411,6 +416,7 @@ <string name="settings.menu_options.play_last_summary">Show Play last in menus</string>
<string name="settings.menu_options.star_summary">Show Star in menus</string>
<string name="settings.menu_options.shared_summary">Show Share in menus</string>
+ <string name="settings.menu_options.rate_summary">Show Rating in menus</string>
<string name="settings.browse_by_tags">Browse By Tags</string>
<string name="settings.browse_by_tags_summary">Browse by tags instead of by folder structure. Requires Subsonic 4.7+</string>
<string name="settings.override_system_language">Override System Language</string>
diff --git a/res/values/themes.xml b/res/values/themes.xml index 1700aa88..129c0612 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -26,6 +26,8 @@ <item name="share">@drawable/ic_menu_share_light</item> <item name="add_person">@drawable/ic_menu_add_person_light</item> <item name="password">@drawable/ic_menu_password_light</item> + <item name="rating_bad">@drawable/ic_action_rating_bad_light</item> + <item name="rating_good">@drawable/ic_action_rating_good_light</item> <item name="drawerItemsIcons">@array/drawerItemIconsLight</item> <item name="android:textViewStyle">@style/DSub.TextViewStyle</item> <item name="android:buttonStyle">@style/DSub.ButtonStyle.Light</item> @@ -57,6 +59,8 @@ <item name="share">@drawable/ic_menu_share_dark</item> <item name="add_person">@drawable/ic_menu_add_person_dark</item> <item name="password">@drawable/ic_menu_password_dark</item> + <item name="rating_bad">@drawable/ic_action_rating_bad_dark</item> + <item name="rating_good">@drawable/ic_action_rating_good_dark</item> <item name="drawerItemsIcons">@array/drawerItemIconsDark</item> <item name="android:textViewStyle">@style/DSub.TextViewStyle</item> <item name="android:buttonStyle">@style/DSub.ButtonStyle.Dark</item> @@ -91,6 +95,8 @@ <item name="share">@drawable/ic_menu_share_dark</item> <item name="add_person">@drawable/ic_menu_add_person_dark</item> <item name="password">@drawable/ic_menu_password_dark</item> + <item name="rating_bad">@drawable/ic_action_rating_bad_dark</item> + <item name="rating_good">@drawable/ic_action_rating_good_dark</item> <item name="drawerItemsIcons">@array/drawerItemIconsDark</item> <item name="android:textViewStyle">@style/DSub.TextViewStyle</item> <item name="android:buttonStyle">@style/DSub.ButtonStyle.Dark</item> diff --git a/res/xml/settings.xml b/res/xml/settings.xml index 42b74aa0..bafb5f6c 100644 --- a/res/xml/settings.xml +++ b/res/xml/settings.xml @@ -101,6 +101,12 @@ android:key="showShared" android:defaultValue="true"/> + <CheckBoxPreference + android:title="@string/menu.rate" + android:summary="@string/settings.menu_options.rate_summary" + android:key="showRating" + android:defaultValue="true"/> + </PreferenceCategory> </PreferenceScreen> diff --git a/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java b/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java index f53a4dff..1933bd64 100644 --- a/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java +++ b/src/github/daneren2005/dsub/audiofx/AudioEffectsController.java @@ -34,7 +34,6 @@ public class AudioEffectsController { private boolean available = false; private EqualizerController equalizerController; - private VisualizerController visualizerController; public AudioEffectsController(Context context, int audioSessionId) { this.context = context; @@ -53,9 +52,6 @@ public class AudioEffectsController { if(equalizerController != null) { equalizerController.release(); } - if(visualizerController != null) { - visualizerController.release(); - } } public EqualizerController getEqualizerController() { @@ -69,14 +65,5 @@ public class AudioEffectsController { } return equalizerController; } - public VisualizerController getVisualizerController() { - if (available && visualizerController == null) { - visualizerController = new VisualizerController(context, audioSessionId); - if (!visualizerController.isAvailable()) { - visualizerController = null; - } - } - return visualizerController; - } } diff --git a/src/github/daneren2005/dsub/audiofx/VisualizerController.java b/src/github/daneren2005/dsub/audiofx/VisualizerController.java deleted file mode 100644 index 92e3712c..00000000 --- a/src/github/daneren2005/dsub/audiofx/VisualizerController.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2011 (C) Sindre Mehus - */ -package github.daneren2005.dsub.audiofx; - -import android.content.Context; -import android.media.audiofx.Visualizer; -import android.util.Log; - -/** - * Backward-compatible wrapper for {@link Visualizer}, which is API Level 9. - * - * @author Sindre Mehus - * @version $Id$ - */ -public class VisualizerController { - - private static final String TAG = VisualizerController.class.getSimpleName(); - private static final int PREFERRED_CAPTURE_SIZE = 128; // Must be a power of two. - - private final Context context; - private Visualizer visualizer; - private boolean released = false; - private int audioSessionId = 0; - - // Class initialization fails when this throws an exception. - static { - try { - Class.forName("android.media.audiofx.Visualizer"); - } catch (Exception ex) { - throw new RuntimeException(ex); - } - } - - /** - * Throws an exception if the {@link Visualizer} class is not available. - */ - public static void checkAvailable() throws Throwable { - // Calling here forces class initialization. - } - - public VisualizerController(Context context, int audioSessionId) { - this.context = context; - try { - this.audioSessionId = audioSessionId; - visualizer = new Visualizer(audioSessionId); - } catch (Throwable x) { - Log.w(TAG, "Failed to create visualizer.", x); - } - - if (visualizer != null) { - int[] captureSizeRange = Visualizer.getCaptureSizeRange(); - int captureSize = Math.max(PREFERRED_CAPTURE_SIZE, captureSizeRange[0]); - captureSize = Math.min(captureSize, captureSizeRange[1]); - visualizer.setCaptureSize(captureSize); - } - } - - public boolean isAvailable() { - return visualizer != null; - } - - public boolean isEnabled() { - return isAvailable() && visualizer.getEnabled(); - } - - public void release() { - if (isAvailable()) { - visualizer.release(); - released = true; - } - } - - public Visualizer getVisualizer() { - if(released) { - released = false; - try { - visualizer = new Visualizer(audioSessionId); - } catch (Throwable x) { - visualizer = null; - Log.w(TAG, "Failed to create visualizer.", x); - } - } - - return visualizer; - } -} - diff --git a/src/github/daneren2005/dsub/domain/MusicDirectory.java b/src/github/daneren2005/dsub/domain/MusicDirectory.java index 1caf77cf..a738f9bf 100644 --- a/src/github/daneren2005/dsub/domain/MusicDirectory.java +++ b/src/github/daneren2005/dsub/domain/MusicDirectory.java @@ -400,8 +400,8 @@ public class MusicDirectory implements Serializable { this.starred = starred; } - public Integer getRating() { - return rating; + public int getRating() { + return rating == null ? 0 : rating; } public void setRating(Integer rating) { this.rating = rating; diff --git a/src/github/daneren2005/dsub/fragments/MainFragment.java b/src/github/daneren2005/dsub/fragments/MainFragment.java index 91902b52..b1320f3f 100644 --- a/src/github/daneren2005/dsub/fragments/MainFragment.java +++ b/src/github/daneren2005/dsub/fragments/MainFragment.java @@ -178,7 +178,11 @@ public class MainFragment extends SubsonicFragment { adapter.addView(offlineButton, true);
if (!Util.isOffline(context)) {
adapter.addView(albumsTitle, false);
- adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsStarredButton, albumsGenresButton, albumsYearButton, albumsRecentButton, albumsFrequentButton), true);
+ adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton), true);
+ if(!Util.isTagBrowsing(context)) {
+ adapter.addView(albumsHighestButton, true);
+ }
+ adapter.addViews(Arrays.asList(albumsStarredButton, albumsGenresButton, albumsYearButton, albumsRecentButton, albumsFrequentButton), true);
}
list.setAdapter(adapter);
registerForContextMenu(dummyView);
diff --git a/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java index 7f55de4e..e0f37f09 100644 --- a/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java +++ b/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java @@ -24,6 +24,8 @@ import android.app.AlertDialog; import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
@@ -69,8 +71,8 @@ import github.daneren2005.dsub.view.DownloadFileAdapter; import github.daneren2005.dsub.view.FadeOutAnimation;
import github.daneren2005.dsub.view.UpdateView;
import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.VisualizerView;
+import static github.daneren2005.dsub.domain.MusicDirectory.Entry;
import static github.daneren2005.dsub.domain.PlayerState.*;
import github.daneren2005.dsub.util.*;
import github.daneren2005.dsub.view.AutoRepeatButton;
@@ -108,18 +110,17 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis private View stopButton;
private View startButton;
private ImageButton repeatButton;
- private Button equalizerButton;
- private Button visualizerButton;
private View toggleListButton;
private ImageButton starButton;
private ImageButton bookmarkButton;
+ private ImageButton rateBadButton;
+ private ImageButton rateGoodButton;
private View mainLayout;
private ScheduledExecutorService executorService;
private DownloadFile currentPlaying;
private long currentRevision;
private int swipeDistance;
private int swipeVelocity;
- private VisualizerView visualizerView;
private ScheduledFuture<?> hideControlsFuture;
private List<DownloadFile> songList;
private DownloadFileAdapter songListAdapter;
@@ -182,10 +183,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis stopButton =rootView.findViewById(R.id.download_stop);
startButton =rootView.findViewById(R.id.download_start);
repeatButton = (ImageButton)rootView.findViewById(R.id.download_repeat);
- equalizerButton = (Button)rootView.findViewById(R.id.download_equalizer);
- visualizerButton = (Button)rootView.findViewById(R.id.download_visualizer);
bookmarkButton = (ImageButton) rootView.findViewById(R.id.download_bookmark);
- LinearLayout visualizerViewLayout = (LinearLayout)rootView.findViewById(R.id.download_visualizer_view_layout);
+ rateBadButton = (ImageButton) rootView.findViewById(R.id.download_rating_bad);
+ rateGoodButton = (ImageButton) rootView.findViewById(R.id.download_rating_good);
toggleListButton =rootView.findViewById(R.id.download_toggle_list);
starButton = (ImageButton)rootView.findViewById(R.id.download_star);
@@ -195,7 +195,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis public void onClick(View v) {
DownloadFile currentDownload = getDownloadService().getCurrentPlaying();
if (currentDownload != null) {
- MusicDirectory.Entry currentSong = currentDownload.getSong();
+ Entry currentSong = currentDownload.getSong();
toggleStarred(currentSong);
starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
}
@@ -214,9 +214,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis pauseButton.setOnTouchListener(touchListener);
stopButton.setOnTouchListener(touchListener);
startButton.setOnTouchListener(touchListener);
- equalizerButton.setOnTouchListener(touchListener);
- visualizerButton.setOnTouchListener(touchListener);
bookmarkButton.setOnTouchListener(touchListener);
+ rateBadButton.setOnTouchListener(touchListener);
+ rateGoodButton.setOnTouchListener(touchListener);
emptyTextView.setOnTouchListener(touchListener);
albumArtImageView.setOnTouchListener(new View.OnTouchListener() {
@Override
@@ -363,42 +363,76 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis }
});
- equalizerButton.setOnClickListener(new View.OnClickListener() {
+ bookmarkButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- DownloadService downloadService = getDownloadService();
- if(downloadService != null && downloadService.getEqualizerController() != null
- && downloadService.getEqualizerController().getEqualizer() != null) {
- SubsonicFragment fragment = new EqualizerFragment();
- replaceFragment(fragment);
- setControlsVisible(true);
- } else {
- Util.toast(context, "Failed to start equalizer. Try restarting.");
- }
+ createBookmark();
+ bookmarkButton.setImageResource(R.drawable.ic_menu_bookmark_selected);
}
});
- visualizerButton.setOnClickListener(new View.OnClickListener() {
+ rateBadButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- boolean active = !visualizerView.isActive();
- visualizerView.setActive(active);
- boolean isActive = visualizerView.isActive();
- getDownloadService().setShowVisualization(isActive);
- updateButtons();
- if(active == isActive) {
- Util.toast(context, active ? R.string.download_visualizer_on : R.string.download_visualizer_off);
+ DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return;
+ }
+
+ Entry entry = downloadService.getCurrentPlaying().getSong();
+
+ // If rating == 1, already set so unset
+ if(entry.getRating() == 1) {
+ setRating(entry, 0);
+
+ if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark);
+ } else {
+ rateBadButton.setImageResource(Util.getAttribute(context, R.attr.rating_bad));
+ }
} else {
- Util.toast(context, "Failed to start visualizer. Try restarting.");
+ // Immediately skip to the next song
+ downloadService.next();
+
+ // Otherwise set rating to 1
+ setRating(entry, 1);
+ rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_selected);
+
+ // Make sure good rating is blank
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark);
+ } else {
+ rateGoodButton.setImageResource(Util.getAttribute(context, R.attr.rating_good));
+ }
}
- setControlsVisible(true);
}
});
-
- bookmarkButton.setOnClickListener(new View.OnClickListener() {
+ rateGoodButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- createBookmark();
+ Entry entry = getDownloadService().getCurrentPlaying().getSong();
+
+ // If rating == 5, already set so unset
+ if(entry.getRating() == 5) {
+ setRating(entry, 0);
+
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_dark);
+ } else {
+ rateGoodButton.setImageResource(Util.getAttribute(context, R.attr.rating_good));
+ }
+ } else {
+ // Otherwise set rating to maximum
+ setRating(entry, 5);
+ rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_selected);
+
+ // Make sure bad rating is blank
+ if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_dark);
+ } else {
+ rateBadButton.setImageResource(Util.getAttribute(context, R.attr.rating_bad));
+ }
+ }
}
});
@@ -496,19 +530,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis downloadService.setShufflePlayEnabled(true);
}
- boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerAvailable();
-
- if (!equalizerAvailable) {
- equalizerButton.setVisibility(View.GONE);
- visualizerButton.setVisibility(View.GONE);
- } else {
- visualizerView = new VisualizerView(context);
- if(downloadService.getShowVisualization()) {
- visualizerView.setActive(true);
- }
- visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
- }
-
if(Build.MODEL.equals("Nexus 4") || Build.MODEL.equals("GT-I9100")) {
View slider = rootView.findViewById(R.id.download_slider);
slider.setPadding(0, 0, 0, 0);
@@ -535,6 +556,19 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(downloadService != null && downloadService.isRemovePlayed()) {
menu.findItem(R.id.menu_remove_played).setChecked(true);
}
+
+ boolean equalizerAvailable = downloadService != null && downloadService.getEqualizerAvailable();
+ if(equalizerAvailable) {
+ SharedPreferences prefs = Util.getPreferences(context);
+ boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false);
+ if (equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
+ getDownloadService().getEqualizerController().isEnabled()) {
+ menu.findItem(R.id.menu_equalizer).setChecked(true);
+ }
+ } else {
+ menu.removeItem(R.id.menu_equalizer);
+ }
+
if(downloadService != null) {
MenuItem mediaRouteItem = menu.findItem(R.id.menu_mediaroute);
if(mediaRouteItem != null) {
@@ -595,7 +629,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis private boolean menuItemSelected(int menuItemId, final DownloadFile song) {
switch (menuItemId) {
case R.id.menu_show_album: case R.id.menu_show_artist:
- MusicDirectory.Entry entry = song.getSong();
+ Entry entry = song.getSong();
Intent intent = new Intent(context, SubsonicFragmentActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true);
@@ -648,16 +682,16 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(context, intent);
return true;
- case R.id.menu_lyrics:
+ case R.id.menu_lyrics: {
SubsonicFragment fragment = new LyricsFragment();
Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ARTIST, song.getSong().getArtist());
args.putString(Constants.INTENT_EXTRA_NAME_TITLE, song.getSong().getTitle());
fragment.setArguments(args);
-
+
replaceFragment(fragment);
return true;
- case R.id.menu_remove:
+ } case R.id.menu_remove:
new SilentBackgroundTask<Void>(context) {
@Override
protected Void doInBackground() throws Throwable {
@@ -672,7 +706,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis }.execute();
return true;
case R.id.menu_delete:
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(1);
+ List<Entry> songs = new ArrayList<Entry>(1);
songs.add(song.getSong());
getDownloadService().delete(songs);
return true;
@@ -729,7 +763,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis }.execute();
return true;
case R.id.menu_save_playlist:
- List<MusicDirectory.Entry> entries = new LinkedList<MusicDirectory.Entry>();
+ List<Entry> entries = new LinkedList<Entry>();
for (DownloadFile downloadFile : getDownloadService().getSongs()) {
entries.add(downloadFile.getSong());
}
@@ -747,7 +781,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis }
return true;
case R.id.menu_add_playlist:
- songs = new ArrayList<MusicDirectory.Entry>(1);
+ songs = new ArrayList<Entry>(1);
songs.add(song.getSong());
addToPlaylist(songs);
return true;
@@ -755,10 +789,22 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis displaySongInfo(song.getSong());
return true;
case R.id.menu_share:
- songs = new ArrayList<MusicDirectory.Entry>(1);
+ songs = new ArrayList<Entry>(1);
songs.add(song.getSong());
createShare(songs);
- default:
+ return true;
+ case R.id.menu_equalizer: {
+ DownloadService downloadService = getDownloadService();
+ if (downloadService != null && downloadService.getEqualizerController() != null
+ && downloadService.getEqualizerController().getEqualizer() != null) {
+ SubsonicFragment fragment = new EqualizerFragment();
+ replaceFragment(fragment);
+ setControlsVisible(true);
+ } else {
+ Util.toast(context, "Failed to start equalizer. Try restarting.");
+ }
+ return true;
+ } default:
return false;
}
}
@@ -795,10 +841,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis context.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
- if (visualizerView != null && downloadService != null && downloadService.getShowVisualization()) {
- visualizerView.setActive(true);
- }
-
updateButtons();
if(currentPlaying == null && downloadService != null && currentPlaying == downloadService.getCurrentPlaying()) {
@@ -813,9 +855,6 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis public void onPause() {
super.onPause();
executorService.shutdown();
- if (visualizerView != null && visualizerView.isActive()) {
- visualizerView.setActive(false);
- }
if(getDownloadService() != null) {
getDownloadService().stopRemoteScan();
}
@@ -871,24 +910,15 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis if(context == null) {
return;
}
-
- SharedPreferences prefs = Util.getPreferences(context);
- boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false);
- if(equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
- getDownloadService().getEqualizerController().isEnabled()) {
- equalizerButton.setTextColor(COLOR_BUTTON_ENABLED);
- } else {
- equalizerButton.setTextColor(COLOR_BUTTON_DISABLED);
- }
-
- if (visualizerView != null) {
- visualizerButton.setTextColor(visualizerView.isActive() ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
- }
if(Util.isOffline(context)) {
bookmarkButton.setVisibility(View.GONE);
+ rateBadButton.setVisibility(View.GONE);
+ rateGoodButton.setVisibility(View.GONE);
} else {
bookmarkButton.setVisibility(View.VISIBLE);
+ rateBadButton.setVisibility(View.VISIBLE);
+ rateGoodButton.setVisibility(View.VISIBLE);
}
}
@@ -1130,11 +1160,39 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis @Override
protected void done(Void result) {
if (currentPlaying != null) {
- MusicDirectory.Entry song = currentPlaying.getSong();
+ Entry song = currentPlaying.getSong();
songTitleTextView.setText(song.getTitle());
getImageLoader().loadImage(albumArtImageView, song, true, true);
starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, currentPlayingSize));
+
+ int badRating, goodRating, bookmark;
+ if(song.getRating() == 1) {
+ badRating = R.drawable.ic_action_rating_bad_selected;
+ } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ badRating = R.drawable.ic_action_rating_bad_dark;
+ } else {
+ badRating = Util.getAttribute(context, R.attr.rating_bad);
+ }
+ rateBadButton.setImageResource(badRating);
+
+ if(song.getRating() == 5) {
+ goodRating = R.drawable.ic_action_rating_good_selected;
+ } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ goodRating = R.drawable.ic_action_rating_good_dark;
+ } else {
+ goodRating = Util.getAttribute(context, R.attr.rating_good);
+ }
+ rateGoodButton.setImageResource(goodRating);
+
+ if(song.getBookmark() != null) {
+ bookmark = R.drawable.ic_menu_bookmark_selected;
+ } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ bookmark = R.drawable.ic_menu_bookmark_dark;
+ } else {
+ bookmark = Util.getAttribute(context, R.attr.bookmark);
+ }
+ bookmarkButton.setImageResource(bookmark);
} else {
songTitleTextView.setText(null);
getImageLoader().loadImage(albumArtImageView, null, true, false);
@@ -1317,13 +1375,13 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis new SilentBackgroundTask<Void>(context) {
@Override
protected Void doInBackground() throws Throwable {
- MusicDirectory.Entry currentSong = currentDownload.getSong();
+ Entry currentSong = currentDownload.getSong();
MusicService musicService = MusicServiceFactory.getMusicService(context);
int position = getDownloadService().getPlayerPosition();
musicService.createBookmark(currentSong.getId(), Util.getParentFromEntry(context, currentSong), position, comment, context, null);
currentSong.setBookmark(new Bookmark(position));
- MusicDirectory.Entry find = UpdateView.findEntry(currentSong);
+ Entry find = UpdateView.findEntry(currentSong);
if(find != null && find != currentSong) {
find.setBookmark(new Bookmark(position));
}
diff --git a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java index a8b1f96b..3da49abd 100644 --- a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java +++ b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java @@ -274,7 +274,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter addToPlaylist(getSelectedSongs());
return true;
case R.id.menu_remove_playlist:
- // TODO: getSelected is returning offset
removeFromPlaylist(playlistId, playlistName, getSelectedIndexes());
return true;
case R.id.menu_download_all:
@@ -808,7 +807,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter for (int i = 0; i < count; i++) {
if (entryList.isItemChecked(i)) {
MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
- if(!entry.isDirectory()) {
+ // Don't try to add directories or 1-starred songs
+ if(!entry.isDirectory() && entry.getRating() != 1) {
songs.add(entry);
}
}
diff --git a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java index 4fa7019b..acdf46c3 100644 --- a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java +++ b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java @@ -46,6 +46,7 @@ import android.widget.Button; import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.LinearLayout;
+import android.widget.RatingBar;
import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.activity.DownloadActivity;
@@ -185,6 +186,10 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR }
else {
inflater.inflate(R.menu.select_album_context, menu);
+
+ if(Util.isTagBrowsing(context)) {
+ menu.removeItem(R.id.menu_rate);
+ }
}
menu.findItem(entry.isDirectory() ? R.id.album_menu_star : R.id.song_menu_star).setTitle(entry.isStarred() ? R.string.common_unstar : R.string.common_star);
} else if(!entry.isVideo()) {
@@ -247,6 +252,9 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_SHARED, true) || !UserUtil.canShare()) {
menu.setGroupVisible(R.id.hide_share, false);
}
+ if(!prefs.getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true)) {
+ menu.setGroupVisible(R.id.hide_rating, false);
+ }
}
protected void recreateContextMenu(ContextMenu menu) {
@@ -379,6 +387,9 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR case R.id.bookmark_menu_delete:
deleteBookmark(entry, null);
break;
+ case R.id.menu_rate:
+ setRating(entry);
+ break;
default:
return false;
}
@@ -848,7 +859,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR }
for (Entry song : parent.getChildren(false, true)) {
- if (!song.isVideo()) {
+ if (!song.isVideo() && song.getRating() != 1) {
songs.add(song);
}
}
@@ -1175,6 +1186,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR if(song.getDuration() != null && song.getDuration() != 0) {
msg += "\nLength: " + Util.formatDuration(song.getDuration());
}
+ if(song.getBookmark() != null) {
+ msg += "\nBookmark Position: " + Util.formatDuration(song.getBookmark().getPosition() / 1000);
+ }
+ if(song.getRating() != 0) {
+ msg += "\nRating: " + song.getRating() + " stars";
+ }
if(song instanceof PodcastEpisode) {
msg += "\n\nDescription: " + song.getAlbum();
}
@@ -1446,17 +1463,26 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR Entry selected = entries.isEmpty() ? null : entries.get(0);
playNow(entries, selected, position);
}
- protected void playNow(List<Entry> entries, Entry song, int position) {
- DownloadService downloadService = getDownloadService();
- if(downloadService == null) {
- return;
- }
-
- downloadService.clear();
- if(song != null) {
- downloadService.download(entries, false, true, true, false, entries.indexOf(song), position);
- }
- Util.startActivityWithoutTransition(context, DownloadActivity.class);
+ protected void playNow(final List<Entry> entries, final Entry song, final int position) {
+ new LoadingTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return null;
+ }
+
+ downloadService.clear();
+ downloadService.download(entries, false, true, true, false, entries.indexOf(song), position);
+
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ Util.startActivityWithoutTransition(context, DownloadActivity.class);
+ }
+ }.execute();
}
protected void deleteBookmark(final MusicDirectory.Entry entry, final ArrayAdapter adapter) {
@@ -1497,4 +1523,60 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR }
});
}
+
+ protected void setRating(final Entry entry) {
+ View layout = context.getLayoutInflater().inflate(R.layout.rating, null);
+ final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.rating_bar);
+ ratingBar.setRating((float) entry.getRating());
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(context.getResources().getString(R.string.rating_title, entry.getTitle()))
+ .setView(layout)
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ int rating = (int) ratingBar.getRating();
+ setRating(entry, rating);
+ }
+ })
+ .setNegativeButton(R.string.common_cancel, null);
+
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+
+ protected void setRating(final Entry entry, final int rating) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.setRating(entry, rating, context, null);
+
+ entry.setRating(rating);
+
+ Entry findEntry = UpdateView.findEntry(entry);
+ if(findEntry != null) {
+ findEntry.setRating(rating);
+ }
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ Util.toast(context, getResources().getString(rating > 0 ? R.string.rating_set_rating : R.string.rating_remove_rating, entry.getTitle()));
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(rating > 0 ? R.string.rating_set_rating_failed : R.string.rating_remove_rating_failed, entry.getTitle()) + " " + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
+ }.execute();
+ }
}
diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java index 90e5539c..be788596 100644 --- a/src/github/daneren2005/dsub/service/CachedMusicService.java +++ b/src/github/daneren2005/dsub/service/CachedMusicService.java @@ -792,8 +792,15 @@ public class CachedMusicService implements MusicService { } @Override - public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception { - musicService.setRating(id, rating, context, progressListener); + public void setRating(final Entry entry, final int rating, Context context, ProgressListener progressListener) throws Exception { + musicService.setRating(entry, rating, context, progressListener); + + new GenericSongUpdater(context, entry) { + @Override + public void updateResult(Entry result) { + result.setRating(rating); + } + }.execute(); } @Override @@ -1222,6 +1229,61 @@ public class CachedMusicService implements MusicService { } } } + private abstract class GenericSongUpdater { + Context context; + Entry entry; + + public GenericSongUpdater(Context context, Entry entry) { + this.context = context; + this.entry = entry; + } + + public boolean checkResult(Entry check) { + return entry.getId().equals(check.getId()); + } + public abstract void updateResult(Entry result); + + public void execute() { + String cacheName, parent; + if(Util.isTagBrowsing(context, musicService.getInstance(context))) { + // If starring album, needs to reference artist instead + if(entry.isDirectory()) { + cacheName = "artist"; + parent = entry.getArtistId(); + } else { + cacheName = "album"; + parent = entry.getAlbumId(); + } + } else { + cacheName = "directory"; + parent = entry.getParent(); + } + + new MusicDirectoryUpdater(context, cacheName, parent) { + @Override + public boolean checkResult(Entry check) { + return GenericSongUpdater.this.checkResult(check); + } + + @Override + public void updateResult(List<Entry> objects, Entry result) { + GenericSongUpdater.this.updateResult(result); + } + }.execute(); + + new PlaylistDirectoryUpdater(context) { + @Override + public boolean checkResult(Entry check) { + return GenericSongUpdater.this.checkResult(check); + } + + @Override + public void updateResult(Entry result) { + GenericSongUpdater.this.updateResult(result); + } + }.execute(); + } + } private abstract class IndexesUpdater extends SerializeUpdater<Artist> { Indexes indexes; diff --git a/src/github/daneren2005/dsub/service/DownloadService.java b/src/github/daneren2005/dsub/service/DownloadService.java index e5495bc2..b3198f3d 100644 --- a/src/github/daneren2005/dsub/service/DownloadService.java +++ b/src/github/daneren2005/dsub/service/DownloadService.java @@ -32,7 +32,6 @@ import static github.daneren2005.dsub.domain.PlayerState.STOPPED; import github.daneren2005.dsub.R; import github.daneren2005.dsub.audiofx.AudioEffectsController; import github.daneren2005.dsub.audiofx.EqualizerController; -import github.daneren2005.dsub.audiofx.VisualizerController; import github.daneren2005.dsub.domain.Bookmark; import github.daneren2005.dsub.domain.MusicDirectory; import github.daneren2005.dsub.domain.PlayerState; @@ -137,7 +136,6 @@ public class DownloadService extends Service { private boolean downloadOngoing = false; private AudioEffectsController effectsController; - private boolean showVisualization; private RemoteControlState remoteState = RemoteControlState.LOCAL; private PositionCache positionCache; private BufferProxy proxy; @@ -187,10 +185,6 @@ public class DownloadService extends Service { if(prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false)) { getEqualizerController(); } - if(prefs.getBoolean(Constants.PREFERENCES_VISUALIZER_ON, false)) { - getVisualizerController(); - showVisualization = true; - } mediaPlayerLooper = Looper.myLooper(); mediaPlayerHandler = new Handler(mediaPlayerLooper); @@ -477,17 +471,6 @@ public class DownloadService extends Service { editor.commit(); } - public boolean getShowVisualization() { - return showVisualization; - } - - public void setShowVisualization(boolean showVisualization) { - this.showVisualization = showVisualization; - SharedPreferences.Editor editor = Util.getPreferences(this).edit(); - editor.putBoolean(Constants.PREFERENCES_VISUALIZER_ON, showVisualization); - editor.commit(); - } - public synchronized DownloadFile forSong(MusicDirectory.Entry song) { DownloadFile returnFile = null; for (DownloadFile downloadFile : downloadList) { @@ -1180,10 +1163,6 @@ public class DownloadService extends Service { return effectsController.getEqualizerController(); } - public VisualizerController getVisualizerController() { - return effectsController.getVisualizerController(); - } - public MediaRouteSelector getRemoteSelector() { return mediaRouter.getSelector(); } diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java index d70f1c46..466ad477 100644 --- a/src/github/daneren2005/dsub/service/MusicService.java +++ b/src/github/daneren2005/dsub/service/MusicService.java @@ -152,7 +152,7 @@ public interface MusicService { void deletePodcastEpisode(String id, String parent, ProgressListener progressListener, Context context) throws Exception; - void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception; + void setRating(MusicDirectory.Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception; MusicDirectory getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception; diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java index 788057d2..e20a2b41 100644 --- a/src/github/daneren2005/dsub/service/OfflineMusicService.java +++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java @@ -737,7 +737,7 @@ public class OfflineMusicService implements MusicService { } @Override - public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception { + public void setRating(MusicDirectory.Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception { throw new OfflineException(ERRORMSG); } diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java index d6715e8c..991ad5ee 100644 --- a/src/github/daneren2005/dsub/service/RESTMusicService.java +++ b/src/github/daneren2005/dsub/service/RESTMusicService.java @@ -1126,10 +1126,10 @@ public class RESTMusicService implements MusicService { } @Override - public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception { + public void setRating(MusicDirectory.Entry entry, int rating, Context context, ProgressListener progressListener) throws Exception { checkServerVersion(context, "1.6", "Setting ratings not supported."); - Reader reader = getReader(context, progressListener, "setRating", null, Arrays.asList("id", "rating"), Arrays.<Object>asList(id, rating)); + Reader reader = getReader(context, progressListener, "setRating", null, Arrays.asList("id", "rating"), Arrays.<Object>asList(entry.getId(), rating)); try { new ErrorParser(context, getInstance(context)).parse(reader); } finally { diff --git a/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java b/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java index 683f6857..c5d5ec51 100644 --- a/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java +++ b/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java @@ -47,6 +47,7 @@ public class MusicDirectoryEntryParser extends AbstractParser { entry.setYear(getInteger("year")); entry.setGenre(get("genre")); entry.setAlbum(get("album")); + entry.setRating(getInteger("userRating")); if (!entry.isDirectory()) { entry.setAlbumId(get("albumId")); diff --git a/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java index c0aecfa2..e96ccb3e 100644 --- a/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java +++ b/src/github/daneren2005/dsub/service/sync/PlaylistSyncAdapter.java @@ -44,8 +44,8 @@ import github.daneren2005.dsub.util.Util; public class PlaylistSyncAdapter extends SubsonicSyncAdapter {
private static String TAG = PlaylistSyncAdapter.class.getSimpleName();
- // Update playlists at least once a week
- private static int MAX_PLAYLIST_AGE = 24 * 7;
+ // Update playlists every day to make sure they are still valid
+ private static int MAX_PLAYLIST_AGE = 24;
public PlaylistSyncAdapter(Context context, boolean autoInitialize) {
super(context, autoInitialize);
diff --git a/src/github/daneren2005/dsub/util/Constants.java b/src/github/daneren2005/dsub/util/Constants.java index 5fb872f2..ac21df4c 100644 --- a/src/github/daneren2005/dsub/util/Constants.java +++ b/src/github/daneren2005/dsub/util/Constants.java @@ -108,7 +108,6 @@ public final class Constants { public static final String PREFERENCES_KEY_SHUFFLE_GENRE = "genre"; public static final String PREFERENCES_KEY_KEEP_SCREEN_ON = "keepScreenOn"; public static final String PREFERENCES_EQUALIZER_ON = "equalizerOn"; - public static final String PREFERENCES_VISUALIZER_ON = "visualizerOn"; public static final String PREFERENCES_EQUALIZER_SETTINGS = "equalizerSettings"; public static final String PREFERENCES_KEY_PERSISTENT_NOTIFICATION = "persistentNotification"; public static final String PREFERENCES_KEY_GAPLESS_PLAYBACK = "gaplessPlayback"; @@ -145,6 +144,7 @@ public final class Constants { public static final String PREFERENCES_KEY_PLAYLIST_ID = "suggestedPlaylistId"; public static final String PREFERENCES_KEY_SERVER_SYNC = "serverSync"; public static final String PREFERENCES_KEY_RECENT_COUNT = "mostRecentCount"; + public static final String PREFERENCES_KEY_MENU_RATING = "showRating"; public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount"; public static final String OFFLINE_SCROBBLE_ID = "scrobbleID"; diff --git a/src/github/daneren2005/dsub/util/Util.java b/src/github/daneren2005/dsub/util/Util.java index 2e4872c8..c80c0824 100644 --- a/src/github/daneren2005/dsub/util/Util.java +++ b/src/github/daneren2005/dsub/util/Util.java @@ -30,6 +30,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.content.res.Resources; +import android.content.res.TypedArray; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.drawable.BitmapDrawable; @@ -1089,6 +1090,15 @@ public final class Util { } } + public static int getAttribute(Context context, int attr) { + int res; + int[] attrs = new int[] {attr}; + TypedArray typedArray = context.obtainStyledAttributes(attrs); + res = typedArray.getResourceId(0, 0); + typedArray.recycle(); + return res; + } + public static void registerMediaButtonEventReceiver(Context context) { // Only do it if enabled in the settings. diff --git a/src/github/daneren2005/dsub/view/SongView.java b/src/github/daneren2005/dsub/view/SongView.java index d5b7c0f2..8d986090 100644 --- a/src/github/daneren2005/dsub/view/SongView.java +++ b/src/github/daneren2005/dsub/view/SongView.java @@ -20,6 +20,7 @@ package github.daneren2005.dsub.view; import android.content.Context; import android.content.res.TypedArray; +import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.widget.*; @@ -48,6 +49,7 @@ public class SongView extends UpdateView implements Checkable { private TextView durationTextView; private TextView statusTextView; private ImageView statusImageView; + private ImageView bookmarkButton; private View bottomRowView; private DownloadService downloadService; @@ -62,6 +64,10 @@ public class SongView extends UpdateView implements Checkable { private File partialFile; private boolean partialFileExists = false; private boolean loaded = false; + private boolean isBookmarked = false; + private boolean bookmarked = false; + private int isRated = 0; + private int rating = 0; public SongView(Context context) { super(context); @@ -75,6 +81,8 @@ public class SongView extends UpdateView implements Checkable { statusImageView = (ImageView) findViewById(R.id.song_status_icon); starButton = (ImageButton) findViewById(R.id.song_star); starButton.setFocusable(false); + bookmarkButton = (ImageButton) findViewById(R.id.song_bookmark); + bookmarkButton.setFocusable(false); moreButton = (ImageView) findViewById(R.id.artist_more); moreButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { @@ -139,6 +147,9 @@ public class SongView extends UpdateView implements Checkable { artistTextView.setText(artist); checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE); + this.setBackgroundColor(0x00000000); + rating = 0; + revision = -1; loaded = false; } @@ -163,6 +174,8 @@ public class SongView extends UpdateView implements Checkable { partialFile = downloadFile.getPartialFile(); partialFileExists = partialFile.exists(); isStarred = song.isStarred(); + isBookmarked = song.getBookmark() != null; + isRated = song.getRating(); // Check if needs to load metadata: check against all fields that we know are null in offline mode if(song.getBitRate() == null && song.getDuration() == null && song.getDiscNumber() == null && isWorkDone) { @@ -232,6 +245,34 @@ public class SongView extends UpdateView implements Checkable { titleTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0); } } + + if(isBookmarked) { + if(!bookmarked) { + bookmarkButton.setVisibility(View.VISIBLE); + bookmarked = true; + } + } else { + if(bookmarked) { + bookmarkButton.setVisibility(View.GONE); + bookmarked = false; + } + } + + if(isRated != rating) { + // Color the entire row based on rating + if(isRated > 3) { + this.setBackgroundColor(Color.GREEN); + this.getBackground().setAlpha(5 * (isRated - 3)); + } else if(isRated < 3 && isRated > 0) { + this.setBackgroundColor(Color.RED); + // Use darker colors the lower the rating goes + this.getBackground().setAlpha(10 * (3 - isRated)); + } else { + this.setBackgroundColor(0x00000000); + } + + rating = isRated; + } } @Override diff --git a/src/github/daneren2005/dsub/view/VisualizerView.java b/src/github/daneren2005/dsub/view/VisualizerView.java deleted file mode 100644 index aa921930..00000000 --- a/src/github/daneren2005/dsub/view/VisualizerView.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - This file is part of Subsonic. - - Subsonic 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 - (at your option) any later version. - - Subsonic 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 Subsonic. If not, see <http://www.gnu.org/licenses/>. - - Copyright 2011 (C) Sindre Mehus - */ -package github.daneren2005.dsub.view; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Paint; -import android.media.audiofx.Visualizer; -import android.view.View; -import github.daneren2005.dsub.audiofx.VisualizerController; -import github.daneren2005.dsub.domain.PlayerState; -import github.daneren2005.dsub.service.DownloadService; - -/** - * A simple class that draws waveform data received from a - * {@link Visualizer.OnDataCaptureListener#onWaveFormDataCapture} - * - * @author Sindre Mehus - * @version $Id$ - */ -public class VisualizerView extends View { - - private static final int PREFERRED_CAPTURE_RATE_MILLIHERTZ = 20000; - - private final Paint paint = new Paint(); - - private byte[] data; - private float[] points; - private boolean active = false; - - public VisualizerView(Context context) { - super(context); - - paint.setStrokeWidth(2f); - paint.setAntiAlias(true); - paint.setColor(Color.rgb(51, 181, 229)); - } - - public boolean isActive() { - return active; - } - - public void setActive(boolean active) { - this.active = active; - VisualizerController visualizerController = getVizualiser(); - Visualizer visualizer = visualizerController == null ? null : visualizerController.getVisualizer(); - if (visualizer == null) { - this.active = false; - return; - } - - int captureRate = Math.min(PREFERRED_CAPTURE_RATE_MILLIHERTZ, Visualizer.getMaxCaptureRate()); - if (active) { - visualizer.setDataCaptureListener(new Visualizer.OnDataCaptureListener() { - @Override - public void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate) { - updateVisualizer(waveform); - } - - @Override - public void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate) { - } - }, captureRate, true, false); - } else { - visualizer.setDataCaptureListener(null, captureRate, false, false); - } - - visualizer.setEnabled(active); - if(!active) { - visualizerController.release(); - } - invalidate(); - } - - private VisualizerController getVizualiser() { - DownloadService downloadService = DownloadService.getInstance(); - VisualizerController visualizerController = downloadService == null ? null : downloadService.getVisualizerController(); - return visualizerController; - } - - private void updateVisualizer(byte[] waveform) { - this.data = waveform; - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - if (!active) { - return; - } - DownloadService downloadService = DownloadService.getInstance(); - if (downloadService != null && downloadService.getPlayerState() != PlayerState.STARTED) { - return; - } - - if (data == null) { - return; - } - - if (points == null || points.length < data.length * 4) { - points = new float[data.length * 4]; - } - - int w = getWidth(); - int h = getHeight(); - - for (int i = 0; i < data.length - 1; i++) { - points[i * 4] = w * i / (data.length - 1); - points[i * 4 + 1] = h / 2 + ((byte) (data[i] + 128)) * (h / 2) / 128; - points[i * 4 + 2] = w * (i + 1) / (data.length - 1); - points[i * 4 + 3] = h / 2 + ((byte) (data[i + 1] + 128)) * (h / 2) / 128; - } - - canvas.drawLines(points, paint); - } -} |