aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AndroidManifest.xml4
-rw-r--r--res/layout/album_cell_item.xml24
-rw-r--r--res/layout/album_list_item.xml28
-rw-r--r--res/layout/select_album_header.xml42
-rw-r--r--res/layout/song_list_item.xml10
-rw-r--r--res/menu/nowplaying_context.xml6
-rw-r--r--res/values-es/strings.xml14
-rw-r--r--res/values-fr/strings.xml25
-rw-r--r--res/values-hu/strings.xml30
-rw-r--r--res/values/dimens.xml2
-rw-r--r--res/values/strings.xml1
-rw-r--r--res/xml/changelog.xml26
-rw-r--r--src/github/daneren2005/dsub/domain/Artist.java67
-rw-r--r--src/github/daneren2005/dsub/domain/Indexes.java15
-rw-r--r--src/github/daneren2005/dsub/domain/MusicDirectory.java9
-rw-r--r--src/github/daneren2005/dsub/fragments/MainFragment.java5
-rw-r--r--src/github/daneren2005/dsub/fragments/NowPlayingFragment.java78
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java145
-rw-r--r--src/github/daneren2005/dsub/fragments/SubsonicFragment.java159
-rw-r--r--src/github/daneren2005/dsub/service/CachedMusicService.java160
-rw-r--r--src/github/daneren2005/dsub/service/DownloadService.java14
-rw-r--r--src/github/daneren2005/dsub/service/MediaStoreService.java9
-rw-r--r--src/github/daneren2005/dsub/service/OfflineMusicService.java37
-rw-r--r--src/github/daneren2005/dsub/service/RESTMusicService.java41
-rw-r--r--src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java2
-rw-r--r--src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java4
-rw-r--r--src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java4
-rw-r--r--src/github/daneren2005/dsub/util/Constants.java4
-rw-r--r--src/github/daneren2005/dsub/util/FileUtil.java43
-rw-r--r--src/github/daneren2005/dsub/util/ImageLoader.java2
-rw-r--r--src/github/daneren2005/dsub/view/AlbumCell.java8
-rw-r--r--src/github/daneren2005/dsub/view/AlbumView.java7
-rw-r--r--src/github/daneren2005/dsub/view/DownloadFileAdapter.java1
-rw-r--r--src/github/daneren2005/dsub/view/SongView.java40
-rw-r--r--src/github/daneren2005/dsub/view/UpdateView.java31
35 files changed, 862 insertions, 235 deletions
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 62ad9f85..752392a8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -2,8 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="github.daneren2005.dsub"
android:installLocation="internalOnly"
- android:versionCode="122"
- android:versionName="4.7.5">
+ android:versionCode="125"
+ android:versionName="4.7.7">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
diff --git a/res/layout/album_cell_item.xml b/res/layout/album_cell_item.xml
index 5f4735fe..3dd79477 100644
--- a/res/layout/album_cell_item.xml
+++ b/res/layout/album_cell_item.xml
@@ -4,12 +4,28 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <github.daneren2005.dsub.view.SquareImageView
- android:id="@+id/album_coverart"
+ <RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
- android:layout_weight="1"
- android:src="@drawable/unknown_album"/>
+ android:layout_weight="1">
+
+ <github.daneren2005.dsub.view.SquareImageView
+ android:id="@+id/album_coverart"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:src="@drawable/unknown_album"/>
+
+ <RatingBar
+ android:id="@+id/album_rating"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:isIndicator="true"
+ android:layout_centerHorizontal="true"
+ android:numStars="5"
+ style="@android:style/Widget.Holo.RatingBar.Small"
+ android:layout_alignParentBottom="true"
+ android:visibility="gone"/>
+ </RelativeLayout>
<LinearLayout
android:layout_width="fill_parent"
diff --git a/res/layout/album_list_item.xml b/res/layout/album_list_item.xml
index aae87638..27ab3c63 100644
--- a/res/layout/album_list_item.xml
+++ b/res/layout/album_list_item.xml
@@ -5,11 +5,28 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content">
- <ImageView
- android:id="@+id/album_coverart"
+ <RelativeLayout
android:layout_width="@dimen/AlbumArt.Small"
- android:layout_height="@dimen/AlbumArt.Small"
- android:layout_gravity="left|center_vertical"/>
+ android:layout_height="@dimen/AlbumArt.Small">
+
+ <ImageView
+ android:id="@+id/album_coverart"
+ android:layout_width="@dimen/AlbumArt.Small"
+ android:layout_height="@dimen/AlbumArt.Small"
+ android:layout_gravity="left|center_vertical"
+ android:src="@drawable/unknown_album"/>
+
+ <RatingBar
+ android:id="@+id/album_rating"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:isIndicator="true"
+ android:layout_centerHorizontal="true"
+ android:numStars="5"
+ style="@android:style/Widget.Holo.RatingBar.Small"
+ android:layout_alignParentBottom="true"
+ android:visibility="gone"/>
+ </RelativeLayout>
<LinearLayout
android:orientation="vertical"
@@ -26,7 +43,8 @@
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:singleLine="true"
- android:ellipsize="marquee"/>
+ android:ellipsize="marquee"
+ android:paddingBottom="6dip"/>
<TextView
android:id="@+id/album_artist"
diff --git a/res/layout/select_album_header.xml b/res/layout/select_album_header.xml
index 4110d530..a253aa31 100644
--- a/res/layout/select_album_header.xml
+++ b/res/layout/select_album_header.xml
@@ -71,16 +71,44 @@
</LinearLayout>
- <ImageView
- android:id="@+id/select_album_share"
- android:layout_height="wrap_content"
+ <LinearLayout
android:layout_width="wrap_content"
- android:scaleType="fitCenter"
- android:src="?attr/share"
- android:padding="10dip"
+ android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
- style="@style/BasicButton"/>
+ android:padding="10dip">
+
+ <LinearLayout
+ android:id="@+id/select_album_rate_wrapper"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent">
+
+ <RatingBar
+ android:id="@+id/select_album_rate"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:numStars="5"
+ style="@android:style/Widget.Holo.RatingBar.Small"
+ android:layout_gravity="center_vertical"/>
+ </LinearLayout>
+
+ <ImageButton
+ android:id="@+id/select_album_star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ style="@style/BasicButton"
+ android:src="@android:drawable/star_big_off"
+ android:layout_gravity="center_vertical"/>
+
+ <ImageView
+ android:id="@+id/select_album_share"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:scaleType="fitCenter"
+ android:src="?attr/share"
+ style="@style/BasicButton"
+ android:layout_gravity="center_vertical"/>
+ </LinearLayout>
</RelativeLayout>
diff --git a/res/layout/song_list_item.xml b/res/layout/song_list_item.xml
index 8febace9..d433df69 100644
--- a/res/layout/song_list_item.xml
+++ b/res/layout/song_list_item.xml
@@ -93,6 +93,16 @@
android:ellipsize="middle"
android:paddingLeft="6dip"/>
+ <RatingBar
+ android:id="@+id/song_rating"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:isIndicator="true"
+ android:layout_centerHorizontal="true"
+ android:numStars="5"
+ style="@android:style/Widget.Holo.RatingBar.Small"
+ android:visibility="gone"/>
+
<TextView
android:id="@+id/song_duration"
android:layout_width="wrap_content"
diff --git a/res/menu/nowplaying_context.xml b/res/menu/nowplaying_context.xml
index 4c936c0d..c9347353 100644
--- a/res/menu/nowplaying_context.xml
+++ b/res/menu/nowplaying_context.xml
@@ -38,6 +38,12 @@
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.8">
<item
android:id="@+id/menu_add_playlist"
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 6364bf72..e2350bab 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -99,6 +99,7 @@
<string name="menu.cast">Hacer streaming al dispositivo</string>
<string name="menu.add_user">Añadir usuario</string>
<string name="menu.rescan">Reescanear servidor</string>
+ <string name="menu.rate">Establecer valoración</string>
<string name="playlist.label">Listas de reproducción</string>
<string name="playlist.update_info">Actualizar información</string>
@@ -209,6 +210,7 @@
</string>
<string name="download.failed_to_load">Error al cargar</string>
<string name="download.menu_remove_played_songs">Borrar canciones reproducidas</string>
+ <string name="download.save_bookmark_failed">Error al crear marcador</string>
<string name="starring_content_starred">Marcado con estrella \"%s\"</string>
<string name="starring_content_unstarred">Sin marca de estrella \"%s\"</string>
@@ -225,6 +227,15 @@
<string name="bookmark.details">Canción: %1$s
\nComentario: %2$s
\nPosición: %3$s</string>
+ <string name="bookmark.resume_title">Reanudar reproducción?</string>
+ <string name="bookmark.resume">Reanudar reproducción \'%1$s\' desde%2$s</string>
+ <string name="bookmark.action_resume">Reanudar</string>
+ <string name="bookmark.action_start_over">Volver a comenzar</string>
+ <string name="rating.title">Valoración\"%s\"</string>
+ <string name="rating.set_rating">Valoración establecida para \"%s\"</string>
+ <string name="rating.set_rating_failed">Error al establecer valoración para \"%s\"</string>
+ <string name="rating.remove_rating">Valoración eliminada a \"%s\"</string>
+ <string name="rating.remove_rating_failed">Error al eliminar valoración a \"%s\"</string>
<string name="song_details.error">Error</string>
<string name="song_details.skipped">Saltados</string>
@@ -404,6 +415,9 @@
<string name="settings.large_album_art_summary">Mostrar los discos con carátulas grandes en vez de en lista</string>
<string name="settings.admin_enabled">Admin Habilitado</string>
<string name="settings.admin_enabled_summary">Mostrar u ocultar la pestaña de Admin en el menú</string>
+ <string name="settings.server_sync_summary">Activar o no la sincronización en este server</string>
+ <string name="settings.server_sync">Sincronización activada</string>
+ <string name="settings.menu_options.rate_summary">Mostrar valoración en los menús</string>
<string name="share.info">Dueño: %1$s
\nDescripción: %2$s
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index ab4c187d..40d04b42 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -50,14 +50,14 @@
<string name="main.faq_title">FAQ</string>
<string name="main.faq_text">
<![CDATA[
- <font color="red">Cache vs Cache permanent</font>:
+ <font color="red">Cache vs Cache permanent</font> :
<br/>Lorsque des titres sont téléchargés par DSub, ils peuvent être supprimés pour libérer de l\'espace pour de nouveaux téléchargements. Le cache permanent premet, lui, de ne jamais supprimer automatiquement la musique téléchargée.
- <p/><font color="red">ChromeCast a échoué</font>:
+ <p/><font color="red">ChromeCast a échoué</font> :
<br/>Assurez-vous de ne pas utiliser un certificat auto-signé, Chromecast les rejette systématiquement.
]]>
</string>
<string name="main.select_server">Choisir un serveur</string>
- <string name="main.shuffle">Jouer au hazard</string>
+ <string name="main.shuffle">Jouer au hasard</string>
<string name="main.offline">Déconnecter</string>
<string name="main.online">Connecter</string>
<string name="main.settings">Paramètres</string>
@@ -67,7 +67,7 @@
<string name="main.albums_frequent">Les plus joués</string>
<string name="main.albums_highest">Les mieux notés</string>
<string name="main.albums_starred">Favoris</string>
- <string name="main.albums_random">Au hazard</string>
+ <string name="main.albums_random">Au hasard</string>
<string name="main.albums_genres">Par genres</string>
<string name="main.albums_year">Par décennies</string>
<string name="main.songs_genres">@string/main.albums_genres</string>
@@ -75,7 +75,7 @@
<string name="main.scan_complete">Completed scan of Server</string>
<string name="menu.search">Recherche</string>
- <string name="menu.shuffle">Hazard</string>
+ <string name="menu.shuffle">Hasard</string>
<string name="menu.refresh">Recharger</string>
<string name="menu.select">Tout sélectionner</string>
<string name="menu.play">Jouer</string>
@@ -103,6 +103,7 @@
<string name="menu.faq">FAQ</string>
<string name="menu.add_user">Ajouter utilisateur</string>
<string name="menu.rescan">Relire le server</string>
+ <string name="menu.rate">Noter</string>
<string name="playlist.label">Playlists</string>
<string name="playlist.update_info">Mise à jour informations</string>
@@ -210,6 +211,7 @@
<string name="download.downloading_summary_expanded">En cours : %1$s
\nTaille estimée : %2$s</string>
<string name="download.failed_to_load">Echec du chargement</string>
+ <string name="download.save_bookmark_failed">Echec de la création du favori</string>
<string name="sync.new_podcasts">Nouveaux podcasts disponibles</string>
<string name="sync.new_playlists">Nouveaux titres dans les playlists</string>
@@ -235,6 +237,16 @@
\nCréé le : %3$s
\nMis à jour : %4$s
\nCommentaire : %5$s</string>
+ <string name="bookmark.resume_title">Reprendre la lecture ?</string>
+ <string name="bookmark.resume">Reprendre la lecture de \'%1$s\' depuis %2$s</string>
+ <string name="bookmark.action_resume">Reprendre</string>
+ <string name="bookmark.action_start_over">Start Over</string>
+
+ <string name="rating.title">Noter \"%s\"</string>
+ <string name="rating.set_rating">Note attribuée à \"%s\"</string>
+ <string name="rating.set_rating_failed">Echec de l\'attribution de la note à \"%s\"</string>
+ <string name="rating.remove_rating">Note supprimée pour \"%s\"</string>
+ <string name="rating.remove_rating_failed">Echec de la suppression de la note pour \"%s\"</string>
<string name="song_details.error">Erreur</string>
<string name="song_details.skipped">Ignoré</string>
@@ -398,11 +410,14 @@
<string name="settings.sync_starred_summary">Charger automatiquement les titres, albums et artistes bien notés</string>
<string name="settings.sync_notification">Afficher des notifications de synchro</string>
<string name="settings.sync_notification_summary">Afficher une notification dès qu\'un média a été synchronisé</string>
+ <string name="settings.server_sync_summary">Synchron autorisée ou non sur ce serveur</string>
+ <string name="settings.server_sync">Synchro autorisée</string>
<string name="settings.menu_options.title">Options de menu optionnelles</string>
<string name="settings.menu_options.play_next_summary">Afficher Lire suivant dans les menus</string>
<string name="settings.menu_options.play_last_summary">Afficher Lire dernier dans les menus</string>
<string name="settings.menu_options.star_summary">Afficher Noter dans les menus</string>
<string name="settings.menu_options.shared_summary">Afficher Partager dans les menus</string>
+ <string name="settings.menu_options.rate_summary">Montrer les notes dans les menus</string>
<string name="settings.browse_by_tags">Naviguer via les tags</string>
<string name="settings.browse_by_tags_summary">Naviguer via les tags plutôt que via l\'arborescence de fichier. Nécessite Subsonic 4.7+</string>
<string name="settings.override_system_language">Ne pas utiliser la langue du système</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 80d509be..c7fa1728 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -63,11 +63,11 @@
<string name="main.online">Online mód</string>
<string name="main.settings">Beállítások</string>
<string name="main.albums_title">Albumok</string>
- <string name="main.albums_newest">Utoljára hozzáadott</string>
- <string name="main.albums_recent">Utoljára lejátszott</string>
- <string name="main.albums_frequent">Legtöbbször lejátszott</string>
- <string name="main.albums_highest">Legjobbra értékelt</string>
- <string name="main.albums_starred">Csillagozott</string>
+ <string name="main.albums_newest">Utoljára hozzáadottak</string>
+ <string name="main.albums_recent">Utoljára lejátszottak</string>
+ <string name="main.albums_frequent">Legtöbbször lejátszottak</string>
+ <string name="main.albums_highest">Legjobbra értékeltek</string>
+ <string name="main.albums_starred">Csillagozottak</string>
<string name="main.albums_random">Véletlenszerű</string>
<string name="main.albums_genres">Műfajok</string>
<string name="main.albums_year">Évtizedek</string>
@@ -103,6 +103,7 @@
<string name="menu.faq">FAQ</string>
<string name="menu.add_user">Felhasználó hozzáadása</string>
<string name="menu.rescan">Médiatár frissítése a kiszolgálón</string>
+ <string name="menu.rate">Értékelés</string>
<string name="playlist.label">Lejátszási listák</string>
<string name="playlist.update_info">Szerkesztés</string>
@@ -186,7 +187,7 @@
<string name="download.playlist_title">Mentés lejátszási listába</string>
<string name="download.playlist_name">Lejátszási lista neve:</string>
<string name="download.playlist_saving">\"%s\" lejátszási lista mentése...</string>
- <string name="download.playlist_done">Lejátszási lista mentése sikeres.</string>
+ <string name="download.playlist_done">Lejátszási lista mentése sikeres</string>
<string name="download.playlist_error">Lejátszási lista mentése sikertelen, próbálja később!</string>
<string name="download.repeat_off">Ismétlés ki</string>
<string name="download.repeat_all">Összes ismétlése</string>
@@ -205,6 +206,7 @@
<string name="download.playing_out_of">Lejátszás: %1$d/%2$d</string>
<string name="download.save_bookmark_title">Könyvjelző létrehozása</string>
<string name="download.save_bookmark">Könyvjelző létrehozva</string>
+ <string name="download.save_bookmark_failed">Könyvjelző létrehozása sikertelen!</string>
<string name="download.downloading_title">%1$d dal letöltése</string>
<string name="download.downloading_summary">Aktuális: %1$s</string>
<string name="download.downloading_summary_expanded">Aktuális: %1$s
@@ -241,6 +243,12 @@
<string name="bookmark.action_resume">Folytatás</string>
<string name="bookmark.action_start_over">Kezdés</string>
+ <string name="rating.title">\"%s\" értékelése</string>
+ <string name="rating.set_rating">\"%s\" értékelése</string>
+ <string name="rating.set_rating_failed">\"%s\" értékelése sikertelen!</string>
+ <string name="rating.remove_rating">\"%s\" értékelése visszavonva</string>
+ <string name="rating.remove_rating_failed">\"%s\" értékelésének visszavonása sikertelen!</string>
+
<string name="song_details.error">Hiba</string>
<string name="song_details.skipped">Átlépve</string>
<string name="song_details.downloading">Letöltés</string>
@@ -263,6 +271,8 @@
<string name="settings.server_username">Felhasználónév</string>
<string name="settings.server_password">Jelszó</string>
<string name="settings.server_open_browser">Megnyitás böngészőben</string>
+ <string name="settings.server_sync_summary">Függetlenül attól, hogy a szinkronizálás engedélyezett-e ezen a kiszolgálón.</string>
+ <string name="settings.server_sync">Szinkronizálás engedélyezve</string>
<string name="settings.cache_title">Zene gyorsítótár (Cache)</string>
<string name="settings.preload_wifi">Dalok előolvasása (Wi-Fi)</string>
<string name="settings.preload_mobile">Dalok előolvasása (Mobilhálózat)</string>
@@ -408,6 +418,7 @@
<string name="settings.menu_options.play_last_summary">Sorbaállítás utolsónak opció megjelenítése a menüben.</string>
<string name="settings.menu_options.star_summary">Csillagozás opció megjelenítése a menüben.</string>
<string name="settings.menu_options.shared_summary">Megosztás opció megjelenítése a menüben.</string>
+ <string name="settings.menu_options.rate_summary">Értékelés opció megjelenítése a menüben.</string>
<string name="settings.browse_by_tags">Böngészés ID3 Tag használatával</string>
<string name="settings.browse_by_tags_summary">ID3 Tag módszer használata a fájlredszer alapú mód helyett. Subsonic 4.7+ verzió felett!</string>
<string name="settings.override_system_language">A rendszer nyelvének felülbírálása</string>
@@ -519,7 +530,7 @@
<string name="widget.4x2">DSub (4x2)</string>
<string name="widget.4x3">DSub (4x3)</string>
<string name="widget.4x4">DSub (4x4)</string>
- <string name="widget.initial_text">Érintse meg a zene kiválasztásához</string>
+ <string name="widget.initial_text">Érintse meg a zene kiválasztásához!</string>
<string name="widget.sdcard_busy">Az SD kártya nem elérhető!</string>
<string name="widget.sdcard_missing">Nincs SD kártya!</string>
@@ -537,6 +548,11 @@
<string name="changelog_version_format" xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">Version <xliff:g id="version_name">%s</xliff:g></string>
+ <string name="tasker.start_playing">Lejátszás indítása</string>
+ <string name="tasker.start_playing_shuffled">Lejátszás indítása kevert sorrendben</string>
+ <string name="tasker.start_playing_title">Tasker -> DSub indítása</string>
+ <string name="tasker.edit_shuffle_mode">Indítás kevert sorrendben: </string>
+
<plurals name="select_album_n_songs">
<item quantity="zero">Nincsenek dalok</item>
<item quantity="one">1 dal</item>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index cab253e9..d5be260f 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -2,6 +2,6 @@
<resources>
<dimen name="Button">54dip</dimen>
<dimen name="Button.Small">46dip</dimen>
- <dimen name="AlbumArt.Small">68dip</dimen>
+ <dimen name="AlbumArt.Small">78dip</dimen>
<dimen name="AlbumArt.Header">120dip</dimen>
</resources> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b31efda1..009e369b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -206,6 +206,7 @@
<string name="download.playing_out_of">Playing: %1$d/%2$d</string>
<string name="download.save_bookmark_title">Create bookmark</string>
<string name="download.save_bookmark">Bookmark created</string>
+ <string name="download.save_bookmark_failed">Failed to create bookmark</string>
<string name="download.downloading_title">Downloading %1$d songs</string>
<string name="download.downloading_summary">Current: %1$s</string>
<string name="download.downloading_summary_expanded">Current: %1$s
diff --git a/res/xml/changelog.xml b/res/xml/changelog.xml
index 0720184b..60c8d657 100644
--- a/res/xml/changelog.xml
+++ b/res/xml/changelog.xml
@@ -1,8 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog>
- <release version="4.7.6 Beta" versioncode="122" releasedate="8/29/2014">
- <change>Playback position fix for Nexus 5. Please let me know if you see any odd behavior with the playback position after this update.</change>
- <change>Windows Server: SNI Support</change>
+ <release version="4.7.7" versioncode="124" releasedate="9/8/2014">
+ <change>Add Set Rating to Now Playing's songs menu</change>
+ <change>Fix "overwrite existing playlist" not showing</change>
+ <change>Fix duplicate songs display status in Now Playing</change>
+ </release>
+ <release version="4.7.6" versioncode="123" releasedate="9/5/2014">
+ <change>Ratings: set album/song ratings</change>
+ <change>Ratings: quick thumbs up/down from now playing screen</change>
+ <change>Ratings: automatically ignore 1-starred songs</change>
+ <change>Add To Playlist: show when song already in</change>
+ <change>Recently Added: show count from Home</change>
+ <change>Bookmarks: auto bookmark tagged Audio Books</change>
+ <change>Bookmarks: show indicator in listing/now playing screen</change>
+ <change>Video: Download using hls transcode settings</change>
+ <change>Sync: Disable per server</change>
+ <change>Global Shuffle: optimize for large list preferences</change>
+ <change>Global Shuffle: don't add duplicates</change>
+ <change>Offline Shuffle: improve randomness</change>
+ <change>Move EQ to options menu</change>
+ <change>Fix issue with empty folder</change>
+ <change>Fix various cache coherency issues</change>
+ <change>Old Servers: fix broken scrobbling</change>
+ <change>Fix cache location reseting</change>
</release>
<release version="4.7.5" versioncode="121" releasedate="8/24/2014">
<change>Bookmarks: Resume from albums/playlists</change>
diff --git a/src/github/daneren2005/dsub/domain/Artist.java b/src/github/daneren2005/dsub/domain/Artist.java
index e4a9001b..f30147e6 100644
--- a/src/github/daneren2005/dsub/domain/Artist.java
+++ b/src/github/daneren2005/dsub/domain/Artist.java
@@ -18,12 +18,18 @@
*/
package github.daneren2005.dsub.domain;
+import android.util.Log;
+
import java.io.Serializable;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
/**
* @author Sindre Mehus
*/
public class Artist implements Serializable {
+ private static final String TAG = Artist.class.getSimpleName();
private String id;
private String name;
@@ -71,8 +77,69 @@ public class Artist implements Serializable {
this.closeness = closeness;
}
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Artist entry = (Artist) o;
+ return id.equals(entry.id);
+ }
+
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
@Override
public String toString() {
return name;
}
+
+ public static class ArtistComparator implements Comparator<Artist> {
+ private String[] ignoredArticles;
+
+ public ArtistComparator(String[] ignoredArticles) {
+ this.ignoredArticles = ignoredArticles;
+ }
+
+ public int compare(Artist lhsArtist, Artist rhsArtist) {
+ String lhs = lhsArtist.getName().toLowerCase();
+ String rhs = rhsArtist.getName().toLowerCase();
+
+ char lhs1 = lhs.charAt(0);
+ char rhs1 = rhs.charAt(0);
+
+ if (Character.isDigit(lhs1) && !Character.isDigit(rhs1)) {
+ return 1;
+ } else if (Character.isDigit(rhs1) && !Character.isDigit(lhs1)) {
+ return -1;
+ }
+
+ for (String article : ignoredArticles) {
+ int index = lhs.indexOf(article.toLowerCase() + " ");
+ if (index == 0) {
+ lhs = lhs.substring(article.length() + 1);
+ }
+ index = rhs.indexOf(article.toLowerCase() + " ");
+ if (index == 0) {
+ rhs = rhs.substring(article.length() + 1);
+ }
+ }
+
+ return lhs.compareTo(rhs);
+ }
+ }
+
+ public static void sort(List<Artist> artists, String[] ignoredArticles) {
+ try {
+ Collections.sort(artists, new ArtistComparator(ignoredArticles));
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to sort artists", e);
+ }
+ }
} \ No newline at end of file
diff --git a/src/github/daneren2005/dsub/domain/Indexes.java b/src/github/daneren2005/dsub/domain/Indexes.java
index 63c3a8d4..e15ccf9f 100644
--- a/src/github/daneren2005/dsub/domain/Indexes.java
+++ b/src/github/daneren2005/dsub/domain/Indexes.java
@@ -18,10 +18,16 @@
*/
package github.daneren2005.dsub.domain;
+import android.content.Context;
+import android.content.SharedPreferences;
+
import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.Util;
+
/**
* @author Sindre Mehus
*/
@@ -76,4 +82,13 @@ public class Indexes implements Serializable {
public List<MusicDirectory.Entry> getEntries() {
return entries;
}
+
+ public void sortChildren(Context context) {
+ SharedPreferences prefs = Util.getPreferences(context);
+ String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les");
+ final String[] ignoredArticles = ignoredArticlesString.split(" ");
+
+ Artist.sort(shortcuts, ignoredArticles);
+ Artist.sort(artists, ignoredArticles);
+ }
} \ No newline at end of file
diff --git a/src/github/daneren2005/dsub/domain/MusicDirectory.java b/src/github/daneren2005/dsub/domain/MusicDirectory.java
index edcbe77d..c7e00719 100644
--- a/src/github/daneren2005/dsub/domain/MusicDirectory.java
+++ b/src/github/daneren2005/dsub/domain/MusicDirectory.java
@@ -18,6 +18,7 @@
*/
package github.daneren2005.dsub.domain;
+import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.util.Log;
import java.util.ArrayList;
@@ -27,6 +28,9 @@ import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.Util;
+
/**
* @author Sindre Mehus
*/
@@ -102,6 +106,11 @@ public class MusicDirectory implements Serializable {
return children.size();
}
+ public void sortChildren(Context context, int instance) {
+ if(ServerInfo.checkServerVersion(context, "1.8", instance)) {
+ sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true));
+ }
+ }
public void sortChildren(boolean byYear) {
EntryComparator.sort(children, byYear);
}
diff --git a/src/github/daneren2005/dsub/fragments/MainFragment.java b/src/github/daneren2005/dsub/fragments/MainFragment.java
index b1320f3f..bbdc4de6 100644
--- a/src/github/daneren2005/dsub/fragments/MainFragment.java
+++ b/src/github/daneren2005/dsub/fragments/MainFragment.java
@@ -493,6 +493,11 @@ public class MainFragment extends SubsonicFragment {
count++;
}
}
+
+ // Keep recents list from growing infinitely
+ while(recents.size() > 40) {
+ recents.remove(0);
+ }
FileUtil.serialize(context, recents, recentAddedFile);
if(firstRun) {
diff --git a/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java b/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java
index 6c2ad126..a957c7f3 100644
--- a/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java
+++ b/src/github/daneren2005/dsub/fragments/NowPlayingFragment.java
@@ -31,6 +31,7 @@ import android.os.Bundle;
import android.os.Handler;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.MediaRouteButton;
+import android.util.Log;
import android.view.ContextMenu;
import android.view.Display;
import android.view.GestureDetector;
@@ -61,6 +62,8 @@ import github.daneren2005.dsub.service.DownloadFile;
import github.daneren2005.dsub.service.DownloadService;
import github.daneren2005.dsub.service.MusicService;
import github.daneren2005.dsub.service.MusicServiceFactory;
+import github.daneren2005.dsub.service.OfflineException;
+import github.daneren2005.dsub.service.ServerTooOldException;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.view.DownloadFileAdapter;
@@ -191,9 +194,13 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
public void onClick(View v) {
DownloadFile currentDownload = getDownloadService().getCurrentPlaying();
if (currentDownload != null) {
- Entry currentSong = currentDownload.getSong();
- toggleStarred(currentSong);
- starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ final Entry currentSong = currentDownload.getSong();
+ toggleStarred(currentSong, new OnStarChange() {
+ @Override
+ void starChange(boolean starred) {
+ starButton.setImageResource(currentSong.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ }
+ });
}
}
});
@@ -374,14 +381,18 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
if(downloadService == null) {
return;
}
-
- Entry entry = downloadService.getCurrentPlaying().getSong();
+
+ DownloadFile downloadFile = downloadService.getCurrentPlaying();
+ if(downloadFile == null) {
+ return;
+ }
+ Entry entry = downloadFile.getSong();
// If rating == 1, already set so unset
if(entry.getRating() == 1) {
setRating(entry, 0);
- if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if(context.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));
@@ -395,7 +406,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
rateBadButton.setImageResource(R.drawable.ic_action_rating_bad_selected);
// Make sure good rating is blank
- if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (context.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));
@@ -406,13 +417,22 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
rateGoodButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
- Entry entry = getDownloadService().getCurrentPlaying().getSong();
+ DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return;
+ }
+
+ DownloadFile downloadFile = downloadService.getCurrentPlaying();
+ if(downloadFile == null) {
+ return;
+ }
+ Entry entry = downloadFile.getSong();
// If rating == 5, already set so unset
if(entry.getRating() == 5) {
setRating(entry, 0);
- if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (context.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));
@@ -423,7 +443,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
rateGoodButton.setImageResource(R.drawable.ic_action_rating_good_selected);
// Make sure bad rating is blank
- if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ if (context.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));
@@ -768,6 +788,9 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
case R.id.menu_star:
toggleStarred(song.getSong());
return true;
+ case R.id.menu_rate:
+ setRating(song.getSong());
+ return true;
case R.id.menu_toggle_timer:
if(getDownloadService().getSleepTimer()) {
getDownloadService().stopSleepTimer();
@@ -1165,7 +1188,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
int badRating, goodRating, bookmark;
if(song.getRating() == 1) {
badRating = R.drawable.ic_action_rating_bad_selected;
- } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
badRating = R.drawable.ic_action_rating_bad_dark;
} else {
badRating = Util.getAttribute(context, R.attr.rating_bad);
@@ -1174,7 +1197,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
if(song.getRating() == 5) {
goodRating = R.drawable.ic_action_rating_good_selected;
- } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
goodRating = R.drawable.ic_action_rating_good_dark;
} else {
goodRating = Util.getAttribute(context, R.attr.rating_good);
@@ -1183,7 +1206,7 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
if(song.getBookmark() != null) {
bookmark = R.drawable.ic_menu_bookmark_selected;
- } else if(getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+ } else if(context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
bookmark = R.drawable.ic_menu_bookmark_dark;
} else {
bookmark = Util.getAttribute(context, R.attr.bookmark);
@@ -1368,14 +1391,20 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
dialog.show();
}
private void createBookmark(final DownloadFile currentDownload, final String comment) {
+ DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return;
+ }
+
+ final Entry currentSong = currentDownload.getSong();
+ final int position = downloadService.getPlayerPosition();
+ final Bookmark oldBookmark = currentSong.getBookmark();
+ currentSong.setBookmark(new Bookmark(position));
+
new SilentBackgroundTask<Void>(context) {
@Override
protected Void doInBackground() throws Throwable {
- Entry currentSong = currentDownload.getSong();
MusicService musicService = MusicServiceFactory.getMusicService(context);
- int position = getDownloadService().getPlayerPosition();
-
- currentSong.setBookmark(new Bookmark(position));
musicService.createBookmark(currentSong, position, comment, context, null);
Entry find = UpdateView.findEntry(currentSong);
@@ -1391,6 +1420,21 @@ public class NowPlayingFragment extends SubsonicFragment implements OnGestureLis
Util.toast(context, R.string.download_save_bookmark);
setControlsVisible(true);
}
+
+ @Override
+ protected void error(Throwable error) {
+ Log.w(TAG, "Failed to create bookmark", error);
+ currentSong.setBookmark(oldBookmark);
+
+ String msg;
+ if(error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.download_save_bookmark_failed) + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
}.execute();
}
diff --git a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
index 9ea84d41..4acccad2 100644
--- a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
@@ -17,9 +17,11 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.GridView;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
+import android.widget.RatingBar;
import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.MusicDirectory;
@@ -51,6 +53,8 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
+import static github.daneren2005.dsub.domain.MusicDirectory.Entry;
+
public class SelectDirectoryFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
private static final String TAG = SelectDirectoryFragment.class.getSimpleName();
@@ -60,14 +64,16 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
private Boolean licenseValid;
private boolean showHeader = true;
private EntryAdapter entryAdapter;
- private List<MusicDirectory.Entry> albums;
- private List<MusicDirectory.Entry> entries;
+ private List<Entry> albums;
+ private List<Entry> entries;
private boolean albumContext = false;
private boolean addAlbumHeader = false;
private LoadTask currentTask;
String id;
String name;
+ boolean starred;
+ int rating;
String playlistId;
String playlistName;
boolean playlistOwner;
@@ -92,8 +98,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
if(bundle != null) {
- entries = (List<MusicDirectory.Entry>) bundle.getSerializable(Constants.FRAGMENT_LIST);
- albums = (List<MusicDirectory.Entry>) bundle.getSerializable(Constants.FRAGMENT_LIST2);
+ entries = (List<Entry>) bundle.getSerializable(Constants.FRAGMENT_LIST);
+ albums = (List<Entry>) bundle.getSerializable(Constants.FRAGMENT_LIST2);
restoredInstance = true;
}
}
@@ -111,6 +117,8 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
if(args != null) {
id = args.getString(Constants.INTENT_EXTRA_NAME_ID);
name = args.getString(Constants.INTENT_EXTRA_NAME_NAME);
+ starred = args.getBoolean(Constants.INTENT_EXTRA_NAME_STARRED, false);
+ rating = args.getInt(Constants.INTENT_EXTRA_NAME_RATING, 0);
playlistId = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID);
playlistName = args.getString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME);
playlistOwner = args.getBoolean(Constants.INTENT_EXTRA_NAME_PLAYLIST_OWNER, false);
@@ -132,11 +140,11 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
lookupParent = true;
}
if(entries == null) {
- entries = (List<MusicDirectory.Entry>) args.getSerializable(Constants.FRAGMENT_LIST);
- albums = (List<MusicDirectory.Entry>) args.getSerializable(Constants.FRAGMENT_LIST2);
+ entries = (List<Entry>) args.getSerializable(Constants.FRAGMENT_LIST);
+ albums = (List<Entry>) args.getSerializable(Constants.FRAGMENT_LIST2);
if(albums == null) {
- albums = new ArrayList<MusicDirectory.Entry>();
+ albums = new ArrayList<Entry>();
}
}
}
@@ -298,15 +306,15 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
- MusicDirectory.Entry entry;
+ Entry entry;
if(view.getId() == R.id.select_album_entries) {
if(info.position == 0) {
return;
}
- entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
+ entry = (Entry) entryList.getItemAtPosition(info.position);
albumContext = false;
} else {
- entry = (MusicDirectory.Entry) albumList.getItemAtPosition(info.position);
+ entry = (Entry) albumList.getItemAtPosition(info.position);
albumContext = true;
}
@@ -352,10 +360,10 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PLAY_NOW_AFTER, false) && menuItem.getItemId() == R.id.song_menu_play_now) {
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
+ List<Entry> songs = new ArrayList<Entry>();
Iterator it = entries.listIterator(info.position - headers);
while(it.hasNext()) {
- songs.add((MusicDirectory.Entry) it.next());
+ songs.add((Entry) it.next());
}
playNow(songs);
@@ -384,12 +392,14 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position >= 0) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position);
+ Entry entry = (Entry) parent.getItemAtPosition(position);
if (entry.isDirectory()) {
SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
+ args.putBoolean(Constants.INTENT_EXTRA_NAME_STARRED, entry.isStarred());
+ args.putInt(Constants.INTENT_EXTRA_NAME_RATING, entry.getRating());
if ("newest".equals(albumListType)) {
args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true);
}
@@ -490,15 +500,15 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
} else {
root = share.getMusicDirectory();
}
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
+ List<Entry> songs = new ArrayList<Entry>();
getSongsRecursively(root, songs);
root.replaceChildren(songs);
return root;
}
- private void getSongsRecursively(MusicDirectory parent, List<MusicDirectory.Entry> songs) throws Exception {
+ private void getSongsRecursively(MusicDirectory parent, List<Entry> songs) throws Exception {
songs.addAll(parent.getChildren(false, true));
- for (MusicDirectory.Entry dir : parent.getChildren(true, false)) {
+ for (Entry dir : parent.getChildren(true, false)) {
MusicService musicService = MusicServiceFactory.getMusicService(context);
MusicDirectory musicDirectory;
@@ -715,11 +725,13 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
albumList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) parent.getItemAtPosition(position);
+ Entry entry = (Entry) parent.getItemAtPosition(position);
SubsonicFragment fragment = new SelectDirectoryFragment();
Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
+ args.putBoolean(Constants.INTENT_EXTRA_NAME_STARRED, entry.isStarred());
+ args.putInt(Constants.INTENT_EXTRA_NAME_RATING, entry.getRating());
if ("newest".equals(albumListType)) {
args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true);
}
@@ -751,7 +763,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
private void playAll(final boolean shuffle, final boolean append) {
boolean hasSubFolders = false;
for (int i = 0; i < entryList.getCount(); i++) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
+ Entry entry = (Entry) entryList.getItemAtPosition(i);
if (entry != null && entry.isDirectory()) {
hasSubFolders = true;
break;
@@ -774,7 +786,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
boolean someUnselected = false;
int count = entryList.getCount();
for (int i = 0; i < count; i++) {
- if (!entryList.isItemChecked(i) && entryList.getItemAtPosition(i) instanceof MusicDirectory.Entry) {
+ if (!entryList.isItemChecked(i) && entryList.getItemAtPosition(i) instanceof Entry) {
someUnselected = true;
break;
}
@@ -786,7 +798,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
int count = entryList.getCount();
int selectedCount = 0;
for (int i = 0; i < count; i++) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
+ Entry entry = (Entry) entryList.getItemAtPosition(i);
if (entry != null && !entry.isDirectory() && !entry.isVideo()) {
entryList.setItemChecked(i, selected);
selectedCount++;
@@ -801,12 +813,12 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
}
- private List<MusicDirectory.Entry> getSelectedSongs() {
- List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>(10);
+ private List<Entry> getSelectedSongs() {
+ List<Entry> songs = new ArrayList<Entry>(10);
int count = entryList.getCount();
for (int i = 0; i < count; i++) {
if (entryList.isItemChecked(i)) {
- MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(i);
+ Entry entry = (Entry) entryList.getItemAtPosition(i);
// Don't try to add directories or 1-starred songs
if(!entry.isDirectory() && entry.getRating() != 1) {
songs.add(entry);
@@ -835,13 +847,13 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
return;
}
- final List<MusicDirectory.Entry> songs = getSelectedSongs();
+ final List<Entry> songs = getSelectedSongs();
warnIfNetworkOrStorageUnavailable();
// Conditions for using play now button
if(!append && !save && autoplay && !playNext && !shuffle) {
// Call playNow which goes through and tries to use bookmark information
- playNow(songs);
+ playNow(songs, playlistName, playlistId);
return;
}
@@ -878,14 +890,14 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
checkLicenseAndTrialPeriod(onValid);
}
private void downloadBackground(final boolean save) {
- List<MusicDirectory.Entry> songs = getSelectedSongs();
+ List<Entry> songs = getSelectedSongs();
if(songs.isEmpty()) {
selectAll(true, false);
songs = getSelectedSongs();
}
downloadBackground(save, songs);
}
- private void downloadBackground(final boolean save, final List<MusicDirectory.Entry> songs) {
+ private void downloadBackground(final boolean save, final List<Entry> songs) {
if (getDownloadService() == null) {
return;
}
@@ -908,7 +920,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
private void delete() {
- List<MusicDirectory.Entry> songs = getSelectedSongs();
+ List<Entry> songs = getSelectedSongs();
if(songs.isEmpty()) {
selectAll(true, false);
songs = getSelectedSongs();
@@ -1009,7 +1021,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.deletePodcastEpisode(episode.getEpisodeId(), episode.getParent(), null, context);
if (getDownloadService() != null) {
- List<MusicDirectory.Entry> episodeList = new ArrayList<MusicDirectory.Entry>(1);
+ List<Entry> episodeList = new ArrayList<Entry>(1);
episodeList.add(episode);
getDownloadService().delete(episodeList);
}
@@ -1033,24 +1045,24 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
public void unstarSelected() {
- List<MusicDirectory.Entry> selected = getSelectedSongs();
+ List<Entry> selected = getSelectedSongs();
if(selected.size() == 0) {
selected = entries;
}
if(selected.size() == 0) {
return;
}
- final List<MusicDirectory.Entry> unstar = new ArrayList<MusicDirectory.Entry>();
+ final List<Entry> unstar = new ArrayList<Entry>();
unstar.addAll(selected);
new LoadingTask<Void>(context, true) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
- List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>();
- List<MusicDirectory.Entry> artists = new ArrayList<MusicDirectory.Entry>();
- List<MusicDirectory.Entry> albums = new ArrayList<MusicDirectory.Entry>();
- for(MusicDirectory.Entry entry: unstar) {
+ List<Entry> entries = new ArrayList<Entry>();
+ List<Entry> artists = new ArrayList<Entry>();
+ List<Entry> albums = new ArrayList<Entry>();
+ for(Entry entry: unstar) {
if(entry.isDirectory()) {
if(entry.isAlbum()) {
albums.add(entry);
@@ -1063,8 +1075,13 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
musicService.setStarred(entries, artists, albums, false, this, context);
- for(MusicDirectory.Entry entry: unstar) {
- setEntryStarred(entry, false);
+ for(Entry entry: unstar) {
+ new EntryInstanceUpdater(entry) {
+ @Override
+ public void update(Entry found) {
+ found.setStarred(false);
+ }
+ }.execute();
}
return null;
@@ -1074,7 +1091,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
protected void done(Void result) {
Util.toast(context, context.getResources().getString(R.string.starring_content_unstarred, Integer.toString(unstar.size())));
- for(MusicDirectory.Entry entry: unstar) {
+ for(Entry entry: unstar) {
entries.remove(entry);
}
entryAdapter.notifyDataSetChanged();
@@ -1149,7 +1166,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
builder.create().show();
}
- private View createHeader(List<MusicDirectory.Entry> entries) {
+ private View createHeader(List<Entry> entries) {
View header = entryList.findViewById(R.id.select_album_header);
boolean add = false;
if(header == null) {
@@ -1160,12 +1177,12 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
final ImageLoader imageLoader = getImageLoader();
// Try a few times to get a random cover art
- MusicDirectory.Entry coverArt = null;
+ Entry coverArt = null;
for(int i = 0; (i < 3) && (coverArt == null || coverArt.getCoverArt() == null); i++) {
coverArt = entries.get(random.nextInt(entries.size()));
}
- final MusicDirectory.Entry albumRep = coverArt;
+ final Entry albumRep = coverArt;
View coverArtView = header.findViewById(R.id.select_album_art);
coverArtView.setOnClickListener(new View.OnClickListener() {
@Override
@@ -1202,7 +1219,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
Set<String> artists = new HashSet<String>();
Set<Integer> years = new HashSet<Integer>();
Integer totalDuration = 0;
- for (MusicDirectory.Entry entry : entries) {
+ for (Entry entry : entries) {
if (!entry.isDirectory()) {
songCount++;
if (entry.getArtist() != null) {
@@ -1274,6 +1291,50 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
});
}
+
+ final Entry album = new Entry();
+ album.setId(id);
+ album.setTitle(name);
+ album.setDirectory(true);
+ album.setStarred(starred);
+ album.setRating(rating);
+
+ final ImageButton starButton = (ImageButton) header.findViewById(R.id.select_album_star);
+ if(id != null && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_STAR, true)) {
+ starButton.setImageResource(album.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ starButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ toggleStarred(album, new OnStarChange() {
+ @Override
+ void starChange(boolean starred) {
+ starButton.setImageResource(album.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ }
+ });
+ }
+ });
+ } else {
+ starButton.setVisibility(View.GONE);
+ }
+
+ View ratingBarWrapper = header.findViewById(R.id.select_album_rate_wrapper);
+ final RatingBar ratingBar = (RatingBar) header.findViewById(R.id.select_album_rate);
+ if(id != null && Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_MENU_RATING, true) && !Util.isOffline(context)) {
+ ratingBar.setRating(album.getRating());
+ ratingBarWrapper.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ setRating(album, new OnRatingChange() {
+ @Override
+ void ratingChange(int rating) {
+ ratingBar.setRating(album.getRating());
+ }
+ });
+ }
+ });
+ } else {
+ ratingBar.setVisibility(View.GONE);
+ }
}
if(add) {
diff --git a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
index fcef44fb..7ff25d2d 100644
--- a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -51,6 +51,7 @@ import github.daneren2005.dsub.activity.DownloadActivity;
import github.daneren2005.dsub.activity.SubsonicActivity;
import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.Bookmark;
import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.Playlist;
@@ -670,9 +671,15 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
dialog.show();
}
- public void toggleStarred(final Entry entry) {
+ public void toggleStarred(Entry entry) {
+ toggleStarred(entry, null);
+ }
+ public void toggleStarred(final Entry entry, final OnStarChange onStarChange) {
final boolean starred = !entry.isStarred();
entry.setStarred(starred);
+ if(onStarChange != null) {
+ onStarChange.starChange(starred);
+ }
new SilentBackgroundTask<Void>(context) {
@Override
@@ -688,7 +695,12 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
musicService.setStarred(Arrays.asList(entry), null, null, starred, null, context);
}
- setEntryStarred(entry, starred);
+ new EntryInstanceUpdater(entry) {
+ @Override
+ public void update(Entry found) {
+ found.setStarred(starred);
+ }
+ }.execute();
return null;
}
@@ -703,6 +715,9 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
protected void error(Throwable error) {
Log.w(TAG, "Failed to star", error);
entry.setStarred(!starred);
+ if(onStarChange != null) {
+ onStarChange.starChange(!starred);
+ }
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
@@ -715,25 +730,6 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
}
}.execute();
}
- protected void setEntryStarred(Entry entry, boolean starred) {
- DownloadService downloadService = DownloadService.getInstance();
- if(downloadService != null && !entry.isDirectory()) {
- List<DownloadFile> files = downloadService.getDownloads();
- for(DownloadFile file: files) {
- Entry check = file.getSong();
- if(entry.getId().equals(check.getId())) {
- check.setStarred(starred);
- downloadService.serializeQueue();
- break;
- }
- }
- }
-
- Entry find = UpdateView.findEntry(entry);
- if(find != null) {
- find.setStarred(starred);
- }
- }
public void toggleStarred(final Artist entry) {
final boolean starred = !entry.isStarred();
@@ -1388,7 +1384,10 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
return gestureScanner;
}
- protected void playBookmark(final List<Entry> songs, final Entry song) {
+ protected void playBookmark(List<Entry> songs, Entry song) {
+ playBookmark(songs, song, null, null);
+ }
+ protected void playBookmark(final List<Entry> songs, final Entry song, final String playlistName, final String playlistId) {
final Integer position = song.getBookmark().getPosition();
AlertDialog.Builder builder = new AlertDialog.Builder(context);
@@ -1403,18 +1402,22 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
.setNegativeButton(R.string.bookmark_action_start_over, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
+ final Bookmark oldBookmark = song.getBookmark();
+ song.setBookmark(null);
+
new SilentBackgroundTask<Void>(context) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.deleteBookmark(song, context, null);
- song.setBookmark(null);
return null;
}
@Override
protected void error(Throwable error) {
+ song.setBookmark(oldBookmark);
+
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
msg = getErrorMessage(error);
@@ -1434,6 +1437,9 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
}
protected void playNow(List<Entry> entries) {
+ playNow(entries, null, null);
+ }
+ protected void playNow(List<Entry> entries, String playlistName, String playlistId) {
Entry bookmark = null;
for(Entry entry: entries) {
if(entry.getBookmark() != null) {
@@ -1444,17 +1450,23 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
// If no bookmark found, just play from start
if(bookmark == null) {
- playNow(entries, 0);
+ playNow(entries, 0, playlistName, playlistId);
} else {
// If bookmark found, then give user choice to start from there or to start over
- playBookmark(entries, bookmark);
+ playBookmark(entries, bookmark, playlistName, playlistId);
}
}
protected void playNow(List<Entry> entries, int position) {
+ playNow(entries, position, null, null);
+ }
+ protected void playNow(List<Entry> entries, int position, String playlistName, String playlistId) {
Entry selected = entries.isEmpty() ? null : entries.get(0);
- playNow(entries, selected, position);
+ playNow(entries, selected, position, playlistName, playlistId);
+ }
+ protected void playNow(List<Entry> entries, Entry song, int position) {
+ playNow(entries, song, position, null, null);
}
- protected void playNow(final List<Entry> entries, final Entry song, final int position) {
+ protected void playNow(final List<Entry> entries, final Entry song, final int position, final String playlistName, final String playlistId) {
new LoadingTask<Void>(context) {
@Override
protected Void doInBackground() throws Throwable {
@@ -1465,6 +1477,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
downloadService.clear();
downloadService.download(entries, false, true, true, false, entries.indexOf(song), position);
+ downloadService.setSuggestedPlaylistName(playlistName, playlistId);
return null;
}
@@ -1480,12 +1493,21 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
Util.confirmDialog(context, R.string.bookmark_delete_title, entry.getTitle(), new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
+ final Bookmark oldBookmark = entry.getBookmark();
+ entry.setBookmark(null);
+
new LoadingTask<Void>(context, false) {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
- entry.setBookmark(null);
musicService.deleteBookmark(entry, context, null);
+
+ new EntryInstanceUpdater(entry) {
+ @Override
+ public void update(Entry found) {
+ found.setBookmark(null);
+ }
+ }.execute();
return null;
}
@@ -1501,6 +1523,8 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
@Override
protected void error(Throwable error) {
+ entry.setBookmark(oldBookmark);
+
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
msg = getErrorMessage(error);
@@ -1514,8 +1538,11 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
}
});
}
-
- protected void setRating(final Entry entry) {
+
+ protected void setRating(Entry entry) {
+ setRating(entry, null);
+ }
+ protected void setRating(final Entry entry, final OnRatingChange onRatingChange) {
View layout = context.getLayoutInflater().inflate(R.layout.rating, null);
final RatingBar ratingBar = (RatingBar) layout.findViewById(R.id.rating_bar);
ratingBar.setRating((float) entry.getRating());
@@ -1527,7 +1554,7 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
@Override
public void onClick(DialogInterface dialog, int id) {
int rating = (int) ratingBar.getRating();
- setRating(entry, rating);
+ setRating(entry, rating, onRatingChange);
}
})
.setNegativeButton(R.string.common_cancel, null);
@@ -1536,19 +1563,29 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
dialog.show();
}
- protected void setRating(final Entry entry, final int rating) {
+ protected void setRating(Entry entry, int rating) {
+ setRating(entry, rating, null);
+ }
+ protected void setRating(final Entry entry, final int rating, final OnRatingChange onRatingChange) {
+ final int oldRating = entry.getRating();
+ entry.setRating(rating);
+
+ if(onRatingChange != null) {
+ onRatingChange.ratingChange(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);
- }
+ new EntryInstanceUpdater(entry) {
+ @Override
+ public void update(Entry found) {
+ found.setRating(rating);
+ }
+ }.execute();
return null;
}
@@ -1559,6 +1596,11 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
@Override
protected void error(Throwable error) {
+ entry.setRating(oldRating);
+ if(onRatingChange != null) {
+ onRatingChange.ratingChange(oldRating);
+ }
+
String msg;
if (error instanceof OfflineException || error instanceof ServerTooOldException) {
msg = getErrorMessage(error);
@@ -1570,4 +1612,45 @@ public class SubsonicFragment extends Fragment implements SwipeRefreshLayout.OnR
}
}.execute();
}
+
+ protected abstract class EntryInstanceUpdater {
+ private Entry entry;
+
+ public EntryInstanceUpdater(Entry entry) {
+ this.entry = entry;
+ }
+
+ public abstract void update(Entry found);
+
+ public void execute() {
+ DownloadService downloadService = getDownloadService();
+ if(downloadService != null && !entry.isDirectory()) {
+ boolean serializeChanges = false;
+ List<DownloadFile> downloadFiles = downloadService.getDownloads();
+ for(DownloadFile file: downloadFiles) {
+ Entry check = file.getSong();
+ if(entry.getId().equals(check.getId())) {
+ update(entry);
+ serializeChanges = true;
+ }
+ }
+
+ if(serializeChanges) {
+ downloadService.serializeQueue();
+ }
+ }
+
+ Entry find = UpdateView.findEntry(entry);
+ if(find != null) {
+ update(find);
+ }
+ }
+ }
+
+ public abstract class OnRatingChange {
+ abstract void ratingChange(int rating);
+ }
+ public abstract class OnStarChange {
+ abstract void starChange(boolean starred);
+ }
}
diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java
index 7c0f9e09..1e553ca2 100644
--- a/src/github/daneren2005/dsub/service/CachedMusicService.java
+++ b/src/github/daneren2005/dsub/service/CachedMusicService.java
@@ -345,10 +345,110 @@ public class CachedMusicService implements MusicService {
musicService.scrobble(id, submission, context, progressListener);
}
- @Override
- public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
- return musicService.getAlbumList(type, size, offset, context, progressListener);
- }
+ @Override
+ public MusicDirectory getAlbumList(String type, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
+ MusicDirectory dir = musicService.getAlbumList(type, size, offset, context, progressListener);
+
+ // Do some serialization updates for changes to recently added
+ if("newest".equals(type) && offset == 0) {
+ String recentlyAddedFile = getCacheName(context, type);
+ ArrayList<String> recents = FileUtil.deserialize(context, recentlyAddedFile, ArrayList.class);
+ if(recents == null) {
+ recents = new ArrayList<String>();
+ }
+
+ // Add any new items
+ final int instance = musicService.getInstance(context);
+ isTagBrowsing = Util.isTagBrowsing(context, instance);
+ for(final Entry album: dir.getChildren()) {
+ if(!recents.contains(album.getId())) {
+ recents.add(album.getId());
+
+ String cacheName, parent;
+ if(isTagBrowsing) {
+ cacheName = "artist";
+ parent = album.getArtistId();
+ } else {
+ cacheName = "directory";
+ parent = album.getParent();
+ }
+
+ // Add album to artist
+ if(parent != null) {
+ new MusicDirectoryUpdater(context, cacheName, parent) {
+ private boolean changed = false;
+
+ @Override
+ public boolean checkResult(Entry check) {
+ return true;
+ }
+
+ @Override
+ public void updateResult(List<Entry> objects, Entry result) {
+ // Only add if it doesn't already exist in it!
+ if(!objects.contains(album)) {
+ objects.add(album);
+ changed = true;
+ }
+ }
+
+ @Override
+ public void save(ArrayList<Entry> objects) {
+ // Only save if actually added to artist
+ if(changed) {
+ musicDirectory.replaceChildren(objects);
+ // Reapply sort after addition
+ musicDirectory.sortChildren(context, instance);
+ FileUtil.serialize(context, musicDirectory, cacheName);
+ }
+ }
+ }.execute();
+ } else {
+ // If parent is null, then this is a root level album
+ final Artist artist = new Artist();
+ artist.setId(album.getId());
+ artist.setName(album.getTitle());
+
+ new IndexesUpdater(context, isTagBrowsing ? "artists" : "indexes") {
+ private boolean changed = false;
+
+ @Override
+ public boolean checkResult(Artist check) {
+ return true;
+ }
+
+ @Override
+ public void updateResult(List<Artist> objects, Artist result) {
+ if(!objects.contains(artist)) {
+ objects.add(artist);
+ changed = true;
+ }
+ }
+
+ @Override
+ public void save(ArrayList<Artist> objects) {
+ if(changed) {
+ indexes.setArtists(objects);
+ // Reapply sort after addition
+ indexes.sortChildren(context);
+ FileUtil.serialize(context, indexes, cacheName);
+ cachedIndexes.set(indexes);
+ }
+ }
+ }.execute();
+ }
+ }
+ }
+
+ // Keep list from growing into infinity
+ while(recents.size() > 0) {
+ recents.remove(0);
+ }
+ FileUtil.serialize(context, recents, recentlyAddedFile);
+ }
+
+ return dir;
+ }
@Override
public MusicDirectory getAlbumList(String type, String extra, int size, int offset, Context context, ProgressListener progressListener) throws Exception {
@@ -381,24 +481,7 @@ public class CachedMusicService implements MusicService {
totalList.addAll(oldList);
totalList.addAll(newList);
- new GenericEntryUpdater(context, totalList) {
- @Override
- public boolean checkResult(Entry entry, Entry check) {
- if (entry.getId().equals(check.getId())) {
- if(entry.isStarred() != check.isStarred()) {
- check.setStarred(entry.isStarred());
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public void updateResult(Entry result) {
-
- }
- }.execute();
+ new StarUpdater(context, totalList).execute();
}
FileUtil.serialize(context, dir, "starred");
@@ -491,12 +574,7 @@ public class CachedMusicService implements MusicService {
allEntries.addAll(entries);
}
- new GenericEntryUpdater(context, allEntries) {
- @Override
- public void updateResult(Entry result) {
- result.setStarred(starred);
- }
- }.execute();
+ new StarUpdater(context, allEntries).execute();
}
@Override
@@ -903,7 +981,7 @@ public class CachedMusicService implements MusicService {
}
}
private abstract class MusicDirectoryUpdater extends SerializeUpdater<Entry> {
- private MusicDirectory musicDirectory;
+ protected MusicDirectory musicDirectory;
public MusicDirectoryUpdater(Context context, String cacheName, String id) {
super(context, cacheName, id, true);
@@ -1018,7 +1096,7 @@ public class CachedMusicService implements MusicService {
@Override
public void updateResult(List<Artist> objects, Artist result) {
- GenericEntryUpdater.this.updateResult(new Entry(result));
+ // Don't try to put anything here, as the Entry update method will not be called since it's a artist!
}
}.execute();
} else {
@@ -1118,6 +1196,28 @@ public class CachedMusicService implements MusicService {
}
}
+ private class StarUpdater extends GenericEntryUpdater {
+ public StarUpdater(Context context, List<Entry> entries) {
+ super(context, entries);
+ }
+
+ @Override
+ public boolean checkResult(Entry entry, Entry check) {
+ if (entry.getId().equals(check.getId())) {
+ if(entry.isStarred() != check.isStarred()) {
+ check.setStarred(entry.isStarred());
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ @Override
+ public void updateResult(Entry result) {
+
+ }
+ };
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 43eac93d..7ff1d5eb 100644
--- a/src/github/daneren2005/dsub/service/DownloadService.java
+++ b/src/github/daneren2005/dsub/service/DownloadService.java
@@ -1880,6 +1880,20 @@ public class DownloadService extends Service {
return null;
}
+
+ @Override
+ public void error(Throwable error) {
+ Log.w(TAG, "Failed to create automatic bookmark", error);
+
+ String msg;
+ if(error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.download_save_bookmark_failed) + getErrorMessage(error);
+ }
+
+ Util.toast(context, msg, false);
+ }
}.execute();
}
}
diff --git a/src/github/daneren2005/dsub/service/MediaStoreService.java b/src/github/daneren2005/dsub/service/MediaStoreService.java
index b641a54f..0aa3269f 100644
--- a/src/github/daneren2005/dsub/service/MediaStoreService.java
+++ b/src/github/daneren2005/dsub/service/MediaStoreService.java
@@ -135,7 +135,14 @@ public class MediaStoreService {
public void deleteFromMediaStore(File file) {
ContentResolver contentResolver = context.getContentResolver();
- int n = contentResolver.delete(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ Uri uri;
+ if(FileUtil.isVideoFile(file)) {
+ uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
+ } else {
+ uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
+ }
+
+ int n = contentResolver.delete(uri,
MediaStore.MediaColumns.DATA + "=?",
new String[]{file.getAbsolutePath()});
if (n > 0) {
diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java
index 41489ee6..b62d04a1 100644
--- a/src/github/daneren2005/dsub/service/OfflineMusicService.java
+++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java
@@ -92,40 +92,9 @@ public class OfflineMusicService implements MusicService {
}
}
- SharedPreferences prefs = Util.getPreferences(context);
- String ignoredArticlesString = prefs.getString(Constants.CACHE_KEY_IGNORE, "The El La Los Las Le Les");
- final String[] ignoredArticles = ignoredArticlesString.split(" ");
-
- Collections.sort(artists, new Comparator<Artist>() {
- public int compare(Artist lhsArtist, Artist rhsArtist) {
- String lhs = lhsArtist.getName().toLowerCase();
- String rhs = rhsArtist.getName().toLowerCase();
-
- char lhs1 = lhs.charAt(0);
- char rhs1 = rhs.charAt(0);
-
- if(Character.isDigit(lhs1) && !Character.isDigit(rhs1)) {
- return 1;
- } else if(Character.isDigit(rhs1) && !Character.isDigit(lhs1)) {
- return -1;
- }
-
- for(String article: ignoredArticles) {
- int index = lhs.indexOf(article.toLowerCase() + " ");
- if(index == 0) {
- lhs = lhs.substring(article.length() + 1);
- }
- index = rhs.indexOf(article.toLowerCase() + " ");
- if(index == 0) {
- rhs = rhs.substring(article.length() + 1);
- }
- }
-
- return lhs.compareTo(rhs);
- }
- });
-
- return new Indexes(0L, Collections.<Artist>emptyList(), artists);
+ Indexes indexes = new Indexes(0L, Collections.<Artist>emptyList(), artists);
+ indexes.sortChildren(context);
+ return indexes;
}
@Override
diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java
index 3e59abe3..53b20634 100644
--- a/src/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/src/github/daneren2005/dsub/service/RESTMusicService.java
@@ -620,7 +620,12 @@ public class RESTMusicService implements MusicService {
List<String> parameterNames = Arrays.asList("id");
List<Object> parameterValues = Arrays.<Object>asList(entry.getCoverArt());
HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener);
- in = entity.getContent();
+
+ in = entity.getContent();
+ Header contentEncoding = entity.getContentEncoding();
+ if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
+ in = new GZIPInputStream(in);
+ }
// If content type is XML, an error occured. Get it.
String contentType = Util.getContentType(entity);
@@ -698,6 +703,10 @@ public class RESTMusicService implements MusicService {
String contentType = Util.getContentType(response.getEntity());
if (contentType != null && contentType.startsWith("text/xml")) {
InputStream in = response.getEntity().getContent();
+ Header contentEncoding = response.getEntity().getContentEncoding();
+ if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
+ in = new GZIPInputStream(in);
+ }
try {
new ErrorParser(context, getInstance(context)).parse(new InputStreamReader(in, Constants.UTF_8));
} finally {
@@ -1309,6 +1318,10 @@ public class RESTMusicService implements MusicService {
HttpEntity entity = getEntityForURL(context, url, null, parameterNames, parameterValues, progressListener);
in = entity.getContent();
+ Header contentEncoding = entity.getContentEncoding();
+ if (contentEncoding != null && contentEncoding.getValue().equalsIgnoreCase("gzip")) {
+ in = new GZIPInputStream(in);
+ }
// If content type is XML, an error occurred. Get it.
String contentType = Util.getContentType(entity);
@@ -1392,18 +1405,24 @@ public class RESTMusicService implements MusicService {
try{
SearchCritera critera = new SearchCritera(search, 0, 1, 1);
SearchResult result = searchNew(critera, context, progressListener);
- if(result.getSongs().size() == 1){
- Log.i(TAG, "Query '" + search + "' returned song " + result.getSongs().get(0).getTitle() + " by " + result.getSongs().get(0).getArtist() + " with id " + result.getSongs().get(0).getId());
- setStarred(Arrays.asList(result.getSongs().get(0)), null, null, starred, progressListener, context);
- } else if(result.getAlbums().size() == 1){
- Log.i(TAG, "Query '" + search + "' returned song " + result.getAlbums().get(0).getTitle() + " by " + result.getAlbums().get(0).getArtist() + " with id " + result.getAlbums().get(0).getId());
- setStarred(Arrays.asList(result.getAlbums().get(0)), null, null, starred, progressListener, context);
+ if(result.getSongs().size() == 1) {
+ MusicDirectory.Entry song = result.getSongs().get(0);
+ Log.i(TAG, "Query '" + search + "' returned song " + song.getTitle() + " by " + song.getArtist() + " with id " + song.getId());
+ setStarred(Arrays.asList(song), null, null, starred, progressListener, context);
+ } else if(result.getAlbums().size() == 1) {
+ MusicDirectory.Entry album = result.getAlbums().get(0);
+ Log.i(TAG, "Query '" + search + "' returned album " + album.getTitle() + " by " + album.getArtist() + " with id " + album.getId());
+ if(Util.isTagBrowsing(context, getInstance(context))) {
+ setStarred(null, null, Arrays.asList(album), starred, progressListener, context);
+ } else {
+ setStarred(Arrays.asList(album), null, null, starred, progressListener, context);
+ }
}
- else{
+ else {
throw new Exception("Song not found on server");
}
}
- catch(Exception e){
+ catch(Exception e) {
Log.e(TAG, e.toString());
retry++;
}
@@ -1550,7 +1569,9 @@ public class RESTMusicService implements MusicService {
request.addHeader(header);
}
}
- request.addHeader("Accept-Encoding", "gzip");
+ if(url.indexOf("getCoverArt") == -1 && url.indexOf("stream") == -1 && url.indexOf("getAvatar") == -1) {
+ request.addHeader("Accept-Encoding", "gzip");
+ }
// Set credentials to get through apache proxies that require authentication.
int instance = prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
diff --git a/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java b/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java
index c5d5ec51..9542324e 100644
--- a/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java
+++ b/src/github/daneren2005/dsub/service/parser/MusicDirectoryEntryParser.java
@@ -71,7 +71,7 @@ public class MusicDirectoryEntryParser extends AbstractParser {
String type = get("type");
if("podcast".equals(type)) {
entry.setType(MusicDirectory.Entry.TYPE_PODCAST);
- } else if("audiobook".equals(type)) {
+ } else if("audiobook".equals(type) || (entry.getGenre() != null && "audiobook".equals(entry.getGenre().toLowerCase()))) {
entry.setType(MusicDirectory.Entry.TYPE_AUDIO_BOOK);
}
} else if(!"".equals(artist)) {
diff --git a/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java b/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java
index 05e8b274..a5500505 100644
--- a/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java
+++ b/src/github/daneren2005/dsub/service/parser/MusicDirectoryParser.java
@@ -96,9 +96,7 @@ public class MusicDirectoryParser extends MusicDirectoryEntryParser {
validate();
// Only apply sorting on server version 4.7 and greater, where disc is supported
- if(ServerInfo.checkServerVersion(context, "1.8.0", instance)) {
- dir.sortChildren(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_CUSTOM_SORT_ENABLED, true));
- }
+ dir.sortChildren(context, instance);
return dir;
}
diff --git a/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java b/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java
index 6dfbbbe4..a0727201 100644
--- a/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java
+++ b/src/github/daneren2005/dsub/service/sync/MostRecentSyncAdapter.java
@@ -83,6 +83,10 @@ public class MostRecentSyncAdapter extends SubsonicSyncAdapter {
}
if(updated.size() > 0) {
+ while(syncedList.size() > 40) {
+ syncedList.remove(0);
+ }
+
FileUtil.serialize(context, syncedList, SyncUtil.getMostRecentSyncFile(context, instance));
// If there is a new album on the active server, chances are artists need to be refreshed
diff --git a/src/github/daneren2005/dsub/util/Constants.java b/src/github/daneren2005/dsub/util/Constants.java
index ac21df4c..f22fd3f0 100644
--- a/src/github/daneren2005/dsub/util/Constants.java
+++ b/src/github/daneren2005/dsub/util/Constants.java
@@ -37,6 +37,8 @@ public final class Constants {
// Names for intent extras.
public static final String INTENT_EXTRA_NAME_ID = "subsonic.id";
public static final String INTENT_EXTRA_NAME_NAME = "subsonic.name";
+ public static final String INTENT_EXTRA_NAME_STARRED = "subsonic.starred";
+ public static final String INTENT_EXTRA_NAME_RATING = "subsonic.rating";
public static final String INTENT_EXTRA_NAME_CHILD_ID = "subsonic.child.id";
public static final String INTENT_EXTRA_NAME_ARTIST = "subsonic.artist";
public static final String INTENT_EXTRA_NAME_TITLE = "subsonic.title";
@@ -73,8 +75,6 @@ public final class Constants {
public static final String PREFERENCES_KEY_SERVER_URL = "serverUrl";
public static final String PREFERENCES_KEY_SERVER_INTERNAL_URL = "serverInternalUrl";
public static final String PREFERENCES_KEY_SERVER_LOCAL_NETWORK_SSID = "serverLocalNetworkSSID";
- public static final String PREFERENCES_KEY_SERVER_VERSION = "serverVersion";
- public static final String PREFERENCES_KEY_SERVER_TYPE = "serverType";
public static final String PREFERENCES_KEY_TEST_CONNECTION = "serverTestConnection";
public static final String PREFERENCES_KEY_OPEN_BROWSER = "openBrowser";
public static final String PREFERENCES_KEY_MUSIC_FOLDER_ID = "musicFolderId";
diff --git a/src/github/daneren2005/dsub/util/FileUtil.java b/src/github/daneren2005/dsub/util/FileUtil.java
index 5aafe213..60fc6031 100644
--- a/src/github/daneren2005/dsub/util/FileUtil.java
+++ b/src/github/daneren2005/dsub/util/FileUtil.java
@@ -30,6 +30,7 @@ import java.io.RandomAccessFile;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Date;
+import java.util.HashMap;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.Iterator;
@@ -74,6 +75,7 @@ public class FileUtil {
private static final List<String> PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u");
private static File DEFAULT_MUSIC_DIR;
private static final Kryo kryo = new Kryo();
+ private static HashMap<String, MusicDirectory.Entry> entryLookup;
static {
kryo.register(MusicDirectory.Entry.class);
@@ -255,7 +257,13 @@ public class FileUtil {
}
}
public static Bitmap getScaledBitmap(Bitmap bitmap, int size) {
- return Bitmap.createScaledBitmap(bitmap, size, Util.getScaledHeight(bitmap, size), true);
+ // Don't waste time scaling if the difference is minor
+ // Large album arts still need to be scaled since displayed as is on now playing!
+ if(size < 400 && bitmap.getWidth() < (size * 1.1)) {
+ return bitmap;
+ } else {
+ return Bitmap.createScaledBitmap(bitmap, size, Util.getScaledHeight(bitmap, size), true);
+ }
}
public static File getAlbumArtDirectory(Context context) {
@@ -280,10 +288,13 @@ public class FileUtil {
File f = new File(fileSystemSafeDir(entry.getPath()));
dir = new File(getMusicDirectory(context).getPath() + "/" + (entry.isDirectory() ? f.getPath() : f.getParent()));
} else {
- MusicDirectory.Entry firstSong = lookupChild(context, entry, false);
- if(firstSong != null) {
- File songFile = FileUtil.getSongFile(context, firstSong);
- dir = songFile.getParentFile();
+ MusicDirectory.Entry firstSong;
+ if(!Util.isOffline(context)) {
+ firstSong = lookupChild(context, entry, false);
+ if(firstSong != null) {
+ File songFile = FileUtil.getSongFile(context, firstSong);
+ dir = songFile.getParentFile();
+ }
}
if(dir == null) {
@@ -299,6 +310,23 @@ public class FileUtil {
}
public static MusicDirectory.Entry lookupChild(Context context, MusicDirectory.Entry entry, boolean allowDir) {
+ // Initialize lookupMap if first time called
+ String lookupName = Util.getCacheName(context, "entryLookup");
+ if(entryLookup == null) {
+ entryLookup = deserialize(context, lookupName, HashMap.class);
+
+ // Create it if
+ if(entryLookup == null) {
+ entryLookup = new HashMap<String, MusicDirectory.Entry>();
+ }
+ }
+
+ // Check if this lookup has already been done before
+ MusicDirectory.Entry child = entryLookup.get(entry.getId());
+ if(child != null) {
+ return child;
+ }
+
// Do a special lookup since 4.7+ doesn't match artist/album to entry.getPath
String s = Util.getRestUrl(context, null, false) + entry.getId();
String cacheName = (Util.isTagBrowsing(context) ? "album-" : "directory-") + s.hashCode() + ".ser";
@@ -307,7 +335,10 @@ public class FileUtil {
if(entryDir != null) {
List<MusicDirectory.Entry> songs = entryDir.getChildren(allowDir, true);
if(songs.size() > 0) {
- return songs.get(0);
+ child = songs.get(0);
+ entryLookup.put(entry.getId(), child);
+ serialize(context, entryLookup, lookupName);
+ return child;
}
}
diff --git a/src/github/daneren2005/dsub/util/ImageLoader.java b/src/github/daneren2005/dsub/util/ImageLoader.java
index f62741ec..1b91b778 100644
--- a/src/github/daneren2005/dsub/util/ImageLoader.java
+++ b/src/github/daneren2005/dsub/util/ImageLoader.java
@@ -124,7 +124,7 @@ public class ImageLoader {
createLargeUnknownImage(view.getContext());
}
- if(entry != null && entry.getCoverArt() == null && entry.isDirectory()) {
+ if(entry != null && entry.getCoverArt() == null && entry.isDirectory() && !Util.isOffline(context)) {
// Try to lookup child cover art
MusicDirectory.Entry firstChild = FileUtil.lookupChild(context, entry, true);
if(firstChild != null) {
diff --git a/src/github/daneren2005/dsub/view/AlbumCell.java b/src/github/daneren2005/dsub/view/AlbumCell.java
index 522834d1..d6a18205 100644
--- a/src/github/daneren2005/dsub/view/AlbumCell.java
+++ b/src/github/daneren2005/dsub/view/AlbumCell.java
@@ -20,6 +20,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.RatingBar;
import android.widget.TextView;
import java.io.File;
@@ -50,6 +51,8 @@ public class AlbumCell extends UpdateView {
titleView = (TextView) findViewById(R.id.album_title);
artistView = (TextView) findViewById(R.id.album_artist);
+ ratingBar = (RatingBar) findViewById(R.id.album_rating);
+ ratingBar.setFocusable(false);
starButton = (ImageButton) findViewById(R.id.album_star);
starButton.setFocusable(false);
moreButton = (ImageView) findViewById(R.id.album_more);
@@ -92,5 +95,10 @@ public class AlbumCell extends UpdateView {
exists = file.exists();
isStarred = album.isStarred();
+ isRated = album.getRating();
+ }
+
+ public MusicDirectory.Entry getEntry() {
+ return album;
}
}
diff --git a/src/github/daneren2005/dsub/view/AlbumView.java b/src/github/daneren2005/dsub/view/AlbumView.java
index e28eeadd..7785a8af 100644
--- a/src/github/daneren2005/dsub/view/AlbumView.java
+++ b/src/github/daneren2005/dsub/view/AlbumView.java
@@ -24,6 +24,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.RatingBar;
import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.MusicDirectory;
@@ -57,6 +58,7 @@ public class AlbumView extends UpdateView {
titleView = (TextView) findViewById(R.id.album_title);
artistView = (TextView) findViewById(R.id.album_artist);
coverArtView = findViewById(R.id.album_coverart);
+ ratingBar = (RatingBar) findViewById(R.id.album_rating);
starButton = (ImageButton) findViewById(R.id.album_star);
starButton.setFocusable(false);
@@ -92,5 +94,10 @@ public class AlbumView extends UpdateView {
exists = file.exists();
isStarred = album.isStarred();
+ isRated = album.getRating();
+ }
+
+ public MusicDirectory.Entry getEntry() {
+ return album;
}
}
diff --git a/src/github/daneren2005/dsub/view/DownloadFileAdapter.java b/src/github/daneren2005/dsub/view/DownloadFileAdapter.java
index f9676dbd..f535acef 100644
--- a/src/github/daneren2005/dsub/view/DownloadFileAdapter.java
+++ b/src/github/daneren2005/dsub/view/DownloadFileAdapter.java
@@ -42,6 +42,7 @@ public class DownloadFileAdapter extends ArrayAdapter<DownloadFile> {
}
DownloadFile downloadFile = getItem(position);
view.setObject(downloadFile.getSong(), false);
+ view.setDownloadFile(downloadFile);
return view;
}
}
diff --git a/src/github/daneren2005/dsub/view/SongView.java b/src/github/daneren2005/dsub/view/SongView.java
index 8d986090..f795cbce 100644
--- a/src/github/daneren2005/dsub/view/SongView.java
+++ b/src/github/daneren2005/dsub/view/SongView.java
@@ -55,6 +55,7 @@ public class SongView extends UpdateView implements Checkable {
private DownloadService downloadService;
private long revision = -1;
private DownloadFile downloadFile;
+ private boolean dontChangeDownloadFile = false;
private boolean playing = false;
private boolean rightImage = false;
@@ -66,8 +67,6 @@ public class SongView extends UpdateView implements Checkable {
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);
@@ -79,6 +78,7 @@ public class SongView extends UpdateView implements Checkable {
durationTextView = (TextView) findViewById(R.id.song_duration);
statusTextView = (TextView) findViewById(R.id.song_status);
statusImageView = (ImageView) findViewById(R.id.song_status_icon);
+ ratingBar = (RatingBar) findViewById(R.id.song_rating);
starButton = (ImageButton) findViewById(R.id.song_star);
starButton.setFocusable(false);
bookmarkButton = (ImageButton) findViewById(R.id.song_bookmark);
@@ -148,11 +148,18 @@ public class SongView extends UpdateView implements Checkable {
checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE);
this.setBackgroundColor(0x00000000);
+ ratingBar.setVisibility(View.GONE);
rating = 0;
revision = -1;
loaded = false;
- }
+ dontChangeDownloadFile = false;
+ }
+
+ public void setDownloadFile(DownloadFile downloadFile) {
+ this.downloadFile = downloadFile;
+ dontChangeDownloadFile = true;
+ }
@Override
protected void updateBackground() {
@@ -164,7 +171,7 @@ public class SongView extends UpdateView implements Checkable {
}
long newRevision = downloadService.getDownloadListUpdateRevision();
- if(revision != newRevision || downloadFile == null) {
+ if((revision != newRevision && dontChangeDownloadFile == false) || downloadFile == null) {
downloadFile = downloadService.forSong(song);
revision = newRevision;
}
@@ -259,15 +266,24 @@ public class SongView extends UpdateView implements Checkable {
}
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) {
+ if(isRated > 1) {
+ if(rating <= 1) {
+ ratingBar.setVisibility(View.VISIBLE);
+ }
+
+ ratingBar.setNumStars(isRated);
+ ratingBar.setRating(isRated);
+ } else if(isRated <= 1) {
+ if(rating > 1) {
+ ratingBar.setVisibility(View.GONE);
+ }
+ }
+
+ // Still highlight red if a 1-star
+ if(isRated == 1) {
this.setBackgroundColor(Color.RED);
- // Use darker colors the lower the rating goes
- this.getBackground().setAlpha(10 * (3 - isRated));
- } else {
+ this.getBackground().setAlpha(20);
+ } else if(rating == 1) {
this.setBackgroundColor(0x00000000);
}
diff --git a/src/github/daneren2005/dsub/view/UpdateView.java b/src/github/daneren2005/dsub/view/UpdateView.java
index 5f34a765..c491fc6d 100644
--- a/src/github/daneren2005/dsub/view/UpdateView.java
+++ b/src/github/daneren2005/dsub/view/UpdateView.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.os.Handler;
import android.os.Looper;
import android.util.Log;
@@ -29,6 +30,8 @@ import android.widget.AbsListView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
+import android.widget.RatingBar;
+
import java.util.ArrayList;
import java.util.List;
import java.util.WeakHashMap;
@@ -48,6 +51,7 @@ public class UpdateView extends LinearLayout {
private static int activeActivities = 0;
protected Context context;
+ protected RatingBar ratingBar;
protected ImageButton starButton;
protected ImageView moreButton;
@@ -56,6 +60,8 @@ public class UpdateView extends LinearLayout {
protected boolean shaded = false;
protected boolean starred = false;
protected boolean isStarred = false;
+ protected int isRated = 0;
+ protected int rating = 0;
protected SilentBackgroundTask<Void> imageTask = null;
protected final boolean autoUpdate;
@@ -215,11 +221,17 @@ public class UpdateView extends LinearLayout {
public static MusicDirectory.Entry findEntry(MusicDirectory.Entry entry) {
for(UpdateView view: INSTANCES.keySet()) {
+ MusicDirectory.Entry check = null;
if(view instanceof SongView) {
- MusicDirectory.Entry check = ((SongView) view).getEntry();
- if(check != null && entry != check && check.getId().equals(entry.getId())) {
- return check;
- }
+ check = ((SongView) view).getEntry();
+ } else if(view instanceof AlbumCell) {
+ check = ((AlbumCell) view).getEntry();
+ } else if(view instanceof AlbumView) {
+ check = ((AlbumView) view).getEntry();
+ }
+
+ if(check != null && entry != check && check.getId().equals(entry.getId())) {
+ return check;
}
}
@@ -259,5 +271,16 @@ public class UpdateView extends LinearLayout {
}
}
}
+
+ if(ratingBar != null && isRated != rating) {
+ if(isRated > 0 && rating == 0) {
+ ratingBar.setVisibility(View.VISIBLE);
+ } else if(isRated == 0 && rating > 0) {
+ ratingBar.setVisibility(View.GONE);
+ }
+
+ ratingBar.setRating(isRated);
+ rating = isRated;
+ }
}
}