aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Jackson <daneren2005@gmail.com>2013-11-14 23:47:19 -0800
committerScott Jackson <daneren2005@gmail.com>2013-11-14 23:47:19 -0800
commit2ad1a9ace84137b18fd6f35174920ea659dde0a3 (patch)
tree25cc337557bf119c5a82052a8312800fea6fe7be
parentedaa382b8a37954fd10f47c50066ae718bd21428 (diff)
parentbbf1ec51c18a5deddef714e948f3702b3d11f97c (diff)
downloaddsub-2ad1a9ace84137b18fd6f35174920ea659dde0a3.tar.gz
dsub-2ad1a9ace84137b18fd6f35174920ea659dde0a3.tar.bz2
dsub-2ad1a9ace84137b18fd6f35174920ea659dde0a3.zip
Merge changes
-rw-r--r--.gitignore1
-rw-r--r--AndroidManifest.xml40
-rw-r--r--DSub.pngbin75587 -> 1052037 bytes
-rw-r--r--README9
-rw-r--r--Subsonic.iml6
-rw-r--r--assets/fonts/Storopia.ttfbin89888 -> 0 bytes
-rw-r--r--assets/html/en/index.html98
-rw-r--r--assets/html/fr/index.html100
-rw-r--r--assets/html/img/paypal.gifbin2127 -> 0 bytes
-rw-r--r--assets/html/img/subsonic.pngbin2084 -> 0 bytes
-rw-r--r--assets/html/ru/index.html98
-rw-r--r--assets/html/style.css11
-rw-r--r--libs/android-support-v4.jarbin556198 -> 621451 bytes
-rw-r--r--libs/android-support-v7-appcompat.jarbin339845 -> 343731 bytes
-rw-r--r--libs/kryo-2.21-all.jarbin0 -> 236628 bytes
-rw-r--r--project.properties6
-rw-r--r--releases/DSub 4.0.1.apkbin1268342 -> 0 bytes
-rw-r--r--releases/DSub 4.0.2.apkbin1269700 -> 0 bytes
-rw-r--r--releases/DSub 4.0.3.apkbin1274029 -> 0 bytes
-rw-r--r--releases/DSub 4.0.4.apkbin1289208 -> 0 bytes
-rw-r--r--releases/DSub 4.0.5.apkbin1288993 -> 0 bytes
-rw-r--r--releases/DSub 4.0.6.apkbin1297293 -> 0 bytes
-rw-r--r--releases/DSub 4.0.7.apkbin1310165 -> 0 bytes
-rw-r--r--releases/DSub 4.1.0.apkbin1315422 -> 0 bytes
-rw-r--r--releases/DSub 4.1.1.apkbin1315520 -> 0 bytes
-rw-r--r--releases/DSub 4.1.2.apkbin1266662 -> 0 bytes
-rw-r--r--res/drawable-hdpi-v11/notification_close.pngbin0 -> 384 bytes
-rw-r--r--res/drawable-hdpi-v11/notification_next.pngbin0 -> 525 bytes
-rw-r--r--res/drawable-hdpi-v11/notification_pause.pngbin0 -> 210 bytes
-rw-r--r--res/drawable-hdpi-v11/notification_play.pngbin0 -> 385 bytes
-rw-r--r--res/drawable-hdpi-v11/notification_previous.pngbin0 -> 541 bytes
-rw-r--r--res/drawable-hdpi-v11/stat_notify_download.pngbin0 -> 300 bytes
-rw-r--r--res/drawable-hdpi-v11/stat_notify_playing.pngbin0 -> 385 bytes
-rw-r--r--res/drawable-hdpi/action_browse.pngbin1673 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_compass.pngbin2069 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_exit.pngbin923 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_help.pngbin1197 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_moreoverflow.pngbin126 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_offline.pngbin1558 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_play_all.pngbin1359 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_refresh.pngbin1820 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_remove_all.pngbin1201 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_save.pngbin1044 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_screen_on_off.pngbin1525 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_search.pngbin1592 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_select.pngbin1158 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_settings.pngbin1649 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_share.pngbin1823 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_shuffle.pngbin1386 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_toggle_list.pngbin552 -> 0 bytes
-rw-r--r--res/drawable-hdpi/action_toggle_list_dark.pngbin0 -> 290 bytes
-rw-r--r--res/drawable-hdpi/action_toggle_list_light.pngbin0 -> 309 bytes
-rw-r--r--res/drawable-hdpi/actionbar_background.9.pngbin234 -> 0 bytes
-rw-r--r--res/drawable-hdpi/album_art_background.pngbin9287 -> 0 bytes
-rw-r--r--res/drawable-hdpi/download_cached.pngbin0 -> 1172 bytes
-rw-r--r--res/drawable-hdpi/download_none_dark.pngbin0 -> 342 bytes
-rw-r--r--res/drawable-hdpi/download_none_light.pngbin0 -> 374 bytes
-rw-r--r--res/drawable-hdpi/download_pinned.pngbin0 -> 1112 bytes
-rw-r--r--res/drawable-hdpi/downloading.pngbin457 -> 0 bytes
-rw-r--r--res/drawable-hdpi/downloading_dark.pngbin0 -> 618 bytes
-rw-r--r--res/drawable-hdpi/downloading_light.pngbin0 -> 743 bytes
-rw-r--r--res/drawable-hdpi/ic_action_volume_dark.pngbin0 -> 1365 bytes
-rw-r--r--res/drawable-hdpi/ic_action_volume_light.pngbin0 -> 1550 bytes
-rw-r--r--res/drawable-hdpi/ic_drawer.pngbin0 -> 2829 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_bookmark_dark.pngbin0 -> 1087 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_bookmark_light.pngbin0 -> 1292 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_chat_dark.pngbin1401 -> 421 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_chat_light.pngbin1374 -> 453 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_chat_send_dark.pngbin1668 -> 602 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_chat_send_light.pngbin1691 -> 677 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_exit.pngbin5689 -> 0 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_help.pngbin5250 -> 0 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_library_dark.pngbin0 -> 617 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_library_light.pngbin0 -> 696 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_playlist_dark.pngbin0 -> 457 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_playlist_light.pngbin0 -> 496 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_podcast_dark.pngbin0 -> 1167 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_podcast_light.pngbin0 -> 1410 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_refresh_dark.pngbin0 -> 1139 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_refresh_light.pngbin0 -> 1351 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_remove_dark.pngbin0 -> 898 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_remove_light.pngbin0 -> 1090 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_save_dark.pngbin0 -> 553 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_save_light.pngbin0 -> 631 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_search_dark.pngbin0 -> 1071 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_search_light.pngbin0 -> 1271 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_settings.pngbin5455 -> 0 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_settings_dark.pngbin0 -> 557 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_settings_light.pngbin0 -> 586 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_shuffle.pngbin1386 -> 0 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_shuffle_dark.pngbin0 -> 985 bytes
-rw-r--r--res/drawable-hdpi/ic_menu_shuffle_light.pngbin0 -> 1132 bytes
-rw-r--r--res/drawable-hdpi/launch.pngbin6155 -> 23597 bytes
-rw-r--r--res/drawable-hdpi/list_item_more.9.pngbin5838 -> 0 bytes
-rw-r--r--res/drawable-hdpi/list_item_more_saved.9.pngbin5919 -> 0 bytes
-rw-r--r--res/drawable-hdpi/list_item_more_shaded.9.pngbin5994 -> 0 bytes
-rw-r--r--res/drawable-hdpi/main_offline.pngbin1405 -> 0 bytes
-rw-r--r--res/drawable-hdpi/main_offline_dark.pngbin0 -> 631 bytes
-rw-r--r--res/drawable-hdpi/main_offline_light.pngbin564 -> 746 bytes
-rw-r--r--res/drawable-hdpi/main_select_server.pngbin1920 -> 0 bytes
-rw-r--r--res/drawable-hdpi/main_select_server_dark.pngbin0 -> 720 bytes
-rw-r--r--res/drawable-hdpi/main_select_server_light.pngbin0 -> 799 bytes
-rw-r--r--res/drawable-hdpi/media_backward.pngbin939 -> 0 bytes
-rw-r--r--res/drawable-hdpi/media_backward_dark.pngbin0 -> 579 bytes
-rw-r--r--res/drawable-hdpi/media_backward_light.pngbin1106 -> 627 bytes
-rw-r--r--res/drawable-hdpi/media_forward.pngbin913 -> 0 bytes
-rw-r--r--res/drawable-hdpi/media_forward_dark.pngbin0 -> 559 bytes
-rw-r--r--res/drawable-hdpi/media_forward_light.pngbin1128 -> 631 bytes
-rw-r--r--res/drawable-hdpi/media_pause.pngbin168 -> 0 bytes
-rw-r--r--res/drawable-hdpi/media_pause_dark.pngbin0 -> 276 bytes
-rw-r--r--res/drawable-hdpi/media_pause_light.pngbin443 -> 301 bytes
-rw-r--r--res/drawable-hdpi/media_start.pngbin742 -> 0 bytes
-rw-r--r--res/drawable-hdpi/media_start_dark.pngbin0 -> 449 bytes
-rw-r--r--res/drawable-hdpi/media_start_light.pngbin1121 -> 511 bytes
-rw-r--r--res/drawable-hdpi/media_stop.pngbin162 -> 0 bytes
-rw-r--r--res/drawable-hdpi/media_stop_dark.pngbin0 -> 265 bytes
-rw-r--r--res/drawable-hdpi/media_stop_light.pngbin301 -> 274 bytes
-rw-r--r--res/drawable-hdpi/menu_browse.pngbin1673 -> 0 bytes
-rw-r--r--res/drawable-hdpi/menu_home.pngbin1814 -> 0 bytes
-rw-r--r--res/drawable-hdpi/menu_now_playing.pngbin1359 -> 0 bytes
-rw-r--r--res/drawable-hdpi/menu_playlists.pngbin1158 -> 0 bytes
-rw-r--r--res/drawable-hdpi/notification_close.pngbin0 -> 501 bytes
-rw-r--r--res/drawable-hdpi/notification_next.pngbin941 -> 651 bytes
-rw-r--r--res/drawable-hdpi/notification_pause.pngbin233 -> 459 bytes
-rw-r--r--res/drawable-hdpi/notification_play.pngbin807 -> 599 bytes
-rw-r--r--res/drawable-hdpi/notification_prev.pngbin957 -> 0 bytes
-rw-r--r--res/drawable-hdpi/notification_previous.pngbin0 -> 633 bytes
-rw-r--r--res/drawable-hdpi/notification_stop.pngbin338 -> 0 bytes
-rw-r--r--res/drawable-hdpi/now_playing.pngbin0 -> 599 bytes
-rw-r--r--res/drawable-hdpi/refresh.pngbin3585 -> 0 bytes
-rw-r--r--res/drawable-hdpi/search.pngbin2940 -> 0 bytes
-rw-r--r--res/drawable-hdpi/stat_notify_download.pngbin0 -> 350 bytes
-rw-r--r--res/drawable-hdpi/stat_notify_playing.pngbin716 -> 599 bytes
-rw-r--r--res/drawable-hdpi/volume.pngbin1659 -> 0 bytes
-rw-r--r--res/drawable-mdpi-v11/notification_close.pngbin0 -> 241 bytes
-rw-r--r--res/drawable-mdpi-v11/notification_next.pngbin0 -> 341 bytes
-rw-r--r--res/drawable-mdpi-v11/notification_pause.pngbin0 -> 156 bytes
-rw-r--r--res/drawable-mdpi-v11/notification_play.pngbin0 -> 280 bytes
-rw-r--r--res/drawable-mdpi-v11/notification_previous.pngbin0 -> 355 bytes
-rw-r--r--res/drawable-mdpi-v11/stat_notify_download.pngbin0 -> 234 bytes
-rw-r--r--res/drawable-mdpi-v11/stat_notify_playing.pngbin0 -> 280 bytes
-rw-r--r--res/drawable-mdpi/action_toggle_list_dark.pngbin0 -> 204 bytes
-rw-r--r--res/drawable-mdpi/action_toggle_list_light.pngbin0 -> 225 bytes
-rw-r--r--res/drawable-mdpi/download_cached.pngbin0 -> 824 bytes
-rw-r--r--res/drawable-mdpi/download_none_dark.pngbin0 -> 216 bytes
-rw-r--r--res/drawable-mdpi/download_none_light.pngbin0 -> 239 bytes
-rw-r--r--res/drawable-mdpi/download_pinned.pngbin0 -> 841 bytes
-rw-r--r--res/drawable-mdpi/downloading_dark.pngbin0 -> 447 bytes
-rw-r--r--res/drawable-mdpi/downloading_light.pngbin0 -> 527 bytes
-rw-r--r--res/drawable-mdpi/ic_action_volume_dark.pngbin0 -> 820 bytes
-rw-r--r--res/drawable-mdpi/ic_action_volume_light.pngbin0 -> 974 bytes
-rw-r--r--res/drawable-mdpi/ic_drawer.pngbin0 -> 2820 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_bookmark_dark.pngbin0 -> 658 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_bookmark_light.pngbin0 -> 782 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_chat_dark.pngbin0 -> 277 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_chat_light.pngbin0 -> 311 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_chat_send_dark.pngbin0 -> 366 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_chat_send_light.pngbin0 -> 394 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_library_dark.pngbin0 -> 420 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_library_light.pngbin0 -> 492 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_playlist_dark.pngbin0 -> 315 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_playlist_light.pngbin0 -> 364 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_podcast_dark.pngbin0 -> 750 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_podcast_light.pngbin0 -> 862 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_refresh_dark.pngbin0 -> 748 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_refresh_light.pngbin0 -> 914 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_remove_dark.pngbin0 -> 576 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_remove_light.pngbin0 -> 689 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_save_dark.pngbin0 -> 406 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_save_light.pngbin0 -> 481 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_search_dark.pngbin0 -> 655 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_search_light.pngbin0 -> 794 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_settings_dark.pngbin0 -> 365 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_settings_light.pngbin0 -> 365 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_shuffle_dark.pngbin0 -> 653 bytes
-rw-r--r--res/drawable-mdpi/ic_menu_shuffle_light.pngbin0 -> 725 bytes
-rw-r--r--res/drawable-mdpi/launch.pngbin3527 -> 12053 bytes
-rw-r--r--res/drawable-mdpi/main_offline_dark.pngbin0 -> 408 bytes
-rw-r--r--res/drawable-mdpi/main_offline_light.pngbin0 -> 456 bytes
-rw-r--r--res/drawable-mdpi/main_select_server_dark.pngbin0 -> 434 bytes
-rw-r--r--res/drawable-mdpi/main_select_server_light.pngbin0 -> 502 bytes
-rw-r--r--res/drawable-mdpi/media_backward_dark.pngbin0 -> 378 bytes
-rw-r--r--res/drawable-mdpi/media_backward_light.pngbin0 -> 412 bytes
-rw-r--r--res/drawable-mdpi/media_forward_dark.pngbin0 -> 372 bytes
-rw-r--r--res/drawable-mdpi/media_forward_light.pngbin0 -> 417 bytes
-rw-r--r--res/drawable-mdpi/media_pause_dark.pngbin0 -> 169 bytes
-rw-r--r--res/drawable-mdpi/media_pause_light.pngbin0 -> 192 bytes
-rw-r--r--res/drawable-mdpi/media_start_dark.pngbin0 -> 301 bytes
-rw-r--r--res/drawable-mdpi/media_start_light.pngbin0 -> 335 bytes
-rw-r--r--res/drawable-mdpi/media_stop_dark.pngbin0 -> 154 bytes
-rw-r--r--res/drawable-mdpi/media_stop_light.pngbin0 -> 162 bytes
-rw-r--r--res/drawable-mdpi/notification_close.pngbin0 -> 337 bytes
-rw-r--r--res/drawable-mdpi/notification_next.pngbin0 -> 460 bytes
-rw-r--r--res/drawable-mdpi/notification_pause.pngbin0 -> 361 bytes
-rw-r--r--res/drawable-mdpi/notification_play.pngbin0 -> 417 bytes
-rw-r--r--res/drawable-mdpi/notification_previous.pngbin0 -> 476 bytes
-rw-r--r--res/drawable-mdpi/now_playing.pngbin0 -> 417 bytes
-rw-r--r--res/drawable-mdpi/stat_notify_download.pngbin0 -> 272 bytes
-rw-r--r--res/drawable-mdpi/stat_notify_playing.pngbin0 -> 417 bytes
-rw-r--r--res/drawable-xhdpi-v11/notification_close.pngbin0 -> 491 bytes
-rw-r--r--res/drawable-xhdpi-v11/notification_next.pngbin0 -> 731 bytes
-rw-r--r--res/drawable-xhdpi-v11/notification_pause.pngbin0 -> 257 bytes
-rw-r--r--res/drawable-xhdpi-v11/notification_play.pngbin0 -> 493 bytes
-rw-r--r--res/drawable-xhdpi-v11/notification_previous.pngbin0 -> 750 bytes
-rw-r--r--res/drawable-xhdpi-v11/stat_notify_download.pngbin0 -> 379 bytes
-rw-r--r--res/drawable-xhdpi-v11/stat_notify_playing.pngbin0 -> 493 bytes
-rw-r--r--res/drawable-xhdpi/action_toggle_list_dark.pngbin0 -> 312 bytes
-rw-r--r--res/drawable-xhdpi/action_toggle_list_light.pngbin0 -> 320 bytes
-rw-r--r--res/drawable-xhdpi/download_cached.pngbin0 -> 1721 bytes
-rw-r--r--res/drawable-xhdpi/download_none_dark.pngbin0 -> 355 bytes
-rw-r--r--res/drawable-xhdpi/download_none_light.pngbin0 -> 375 bytes
-rw-r--r--res/drawable-xhdpi/download_pinned.pngbin0 -> 1750 bytes
-rw-r--r--res/drawable-xhdpi/downloading_dark.pngbin0 -> 869 bytes
-rw-r--r--res/drawable-xhdpi/downloading_light.pngbin0 -> 1017 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_volume_dark.pngbin0 -> 1916 bytes
-rw-r--r--res/drawable-xhdpi/ic_action_volume_light.pngbin0 -> 2180 bytes
-rw-r--r--res/drawable-xhdpi/ic_drawer.pngbin0 -> 2836 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_bookmark_dark.pngbin0 -> 1442 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_bookmark_light.pngbin0 -> 1665 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_chat_dark.pngbin0 -> 472 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_chat_light.pngbin0 -> 517 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_chat_send_dark.pngbin0 -> 743 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_chat_send_light.pngbin0 -> 799 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_library_dark.pngbin0 -> 820 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_library_light.pngbin0 -> 980 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_playlist_dark.pngbin0 -> 508 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_playlist_light.pngbin0 -> 555 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_podcast_dark.pngbin0 -> 1553 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_podcast_light.pngbin0 -> 1787 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_refresh_dark.pngbin0 -> 1520 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_refresh_light.pngbin0 -> 1802 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_remove_dark.pngbin0 -> 1146 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_remove_light.pngbin0 -> 1394 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_save_dark.pngbin0 -> 644 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_save_light.pngbin0 -> 735 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_search_dark.pngbin0 -> 1445 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_search_light.pngbin0 -> 1701 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_settings_dark.pngbin0 -> 708 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_settings_light.pngbin0 -> 748 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_shuffle_dark.pngbin0 -> 1400 bytes
-rw-r--r--res/drawable-xhdpi/ic_menu_shuffle_light.pngbin0 -> 1637 bytes
-rw-r--r--res/drawable-xhdpi/launch.pngbin8969 -> 39749 bytes
-rw-r--r--res/drawable-xhdpi/main_offline_dark.pngbin0 -> 818 bytes
-rw-r--r--res/drawable-xhdpi/main_offline_light.pngbin0 -> 976 bytes
-rw-r--r--res/drawable-xhdpi/main_select_server_dark.pngbin0 -> 939 bytes
-rw-r--r--res/drawable-xhdpi/main_select_server_light.pngbin0 -> 1079 bytes
-rw-r--r--res/drawable-xhdpi/media_backward_dark.pngbin0 -> 778 bytes
-rw-r--r--res/drawable-xhdpi/media_backward_light.pngbin0 -> 860 bytes
-rw-r--r--res/drawable-xhdpi/media_forward_dark.pngbin0 -> 716 bytes
-rw-r--r--res/drawable-xhdpi/media_forward_light.pngbin0 -> 834 bytes
-rw-r--r--res/drawable-xhdpi/media_pause_dark.pngbin0 -> 314 bytes
-rw-r--r--res/drawable-xhdpi/media_pause_light.pngbin0 -> 333 bytes
-rw-r--r--res/drawable-xhdpi/media_start_dark.pngbin0 -> 580 bytes
-rw-r--r--res/drawable-xhdpi/media_start_light.pngbin0 -> 649 bytes
-rw-r--r--res/drawable-xhdpi/media_stop_dark.pngbin0 -> 298 bytes
-rw-r--r--res/drawable-xhdpi/media_stop_light.pngbin0 -> 307 bytes
-rw-r--r--res/drawable-xhdpi/notification_close.pngbin0 -> 538 bytes
-rw-r--r--res/drawable-xhdpi/notification_next.pngbin0 -> 886 bytes
-rw-r--r--res/drawable-xhdpi/notification_pause.pngbin0 -> 529 bytes
-rw-r--r--res/drawable-xhdpi/notification_play.pngbin0 -> 753 bytes
-rw-r--r--res/drawable-xhdpi/notification_previous.pngbin0 -> 891 bytes
-rw-r--r--res/drawable-xhdpi/now_playing.pngbin0 -> 753 bytes
-rw-r--r--res/drawable-xhdpi/stat_notify_download.pngbin0 -> 404 bytes
-rw-r--r--res/drawable-xhdpi/stat_notify_playing.pngbin0 -> 753 bytes
-rw-r--r--res/drawable-xxhdpi-v11/notification_close.pngbin0 -> 712 bytes
-rw-r--r--res/drawable-xxhdpi-v11/notification_next.pngbin0 -> 1105 bytes
-rw-r--r--res/drawable-xxhdpi-v11/notification_pause.pngbin0 -> 358 bytes
-rw-r--r--res/drawable-xxhdpi-v11/notification_play.pngbin0 -> 781 bytes
-rw-r--r--res/drawable-xxhdpi-v11/notification_previous.pngbin0 -> 1143 bytes
-rw-r--r--res/drawable-xxhdpi-v11/stat_notify_download.pngbin0 -> 531 bytes
-rw-r--r--res/drawable-xxhdpi-v11/stat_notify_playing.pngbin0 -> 781 bytes
-rw-r--r--res/drawable-xxhdpi/action_toggle_list_dark.pngbin0 -> 608 bytes
-rw-r--r--res/drawable-xxhdpi/action_toggle_list_light.pngbin0 -> 630 bytes
-rw-r--r--res/drawable-xxhdpi/download_none_dark.pngbin0 -> 617 bytes
-rw-r--r--res/drawable-xxhdpi/download_none_light.pngbin0 -> 639 bytes
-rw-r--r--res/drawable-xxhdpi/downloading_dark.pngbin0 -> 1353 bytes
-rw-r--r--res/drawable-xxhdpi/downloading_light.pngbin0 -> 1542 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_volume_dark.pngbin0 -> 3148 bytes
-rw-r--r--res/drawable-xxhdpi/ic_action_volume_light.pngbin0 -> 3473 bytes
-rw-r--r--res/drawable-xxhdpi/ic_drawer.pngbin0 -> 202 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_bookmark_dark.pngbin0 -> 2194 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_bookmark_light.pngbin0 -> 2474 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_chat_dark.pngbin0 -> 723 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_chat_light.pngbin0 -> 771 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_chat_send_dark.pngbin0 -> 1326 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_chat_send_light.pngbin0 -> 1608 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_library_dark.pngbin0 -> 1357 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_library_light.pngbin0 -> 1579 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_playlist_dark.pngbin0 -> 783 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_playlist_light.pngbin0 -> 840 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_podcast_dark.pngbin0 -> 2439 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_podcast_light.pngbin0 -> 2798 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_refresh_dark.pngbin0 -> 2453 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_refresh_light.pngbin0 -> 2952 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_remove_dark.pngbin0 -> 1843 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_remove_light.pngbin0 -> 2164 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_save_dark.pngbin0 -> 977 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_save_light.pngbin0 -> 1076 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_search_dark.pngbin0 -> 2258 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_search_light.pngbin0 -> 2571 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_settings_dark.pngbin0 -> 1221 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_settings_light.pngbin0 -> 1194 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_shuffle_dark.pngbin0 -> 2268 bytes
-rw-r--r--res/drawable-xxhdpi/ic_menu_shuffle_light.pngbin0 -> 2529 bytes
-rw-r--r--res/drawable-xxhdpi/launch.pngbin15050 -> 85882 bytes
-rw-r--r--res/drawable-xxhdpi/main_offline_dark.pngbin0 -> 1265 bytes
-rw-r--r--res/drawable-xxhdpi/main_offline_light.pngbin0 -> 1466 bytes
-rw-r--r--res/drawable-xxhdpi/main_select_server_dark.pngbin0 -> 1396 bytes
-rw-r--r--res/drawable-xxhdpi/main_select_server_light.pngbin0 -> 1622 bytes
-rw-r--r--res/drawable-xxhdpi/media_backward_dark.pngbin0 -> 1282 bytes
-rw-r--r--res/drawable-xxhdpi/media_backward_light.pngbin0 -> 1443 bytes
-rw-r--r--res/drawable-xxhdpi/media_forward_dark.pngbin0 -> 1258 bytes
-rw-r--r--res/drawable-xxhdpi/media_forward_light.pngbin0 -> 1388 bytes
-rw-r--r--res/drawable-xxhdpi/media_pause_dark.pngbin0 -> 612 bytes
-rw-r--r--res/drawable-xxhdpi/media_pause_light.pngbin0 -> 631 bytes
-rw-r--r--res/drawable-xxhdpi/media_start_dark.pngbin0 -> 996 bytes
-rw-r--r--res/drawable-xxhdpi/media_start_light.pngbin0 -> 1069 bytes
-rw-r--r--res/drawable-xxhdpi/media_stop_dark.pngbin0 -> 545 bytes
-rw-r--r--res/drawable-xxhdpi/media_stop_light.pngbin0 -> 554 bytes
-rw-r--r--res/drawable-xxhdpi/notification_close.pngbin0 -> 1081 bytes
-rw-r--r--res/drawable-xxhdpi/notification_next.pngbin0 -> 1292 bytes
-rw-r--r--res/drawable-xxhdpi/notification_pause.pngbin0 -> 724 bytes
-rw-r--r--res/drawable-xxhdpi/notification_play.pngbin0 -> 1125 bytes
-rw-r--r--res/drawable-xxhdpi/notification_previous.pngbin0 -> 1261 bytes
-rw-r--r--res/drawable-xxhdpi/now_playing.pngbin0 -> 1125 bytes
-rw-r--r--res/drawable-xxhdpi/stat_notify_download.pngbin0 -> 558 bytes
-rw-r--r--res/drawable-xxhdpi/stat_notify_playing.pngbin0 -> 1125 bytes
-rw-r--r--res/layout-land/download.xml48
-rw-r--r--res/layout-large-land/abstract_fragment_container.xml21
-rw-r--r--res/layout-port/download.xml66
-rw-r--r--res/layout/abstract_activity.xml21
-rw-r--r--res/layout/abstract_fragment_activity.xml (renamed from res/layout/main.xml)164
-rw-r--r--res/layout/abstract_fragment_container.xml6
-rw-r--r--res/layout/abstract_list_fragment.xml (renamed from res/layout/select_podcasts.xml)58
-rw-r--r--res/layout/album_list_item.xml4
-rw-r--r--res/layout/appwidget4x1.xml3
-rw-r--r--res/layout/appwidget4x2.xml3
-rw-r--r--res/layout/appwidget4x3.xml3
-rw-r--r--res/layout/appwidget4x4.xml3
-rw-r--r--res/layout/basic_list_item.xml (renamed from res/layout/artist_list_item.xml)74
-rw-r--r--res/layout/create_bookmark.xml26
-rw-r--r--res/layout/download_action_buttons.xml33
-rw-r--r--res/layout/download_media_buttons.xml2
-rw-r--r--res/layout/drawer_list_item.xml26
-rw-r--r--res/layout/equalizer.xml2
-rw-r--r--res/layout/equalizer_bar.xml3
-rw-r--r--res/layout/help.xml42
-rw-r--r--res/layout/jukebox_volume.xml2
-rw-r--r--res/layout/main_buttons.xml9
-rw-r--r--res/layout/notification.xml120
-rw-r--r--res/layout/notification_expanded.xml2
-rw-r--r--res/layout/play_video.xml11
-rw-r--r--res/layout/playlist_list_item.xml26
-rw-r--r--res/layout/search.xml22
-rw-r--r--res/layout/search_buttons.xml12
-rw-r--r--res/layout/select_album_footer.xml21
-rw-r--r--res/layout/select_artist.xml22
-rw-r--r--res/layout/select_artist_header.xml2
-rw-r--r--res/layout/select_genres.xml30
-rw-r--r--res/layout/select_playlist.xml30
-rw-r--r--res/layout/song_list_item.xml24
-rw-r--r--res/menu/abstract_top_menu.xml (renamed from res/menu/chat.xml)38
-rw-r--r--res/menu/drawer_menu.xml8
-rw-r--r--res/menu/empty.xml2
-rw-r--r--res/menu/main.xml19
-rw-r--r--res/menu/nowplaying.xml15
-rw-r--r--res/menu/nowplaying_downloading.xml13
-rw-r--r--res/menu/nowplaying_offline.xml11
-rw-r--r--res/menu/search.xml13
-rw-r--r--res/menu/select_album.xml6
-rw-r--r--res/menu/select_album_list.xml2
-rw-r--r--res/menu/select_artist.xml14
-rw-r--r--res/menu/select_bookmark_context.xml24
-rw-r--r--res/menu/select_genres.xml12
-rw-r--r--res/menu/select_playlist.xml25
-rw-r--r--res/menu/select_podcast_episode.xml3
-rw-r--r--res/menu/select_podcast_episode_offline.xml3
-rw-r--r--res/menu/select_podcasts.xml18
-rw-r--r--res/menu/select_podcasts_context_offline.xml7
-rw-r--r--res/menu/select_song.xml26
-rw-r--r--res/menu/select_song_offline.xml18
-rw-r--r--res/raw/changelog.xml39
-rw-r--r--res/values-es/strings.xml401
-rw-r--r--res/values-large/dimens.xml5
-rw-r--r--res/values-v16/themes.xml10
-rw-r--r--res/values/arrays.xml52
-rw-r--r--res/values/attrs.xml15
-rw-r--r--res/values/dimens.xml5
-rw-r--r--res/values/strings.xml38
-rw-r--r--res/values/styles.xml30
-rw-r--r--res/values/themes.xml80
-rw-r--r--res/xml/settings.xml475
-rw-r--r--src/github/daneren2005/dsub/activity/DownloadActivity.java48
-rw-r--r--src/github/daneren2005/dsub/activity/EqualizerActivity.java278
-rw-r--r--src/github/daneren2005/dsub/activity/HelpActivity.java117
-rw-r--r--src/github/daneren2005/dsub/activity/QueryReceiverActivity.java7
-rw-r--r--src/github/daneren2005/dsub/activity/SearchActivity.java92
-rw-r--r--src/github/daneren2005/dsub/activity/SettingsActivity.java48
-rw-r--r--src/github/daneren2005/dsub/activity/SubsonicActivity.java758
-rw-r--r--src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java (renamed from src/github/daneren2005/dsub/activity/MainActivity.java)775
-rw-r--r--src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java7
-rw-r--r--src/github/daneren2005/dsub/audiofx/EqualizerController.java15
-rw-r--r--src/github/daneren2005/dsub/domain/Bookmark.java102
-rw-r--r--src/github/daneren2005/dsub/domain/Indexes.java29
-rw-r--r--src/github/daneren2005/dsub/domain/MusicDirectory.java35
-rw-r--r--src/github/daneren2005/dsub/domain/MusicFolder.java7
-rw-r--r--src/github/daneren2005/dsub/domain/Playlist.java3
-rw-r--r--src/github/daneren2005/dsub/fragments/ChatFragment.java2
-rw-r--r--src/github/daneren2005/dsub/fragments/DownloadFragment.java309
-rw-r--r--src/github/daneren2005/dsub/fragments/EqualizerFragment.java286
-rw-r--r--src/github/daneren2005/dsub/fragments/MainFragment.java8
-rw-r--r--src/github/daneren2005/dsub/fragments/SearchFragment.java27
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectArtistFragment.java22
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java238
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java93
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectGenreFragment.java24
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java17
-rw-r--r--src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java12
-rw-r--r--src/github/daneren2005/dsub/fragments/SubsonicFragment.java72
-rw-r--r--src/github/daneren2005/dsub/provider/DSubWidgetProvider.java20
-rw-r--r--src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java10
-rw-r--r--src/github/daneren2005/dsub/service/CachedMusicService.java103
-rw-r--r--src/github/daneren2005/dsub/service/DownloadFile.java33
-rw-r--r--src/github/daneren2005/dsub/service/DownloadService.java2
-rw-r--r--src/github/daneren2005/dsub/service/DownloadServiceImpl.java126
-rw-r--r--src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java28
-rw-r--r--src/github/daneren2005/dsub/service/JukeboxController.java2
-rw-r--r--src/github/daneren2005/dsub/service/MusicService.java14
-rw-r--r--src/github/daneren2005/dsub/service/OfflineMusicService.java62
-rw-r--r--src/github/daneren2005/dsub/service/RESTMusicService.java86
-rw-r--r--src/github/daneren2005/dsub/service/StreamProxy.java151
-rw-r--r--src/github/daneren2005/dsub/service/parser/BookmarkParser.java73
-rw-r--r--src/github/daneren2005/dsub/service/parser/IndexesParser.java11
-rw-r--r--src/github/daneren2005/dsub/util/Constants.java10
-rw-r--r--src/github/daneren2005/dsub/util/FileUtil.java61
-rw-r--r--src/github/daneren2005/dsub/util/Util.java136
-rw-r--r--src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java2
-rw-r--r--src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java43
-rw-r--r--src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java50
-rw-r--r--src/github/daneren2005/dsub/view/ArtistAdapter.java2
-rw-r--r--src/github/daneren2005/dsub/view/ArtistEntryView.java8
-rw-r--r--src/github/daneren2005/dsub/view/ArtistView.java10
-rw-r--r--src/github/daneren2005/dsub/view/BookmarkAdapter.java62
-rw-r--r--src/github/daneren2005/dsub/view/DrawerAdapter.java68
-rw-r--r--src/github/daneren2005/dsub/view/ErrorDialog.java11
-rw-r--r--src/github/daneren2005/dsub/view/GenreView.java9
-rw-r--r--src/github/daneren2005/dsub/view/PlaylistAdapter.java2
-rw-r--r--src/github/daneren2005/dsub/view/PlaylistView.java16
-rw-r--r--src/github/daneren2005/dsub/view/PodcastChannelView.java8
-rw-r--r--src/github/daneren2005/dsub/view/SongView.java49
-rw-r--r--src/github/daneren2005/dsub/view/UpdateView.java13
451 files changed, 4357 insertions, 3092 deletions
diff --git a/.gitignore b/.gitignore
index 58844f15..f465e508 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ private/*
nbandroid/*
.idea
subsonic-android.iml
+releases/ \ No newline at end of file
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 2e96d2ca..207c2afd 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="62"
- android:versionName="4.1.4">
+ android:versionCode="69"
+ android:versionName="4.2.0">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
@@ -23,7 +23,7 @@
<uses-feature android:name="android.hardware.bluetooth" android:required="false" />
<uses-feature android:name="android.hardware.microphone" android:required="false" />
- <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18"/>
+ <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="19"/>
<supports-screens android:anyDensity="true" android:xlargeScreens="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/>
@@ -32,36 +32,20 @@
android:icon="@drawable/launch"
android:theme="@style/Theme.DSub.Holo">
- <activity android:name="github.daneren2005.dsub.activity.MainActivity"
- android:label="DSub"
- android:configChanges="orientation|keyboardHidden"
- android:launchMode="standard">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- <category android:name="android.intent.category.LAUNCHER"/>
- </intent-filter>
- </activity>
-
- <activity android:name="github.daneren2005.dsub.activity.SearchActivity"
- android:label="@string/search.label"
- android:configChanges="orientation|keyboardHidden"
- android:launchMode="singleTask"/>
+ <activity android:name="github.daneren2005.dsub.activity.SubsonicFragmentActivity"
+ android:configChanges="orientation|keyboardHidden"
+ android:launchMode="standard">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
- <activity android:name="github.daneren2005.dsub.activity.DownloadActivity"
+ <activity android:name="github.daneren2005.dsub.activity.DownloadActivity"
android:configChanges="keyboardHidden"
android:launchMode="singleTask"/>
<activity android:name="github.daneren2005.dsub.activity.SettingsActivity"
- android:theme="@style/Theme.DSub.Dark"
- android:configChanges="orientation|keyboardHidden"
- android:launchMode="singleTask"/>
-
- <activity android:name="github.daneren2005.dsub.activity.HelpActivity"
- android:label="@string/help.label"
- android:launchMode="singleTask"/>
-
- <activity android:name="github.daneren2005.dsub.activity.EqualizerActivity"
- android:label="@string/equalizer.label"
android:configChanges="orientation|keyboardHidden"
android:launchMode="singleTask"/>
diff --git a/DSub.png b/DSub.png
index 1ec0bfff..d6bd8439 100644
--- a/DSub.png
+++ b/DSub.png
Binary files differ
diff --git a/README b/README
index 8b117f7c..4e716c5a 100644
--- a/README
+++ b/README
@@ -3,26 +3,23 @@ Run these commands to grab dependent libraries:
git submodule init
git submodule update
-Go to both ActionBarSherlock/library and DragSortListView/library and build project files with:
+Go to DragSortListView/library and build project files with:
android update project --path ./
+Replace the file DragSortListView/library/libs/android-support-v4.jar with the one from main projects libs/
Roadmap of major planned features in rough order that I plan to work on them in (little features get sprinkled in wherever):
UI Redesign
- -Fragments
- -Native tabs
-Tablets: side by side fragments
HLS Video
-Display video where album art is currently (double tap to fullscreen)
-Videos can play inline with songs
Background Sync
-Mark playlists as 'offline', syncs changes
- -Do things like star songs in offline mode that sync later
+ -Mark podcasts as 'offline', download new episodes only
New Tabs
- -Podcasts
-Admin functions
-Change your password
-Create/delete users if admin
- -Chat
diff --git a/Subsonic.iml b/Subsonic.iml
index d89b96cf..f7983073 100644
--- a/Subsonic.iml
+++ b/Subsonic.iml
@@ -11,13 +11,13 @@
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
- <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/gen" isTestSource="false" generated="true" />
</content>
+ <orderEntry type="library" name="libs1" level="project" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
- <orderEntry type="library" name="libs1" level="project" />
- <orderEntry type="module" module-name="DragSortListView" />
<orderEntry type="module" module-name="appcompat" />
+ <orderEntry type="module" module-name="DragSortListView" />
</component>
</module>
diff --git a/assets/fonts/Storopia.ttf b/assets/fonts/Storopia.ttf
deleted file mode 100644
index cbdc4c1f..00000000
--- a/assets/fonts/Storopia.ttf
+++ /dev/null
Binary files differ
diff --git a/assets/html/en/index.html b/assets/html/en/index.html
deleted file mode 100644
index 9ad7542c..00000000
--- a/assets/html/en/index.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<html>
-<head>
- <title>DSub Help</title>
- <link rel="stylesheet" href="../style.css" type="text/css">
-
-</head>
-
-<body>
-
-<h3><img src="../img/subsonic.png" alt=""> Welcome to DSub!</h3>
-
-<p>
- With <b>DSub</b> you can easily stream or download music from your home computer to your Android phone
- (and do lots of other cool stuff too).
-</p>
-
-<p>
- To install the Subsonic server software on your computer, please visit <a href="http://subsonic.org">subsonic.org</a>.
- It's available for Windows, Mac, Linux and Unix.
-</p>
-
-<p>
- By default, this program is configured to use the <b>Subsonic demo server</b>. Once you've set up your own
- server, please go to <b>Settings</b> and change the configuration so that it connects to your own computer.
-</p>
-
-<p>
- You can use this program freely for 30 days. After that you will have to make a donation to the Subsonic project.
- As a donor you get the following benefits:
-</p>
-<ul>
- <li>Unlimited streaming and download to any number of iPhone and Android phones.</li>
- <li>Video streaming.</li>
- <li>A personal web address for your Subsonic server (<em>yourname</em>.subsonic.org).</li>
- <li>No ads in the Subsonic web interface.</li>
- <li>Free access to new premium features.</li>
-</ul>
-
-<p>
- The suggested donation amount is <b>&euro;20</b>, but you can give any amount you like.
-</p>
-
-<p>
- Click one of the buttons to go to PayPal where you can pay by credit card or by using your PayPal account.
- Once the donation is processed, you will receive a license key by email.
-</p>
-
-<table>
- <tr>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3RTGWJRNAW2PU"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;10</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCUUB2TYE4PGN"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;20</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3M6TFHWEPSU44"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;25</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5KP7LPQU77UAS"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;30</td>
- </tr>
- </table>
- </td>
- </tr>
-</table>
-
-<p>
- For more information, please visit <a href="http://subsonic.org/">subsonic.org</a>
-</p>
-
-</body>
-</html>
diff --git a/assets/html/fr/index.html b/assets/html/fr/index.html
deleted file mode 100644
index 4ac8c9c3..00000000
--- a/assets/html/fr/index.html
+++ /dev/null
@@ -1,100 +0,0 @@
-<html>
-<head>
- <title>Aide de Subsonic</title>
- <link rel="stylesheet" href="../style.css" type="text/css">
-
-</head>
-
-<body>
-
-<h3><img src="../img/subsonic.png" alt=""> Bienvenue dans Subsonic</h3>
-
-<p>
- Avec <b>Subsonic</b>, vous pouvez facilement &eacute;couter ou t&eacute;l&eacute;charger de la musique &agrave; partir de votre ordinateur personnel sur votre appareil Android
- (et faire plein d'autres trucs cools aussi).
-</p>
-
-<p>
- Pour installer le serveur Subsonic sur votre ordinateur, veuillez visiter <a href="http://subsonic.org">subsonic.org</a>.
- Celui-ci est disponible pour Windows, Mac, Linux et Unix.
-</p>
-
-<p>
- Par d&eacute;faut, cette application est configur&eacute; pour utiliser le <b>serveur d&eacute;mo Subsonic</b>.
- Apr&egrave;s avoir configur&eacute; votre serveur personnel, veuillez acc&eacute;der aux <b>Param&egrave;tres</b> et modifier la configuration
- afin de vous connecter &agrave; votre propre ordinateur.
-</p>
-
-<p>
- Vous pouvez utiliser cette application gratuitement pendant 30 jours.
- Ensuite, vous devrez effectuer un don au projet Subsonic.
- En tant que donateur, vous obtiendrez les b&eacute;n&eacute;fices suivants:
-</p>
-<ul>
- <li>&Eacute;coute et t&eacute;l&eacute;chargement illimit&eacute;s vers autant de iPhones et d'appareils Android que d&eacute;sir&eacute;.</li>
- <li>&Eacute;coute de vid&eacute;os.</li>
- <li>Une adresse web personnalis&eacute;e pour votre serveur Subsonic (<em>votrenom</em>.subsonic.org).</li>
- <li>Aucune publicit&eacute; dans l'interface web de Subsonic.</li>
- <li>Acc&egrave;s gratuit aux nouvelles fonctionnalit&eacute;s avanc&eacute;es.</li>
-</ul>
-
-<p>
- Le montant sugg&eacute;r&eacute; pour le don est de <b>20&euro;</b>, mais n'importe quel montant fera l'affaire.
-</p>
-
-<p>
- Cliquez l'un des boutons suivants pour acc&eacute;der &agrave; PayPal, d'o&ugrave; vous pourrez payer soit par carte de cr&eacute;dit ou en utilisant votre compte PayPal.
- Une fois le don re&ccedil;u et trait&eacute;, vous recevrez votre cl&eacute; d'activation par courriel.
-</p>
-
-<table>
- <tr>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3RTGWJRNAW2PU"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">10&euro;</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCUUB2TYE4PGN"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">20&euro;</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3M6TFHWEPSU44"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">25&euro;</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5KP7LPQU77UAS"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">30&euro;</td>
- </tr>
- </table>
- </td>
- </tr>
-</table>
-
-<p>
- Pour plus d'information, veuillez visiter <a href="http://subsonic.org/">subsonic.org</a>
-</p>
-
-</body>
-</html>
diff --git a/assets/html/img/paypal.gif b/assets/html/img/paypal.gif
deleted file mode 100644
index d017250a..00000000
--- a/assets/html/img/paypal.gif
+++ /dev/null
Binary files differ
diff --git a/assets/html/img/subsonic.png b/assets/html/img/subsonic.png
deleted file mode 100644
index 38c521c5..00000000
--- a/assets/html/img/subsonic.png
+++ /dev/null
Binary files differ
diff --git a/assets/html/ru/index.html b/assets/html/ru/index.html
deleted file mode 100644
index 57979152..00000000
--- a/assets/html/ru/index.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<html>
-<head>
- <title>Помощь DSub</title>
- <link rel="stylesheet" href="../style.css" type="text/css">
-
-</head>
-
-<body>
-
-<h3><img src="../img/subsonic.png" alt=""> Добро пожаловать в DSub!</h3>
-
-<p>
- С программой <b>DSub</b> Вы можете легко включить поточное воспроизведение или скачивать музыку с Вашего домашнего компьютера на Android устройство
- (и использовать множество других полезных функции).
-</p>
-
-<p>
- Для установки серверного приложения Subsonic на Ваш компьютер, пожалуйста, посетите <a href="http://subsonic.org">subsonic.org</a>.
- Приложение доступно для Windows, Mac, а также Linux и Unix.
-</p>
-
-<p>
- По умолчанию данная программа настроена на работу с <b>демо сервером Subsonic</b>. После установки серверного
- приложения, пожалуйста, перейдите в раздел <b>Настройки</b> и измените параметры для подключения.
-</p>
-
-<p>
- Вы можете бесплатно использовать программу до 30 дней. После этого Вам необходимо сделать пожертвование проекту Subsonic.
- После этого Вы получите следующие возможности:
-</p>
-<ul>
- <li>Неограниченное поточное воспроизведение или скачивание с любого количества iPhone и Android устройств.</li>
- <li>Потоковое воспроизведение видео.</li>
- <li>Персональный адрес страницы на сервере Subsonic (<em>вашеимя</em>.subsonic.org).</li>
- <li>Отсутствие рекламы в веб-интерфейсе Subsonic.</li>
- <li>Бесплатный доступ к новым премиум-функциям.</li>
-</ul>
-
-<p>
- Рекомендуемая сумма пожертвования - <b>&euro;20</b>, но Вы можете пожертвовать любую сумму.
-</p>
-
-<p>
- Нажмите одну из кнопок для перехода на страницу PayPal, откуда Вы сможете сделать перевод с Вашей кредитной карты или используя аккаунт PayPal.
- После отправки пожертвования Вы получите лицензионный ключ на Ваш email.
-</p>
-
-<table>
- <tr>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3RTGWJRNAW2PU"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;10</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UCUUB2TYE4PGN"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;20</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=3M6TFHWEPSU44"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;25</td>
- </tr>
- </table>
- </td>
- <td style="border:none;">
- <table>
- <tr>
- <td style="border:none;padding:0"><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=5KP7LPQU77UAS"><img src="../img/paypal.gif" alt=""/></a> </td>
- </tr>
- <tr>
- <td style="text-align:center;border:none;padding:0">&euro;30</td>
- </tr>
- </table>
- </td>
- </tr>
-</table>
-
-<p>
- За дополнительной информацией посетите <a href="http://subsonic.org/">subsonic.org</a>
-</p>
-
-</body>
-</html> \ No newline at end of file
diff --git a/assets/html/style.css b/assets/html/style.css
deleted file mode 100644
index 9c1d55f2..00000000
--- a/assets/html/style.css
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
-* Taken from http://yui.yahooapis.com/2.8.0r4/build/fonts/fonts.css
-*/
-body {
- font: 13px / 1.231 arial, helvetica, clean, sans-serif;
-}
-
-table {
- font-size:inherit;
- font:100%;
-} \ No newline at end of file
diff --git a/libs/android-support-v4.jar b/libs/android-support-v4.jar
index cf12d283..9056828a 100644
--- a/libs/android-support-v4.jar
+++ b/libs/android-support-v4.jar
Binary files differ
diff --git a/libs/android-support-v7-appcompat.jar b/libs/android-support-v7-appcompat.jar
index b5f52924..fd1d984d 100644
--- a/libs/android-support-v7-appcompat.jar
+++ b/libs/android-support-v7-appcompat.jar
Binary files differ
diff --git a/libs/kryo-2.21-all.jar b/libs/kryo-2.21-all.jar
new file mode 100644
index 00000000..83f8b0f0
--- /dev/null
+++ b/libs/kryo-2.21-all.jar
Binary files differ
diff --git a/project.properties b/project.properties
index 558f3a9e..73506e5d 100644
--- a/project.properties
+++ b/project.properties
@@ -8,6 +8,6 @@
# project structure.
# Project target.
-target=android-18
-android.library.reference.1=DragSortListView/library
-android.library.reference.2=../../../../Program Files (x86)/Android/android-sdk/extras/android/support/v7/appcompat \ No newline at end of file
+target=android-19
+android.library.reference.1=../../../../Program Files (x86)/Android/android-sdk/extras/android/support/v7/appcompat
+android.library.reference.2=DragSortListView/library \ No newline at end of file
diff --git a/releases/DSub 4.0.1.apk b/releases/DSub 4.0.1.apk
deleted file mode 100644
index 850a4bfa..00000000
--- a/releases/DSub 4.0.1.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.0.2.apk b/releases/DSub 4.0.2.apk
deleted file mode 100644
index 0c168ba8..00000000
--- a/releases/DSub 4.0.2.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.0.3.apk b/releases/DSub 4.0.3.apk
deleted file mode 100644
index a1749e3c..00000000
--- a/releases/DSub 4.0.3.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.0.4.apk b/releases/DSub 4.0.4.apk
deleted file mode 100644
index 1332af32..00000000
--- a/releases/DSub 4.0.4.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.0.5.apk b/releases/DSub 4.0.5.apk
deleted file mode 100644
index 1ece93f6..00000000
--- a/releases/DSub 4.0.5.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.0.6.apk b/releases/DSub 4.0.6.apk
deleted file mode 100644
index 278256d7..00000000
--- a/releases/DSub 4.0.6.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.0.7.apk b/releases/DSub 4.0.7.apk
deleted file mode 100644
index a97c215c..00000000
--- a/releases/DSub 4.0.7.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.1.0.apk b/releases/DSub 4.1.0.apk
deleted file mode 100644
index 1bb3fe41..00000000
--- a/releases/DSub 4.1.0.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.1.1.apk b/releases/DSub 4.1.1.apk
deleted file mode 100644
index 9d582aec..00000000
--- a/releases/DSub 4.1.1.apk
+++ /dev/null
Binary files differ
diff --git a/releases/DSub 4.1.2.apk b/releases/DSub 4.1.2.apk
deleted file mode 100644
index 0a4ee2bc..00000000
--- a/releases/DSub 4.1.2.apk
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi-v11/notification_close.png b/res/drawable-hdpi-v11/notification_close.png
new file mode 100644
index 00000000..254e130f
--- /dev/null
+++ b/res/drawable-hdpi-v11/notification_close.png
Binary files differ
diff --git a/res/drawable-hdpi-v11/notification_next.png b/res/drawable-hdpi-v11/notification_next.png
new file mode 100644
index 00000000..59239305
--- /dev/null
+++ b/res/drawable-hdpi-v11/notification_next.png
Binary files differ
diff --git a/res/drawable-hdpi-v11/notification_pause.png b/res/drawable-hdpi-v11/notification_pause.png
new file mode 100644
index 00000000..cbd61795
--- /dev/null
+++ b/res/drawable-hdpi-v11/notification_pause.png
Binary files differ
diff --git a/res/drawable-hdpi-v11/notification_play.png b/res/drawable-hdpi-v11/notification_play.png
new file mode 100644
index 00000000..78b4d5bf
--- /dev/null
+++ b/res/drawable-hdpi-v11/notification_play.png
Binary files differ
diff --git a/res/drawable-hdpi-v11/notification_previous.png b/res/drawable-hdpi-v11/notification_previous.png
new file mode 100644
index 00000000..556eaec3
--- /dev/null
+++ b/res/drawable-hdpi-v11/notification_previous.png
Binary files differ
diff --git a/res/drawable-hdpi-v11/stat_notify_download.png b/res/drawable-hdpi-v11/stat_notify_download.png
new file mode 100644
index 00000000..48ca6924
--- /dev/null
+++ b/res/drawable-hdpi-v11/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-hdpi-v11/stat_notify_playing.png b/res/drawable-hdpi-v11/stat_notify_playing.png
new file mode 100644
index 00000000..78b4d5bf
--- /dev/null
+++ b/res/drawable-hdpi-v11/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-hdpi/action_browse.png b/res/drawable-hdpi/action_browse.png
deleted file mode 100644
index 54296909..00000000
--- a/res/drawable-hdpi/action_browse.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_compass.png b/res/drawable-hdpi/action_compass.png
deleted file mode 100644
index 39760f89..00000000
--- a/res/drawable-hdpi/action_compass.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_exit.png b/res/drawable-hdpi/action_exit.png
deleted file mode 100644
index 09e18dee..00000000
--- a/res/drawable-hdpi/action_exit.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_help.png b/res/drawable-hdpi/action_help.png
deleted file mode 100644
index aaf8304c..00000000
--- a/res/drawable-hdpi/action_help.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_moreoverflow.png b/res/drawable-hdpi/action_moreoverflow.png
deleted file mode 100644
index cb6ebdaf..00000000
--- a/res/drawable-hdpi/action_moreoverflow.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_offline.png b/res/drawable-hdpi/action_offline.png
deleted file mode 100644
index a85f0931..00000000
--- a/res/drawable-hdpi/action_offline.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_play_all.png b/res/drawable-hdpi/action_play_all.png
deleted file mode 100644
index 6ce5629a..00000000
--- a/res/drawable-hdpi/action_play_all.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_refresh.png b/res/drawable-hdpi/action_refresh.png
deleted file mode 100644
index 9f30dc95..00000000
--- a/res/drawable-hdpi/action_refresh.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_remove_all.png b/res/drawable-hdpi/action_remove_all.png
deleted file mode 100644
index 97b88837..00000000
--- a/res/drawable-hdpi/action_remove_all.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_save.png b/res/drawable-hdpi/action_save.png
deleted file mode 100644
index 7bda97d6..00000000
--- a/res/drawable-hdpi/action_save.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_screen_on_off.png b/res/drawable-hdpi/action_screen_on_off.png
deleted file mode 100644
index c7168563..00000000
--- a/res/drawable-hdpi/action_screen_on_off.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_search.png b/res/drawable-hdpi/action_search.png
deleted file mode 100644
index 6bc3d426..00000000
--- a/res/drawable-hdpi/action_search.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_select.png b/res/drawable-hdpi/action_select.png
deleted file mode 100644
index e9e83e3d..00000000
--- a/res/drawable-hdpi/action_select.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_settings.png b/res/drawable-hdpi/action_settings.png
deleted file mode 100644
index 1ab7722b..00000000
--- a/res/drawable-hdpi/action_settings.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_share.png b/res/drawable-hdpi/action_share.png
deleted file mode 100644
index 28376157..00000000
--- a/res/drawable-hdpi/action_share.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_shuffle.png b/res/drawable-hdpi/action_shuffle.png
deleted file mode 100644
index 0613965c..00000000
--- a/res/drawable-hdpi/action_shuffle.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_toggle_list.png b/res/drawable-hdpi/action_toggle_list.png
deleted file mode 100644
index 87f9280f..00000000
--- a/res/drawable-hdpi/action_toggle_list.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/action_toggle_list_dark.png b/res/drawable-hdpi/action_toggle_list_dark.png
new file mode 100644
index 00000000..d0ec1a5d
--- /dev/null
+++ b/res/drawable-hdpi/action_toggle_list_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/action_toggle_list_light.png b/res/drawable-hdpi/action_toggle_list_light.png
new file mode 100644
index 00000000..60ec88be
--- /dev/null
+++ b/res/drawable-hdpi/action_toggle_list_light.png
Binary files differ
diff --git a/res/drawable-hdpi/actionbar_background.9.png b/res/drawable-hdpi/actionbar_background.9.png
deleted file mode 100644
index 9ce38a61..00000000
--- a/res/drawable-hdpi/actionbar_background.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/album_art_background.png b/res/drawable-hdpi/album_art_background.png
deleted file mode 100644
index f0757695..00000000
--- a/res/drawable-hdpi/album_art_background.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/download_cached.png b/res/drawable-hdpi/download_cached.png
new file mode 100644
index 00000000..d935cb2c
--- /dev/null
+++ b/res/drawable-hdpi/download_cached.png
Binary files differ
diff --git a/res/drawable-hdpi/download_none_dark.png b/res/drawable-hdpi/download_none_dark.png
new file mode 100644
index 00000000..a074c10d
--- /dev/null
+++ b/res/drawable-hdpi/download_none_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/download_none_light.png b/res/drawable-hdpi/download_none_light.png
new file mode 100644
index 00000000..21544e5f
--- /dev/null
+++ b/res/drawable-hdpi/download_none_light.png
Binary files differ
diff --git a/res/drawable-hdpi/download_pinned.png b/res/drawable-hdpi/download_pinned.png
new file mode 100644
index 00000000..b5b6dfb1
--- /dev/null
+++ b/res/drawable-hdpi/download_pinned.png
Binary files differ
diff --git a/res/drawable-hdpi/downloading.png b/res/drawable-hdpi/downloading.png
deleted file mode 100644
index afff39a9..00000000
--- a/res/drawable-hdpi/downloading.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/downloading_dark.png b/res/drawable-hdpi/downloading_dark.png
new file mode 100644
index 00000000..3ccb1837
--- /dev/null
+++ b/res/drawable-hdpi/downloading_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/downloading_light.png b/res/drawable-hdpi/downloading_light.png
new file mode 100644
index 00000000..07be3016
--- /dev/null
+++ b/res/drawable-hdpi/downloading_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_volume_dark.png b/res/drawable-hdpi/ic_action_volume_dark.png
new file mode 100644
index 00000000..62550655
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_volume_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_action_volume_light.png b/res/drawable-hdpi/ic_action_volume_light.png
new file mode 100644
index 00000000..1b1d182c
--- /dev/null
+++ b/res/drawable-hdpi/ic_action_volume_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_drawer.png b/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 00000000..c59f601c
--- /dev/null
+++ b/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_bookmark_dark.png b/res/drawable-hdpi/ic_menu_bookmark_dark.png
new file mode 100644
index 00000000..e7cd08e4
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_bookmark_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_bookmark_light.png b/res/drawable-hdpi/ic_menu_bookmark_light.png
new file mode 100644
index 00000000..fdb46da3
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_bookmark_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_chat_dark.png b/res/drawable-hdpi/ic_menu_chat_dark.png
index be04b06e..75363fce 100644
--- a/res/drawable-hdpi/ic_menu_chat_dark.png
+++ b/res/drawable-hdpi/ic_menu_chat_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_chat_light.png b/res/drawable-hdpi/ic_menu_chat_light.png
index 3f58695c..e28933e4 100644
--- a/res/drawable-hdpi/ic_menu_chat_light.png
+++ b/res/drawable-hdpi/ic_menu_chat_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_chat_send_dark.png b/res/drawable-hdpi/ic_menu_chat_send_dark.png
index bd37dc59..c0e9b372 100644
--- a/res/drawable-hdpi/ic_menu_chat_send_dark.png
+++ b/res/drawable-hdpi/ic_menu_chat_send_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_chat_send_light.png b/res/drawable-hdpi/ic_menu_chat_send_light.png
index 0c870d2c..ebcfe9e8 100644
--- a/res/drawable-hdpi/ic_menu_chat_send_light.png
+++ b/res/drawable-hdpi/ic_menu_chat_send_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_exit.png b/res/drawable-hdpi/ic_menu_exit.png
deleted file mode 100644
index 847a1ed3..00000000
--- a/res/drawable-hdpi/ic_menu_exit.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_help.png b/res/drawable-hdpi/ic_menu_help.png
deleted file mode 100644
index 9f11f434..00000000
--- a/res/drawable-hdpi/ic_menu_help.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_library_dark.png b/res/drawable-hdpi/ic_menu_library_dark.png
new file mode 100644
index 00000000..717cb3e1
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_library_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_library_light.png b/res/drawable-hdpi/ic_menu_library_light.png
new file mode 100644
index 00000000..17a45d77
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_library_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_playlist_dark.png b/res/drawable-hdpi/ic_menu_playlist_dark.png
new file mode 100644
index 00000000..8e3babc7
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_playlist_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_playlist_light.png b/res/drawable-hdpi/ic_menu_playlist_light.png
new file mode 100644
index 00000000..4131dba4
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_playlist_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_podcast_dark.png b/res/drawable-hdpi/ic_menu_podcast_dark.png
new file mode 100644
index 00000000..d1d62d03
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_podcast_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_podcast_light.png b/res/drawable-hdpi/ic_menu_podcast_light.png
new file mode 100644
index 00000000..4ce1b787
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_podcast_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_refresh_dark.png b/res/drawable-hdpi/ic_menu_refresh_dark.png
new file mode 100644
index 00000000..2795cfa9
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_refresh_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_refresh_light.png b/res/drawable-hdpi/ic_menu_refresh_light.png
new file mode 100644
index 00000000..86d1b042
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_refresh_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_remove_dark.png b/res/drawable-hdpi/ic_menu_remove_dark.png
new file mode 100644
index 00000000..878b378a
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_remove_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_remove_light.png b/res/drawable-hdpi/ic_menu_remove_light.png
new file mode 100644
index 00000000..ece5ad8d
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_remove_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_save_dark.png b/res/drawable-hdpi/ic_menu_save_dark.png
new file mode 100644
index 00000000..b80828bf
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_save_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_save_light.png b/res/drawable-hdpi/ic_menu_save_light.png
new file mode 100644
index 00000000..a3a5e23a
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_save_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_search_dark.png b/res/drawable-hdpi/ic_menu_search_dark.png
new file mode 100644
index 00000000..ef2b3013
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_search_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_search_light.png b/res/drawable-hdpi/ic_menu_search_light.png
new file mode 100644
index 00000000..756937df
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_search_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings.png b/res/drawable-hdpi/ic_menu_settings.png
deleted file mode 100644
index 48775c1e..00000000
--- a/res/drawable-hdpi/ic_menu_settings.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings_dark.png b/res/drawable-hdpi/ic_menu_settings_dark.png
new file mode 100644
index 00000000..d6dd17ec
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_settings_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_settings_light.png b/res/drawable-hdpi/ic_menu_settings_light.png
new file mode 100644
index 00000000..70c29951
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_settings_light.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_shuffle.png b/res/drawable-hdpi/ic_menu_shuffle.png
deleted file mode 100644
index 0613965c..00000000
--- a/res/drawable-hdpi/ic_menu_shuffle.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_shuffle_dark.png b/res/drawable-hdpi/ic_menu_shuffle_dark.png
new file mode 100644
index 00000000..f77cfed2
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_shuffle_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/ic_menu_shuffle_light.png b/res/drawable-hdpi/ic_menu_shuffle_light.png
new file mode 100644
index 00000000..ded93939
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_shuffle_light.png
Binary files differ
diff --git a/res/drawable-hdpi/launch.png b/res/drawable-hdpi/launch.png
index 72f80486..9caa6675 100644
--- a/res/drawable-hdpi/launch.png
+++ b/res/drawable-hdpi/launch.png
Binary files differ
diff --git a/res/drawable-hdpi/list_item_more.9.png b/res/drawable-hdpi/list_item_more.9.png
deleted file mode 100644
index 79ca860d..00000000
--- a/res/drawable-hdpi/list_item_more.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_item_more_saved.9.png b/res/drawable-hdpi/list_item_more_saved.9.png
deleted file mode 100644
index f3805bfb..00000000
--- a/res/drawable-hdpi/list_item_more_saved.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/list_item_more_shaded.9.png b/res/drawable-hdpi/list_item_more_shaded.9.png
deleted file mode 100644
index 99c2f5b8..00000000
--- a/res/drawable-hdpi/list_item_more_shaded.9.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/main_offline.png b/res/drawable-hdpi/main_offline.png
deleted file mode 100644
index a1d27cec..00000000
--- a/res/drawable-hdpi/main_offline.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/main_offline_dark.png b/res/drawable-hdpi/main_offline_dark.png
new file mode 100644
index 00000000..a594530d
--- /dev/null
+++ b/res/drawable-hdpi/main_offline_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/main_offline_light.png b/res/drawable-hdpi/main_offline_light.png
index 69bee782..cabca581 100644
--- a/res/drawable-hdpi/main_offline_light.png
+++ b/res/drawable-hdpi/main_offline_light.png
Binary files differ
diff --git a/res/drawable-hdpi/main_select_server.png b/res/drawable-hdpi/main_select_server.png
deleted file mode 100644
index c2cefead..00000000
--- a/res/drawable-hdpi/main_select_server.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/main_select_server_dark.png b/res/drawable-hdpi/main_select_server_dark.png
new file mode 100644
index 00000000..e3a9dd5d
--- /dev/null
+++ b/res/drawable-hdpi/main_select_server_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/main_select_server_light.png b/res/drawable-hdpi/main_select_server_light.png
new file mode 100644
index 00000000..4606410d
--- /dev/null
+++ b/res/drawable-hdpi/main_select_server_light.png
Binary files differ
diff --git a/res/drawable-hdpi/media_backward.png b/res/drawable-hdpi/media_backward.png
deleted file mode 100644
index 3bb85e68..00000000
--- a/res/drawable-hdpi/media_backward.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/media_backward_dark.png b/res/drawable-hdpi/media_backward_dark.png
new file mode 100644
index 00000000..b1dde4f5
--- /dev/null
+++ b/res/drawable-hdpi/media_backward_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/media_backward_light.png b/res/drawable-hdpi/media_backward_light.png
index 14188c86..3e277267 100644
--- a/res/drawable-hdpi/media_backward_light.png
+++ b/res/drawable-hdpi/media_backward_light.png
Binary files differ
diff --git a/res/drawable-hdpi/media_forward.png b/res/drawable-hdpi/media_forward.png
deleted file mode 100644
index cf39f1f0..00000000
--- a/res/drawable-hdpi/media_forward.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/media_forward_dark.png b/res/drawable-hdpi/media_forward_dark.png
new file mode 100644
index 00000000..eb2546c7
--- /dev/null
+++ b/res/drawable-hdpi/media_forward_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/media_forward_light.png b/res/drawable-hdpi/media_forward_light.png
index 9e172d8f..185e3c39 100644
--- a/res/drawable-hdpi/media_forward_light.png
+++ b/res/drawable-hdpi/media_forward_light.png
Binary files differ
diff --git a/res/drawable-hdpi/media_pause.png b/res/drawable-hdpi/media_pause.png
deleted file mode 100644
index d4cab525..00000000
--- a/res/drawable-hdpi/media_pause.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/media_pause_dark.png b/res/drawable-hdpi/media_pause_dark.png
new file mode 100644
index 00000000..b057588e
--- /dev/null
+++ b/res/drawable-hdpi/media_pause_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/media_pause_light.png b/res/drawable-hdpi/media_pause_light.png
index 8ebf9b45..e01815e3 100644
--- a/res/drawable-hdpi/media_pause_light.png
+++ b/res/drawable-hdpi/media_pause_light.png
Binary files differ
diff --git a/res/drawable-hdpi/media_start.png b/res/drawable-hdpi/media_start.png
deleted file mode 100644
index 2af5996f..00000000
--- a/res/drawable-hdpi/media_start.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/media_start_dark.png b/res/drawable-hdpi/media_start_dark.png
new file mode 100644
index 00000000..dbfd337a
--- /dev/null
+++ b/res/drawable-hdpi/media_start_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/media_start_light.png b/res/drawable-hdpi/media_start_light.png
index 45cad73c..e4310efc 100644
--- a/res/drawable-hdpi/media_start_light.png
+++ b/res/drawable-hdpi/media_start_light.png
Binary files differ
diff --git a/res/drawable-hdpi/media_stop.png b/res/drawable-hdpi/media_stop.png
deleted file mode 100644
index 329eb906..00000000
--- a/res/drawable-hdpi/media_stop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/media_stop_dark.png b/res/drawable-hdpi/media_stop_dark.png
new file mode 100644
index 00000000..5ceb39f3
--- /dev/null
+++ b/res/drawable-hdpi/media_stop_dark.png
Binary files differ
diff --git a/res/drawable-hdpi/media_stop_light.png b/res/drawable-hdpi/media_stop_light.png
index 110d538e..8deca73e 100644
--- a/res/drawable-hdpi/media_stop_light.png
+++ b/res/drawable-hdpi/media_stop_light.png
Binary files differ
diff --git a/res/drawable-hdpi/menu_browse.png b/res/drawable-hdpi/menu_browse.png
deleted file mode 100644
index 54296909..00000000
--- a/res/drawable-hdpi/menu_browse.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/menu_home.png b/res/drawable-hdpi/menu_home.png
deleted file mode 100644
index 3cec6246..00000000
--- a/res/drawable-hdpi/menu_home.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/menu_now_playing.png b/res/drawable-hdpi/menu_now_playing.png
deleted file mode 100644
index 6ce5629a..00000000
--- a/res/drawable-hdpi/menu_now_playing.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/menu_playlists.png b/res/drawable-hdpi/menu_playlists.png
deleted file mode 100644
index e9e83e3d..00000000
--- a/res/drawable-hdpi/menu_playlists.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/notification_close.png b/res/drawable-hdpi/notification_close.png
new file mode 100644
index 00000000..916c9a0f
--- /dev/null
+++ b/res/drawable-hdpi/notification_close.png
Binary files differ
diff --git a/res/drawable-hdpi/notification_next.png b/res/drawable-hdpi/notification_next.png
index 5835f654..078c310f 100644
--- a/res/drawable-hdpi/notification_next.png
+++ b/res/drawable-hdpi/notification_next.png
Binary files differ
diff --git a/res/drawable-hdpi/notification_pause.png b/res/drawable-hdpi/notification_pause.png
index 3324f88f..16627e44 100644
--- a/res/drawable-hdpi/notification_pause.png
+++ b/res/drawable-hdpi/notification_pause.png
Binary files differ
diff --git a/res/drawable-hdpi/notification_play.png b/res/drawable-hdpi/notification_play.png
index 8c95b6a5..02f38944 100644
--- a/res/drawable-hdpi/notification_play.png
+++ b/res/drawable-hdpi/notification_play.png
Binary files differ
diff --git a/res/drawable-hdpi/notification_prev.png b/res/drawable-hdpi/notification_prev.png
deleted file mode 100644
index 73fb16f2..00000000
--- a/res/drawable-hdpi/notification_prev.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/notification_previous.png b/res/drawable-hdpi/notification_previous.png
new file mode 100644
index 00000000..9d10abd9
--- /dev/null
+++ b/res/drawable-hdpi/notification_previous.png
Binary files differ
diff --git a/res/drawable-hdpi/notification_stop.png b/res/drawable-hdpi/notification_stop.png
deleted file mode 100644
index ab98e188..00000000
--- a/res/drawable-hdpi/notification_stop.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/now_playing.png b/res/drawable-hdpi/now_playing.png
new file mode 100644
index 00000000..02f38944
--- /dev/null
+++ b/res/drawable-hdpi/now_playing.png
Binary files differ
diff --git a/res/drawable-hdpi/refresh.png b/res/drawable-hdpi/refresh.png
deleted file mode 100644
index 2f887c26..00000000
--- a/res/drawable-hdpi/refresh.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/search.png b/res/drawable-hdpi/search.png
deleted file mode 100644
index 43d8c87e..00000000
--- a/res/drawable-hdpi/search.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-hdpi/stat_notify_download.png b/res/drawable-hdpi/stat_notify_download.png
new file mode 100644
index 00000000..aa1b6c92
--- /dev/null
+++ b/res/drawable-hdpi/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-hdpi/stat_notify_playing.png b/res/drawable-hdpi/stat_notify_playing.png
index bfd3e6a5..02f38944 100644
--- a/res/drawable-hdpi/stat_notify_playing.png
+++ b/res/drawable-hdpi/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-hdpi/volume.png b/res/drawable-hdpi/volume.png
deleted file mode 100644
index 95134dfd..00000000
--- a/res/drawable-hdpi/volume.png
+++ /dev/null
Binary files differ
diff --git a/res/drawable-mdpi-v11/notification_close.png b/res/drawable-mdpi-v11/notification_close.png
new file mode 100644
index 00000000..a056fe61
--- /dev/null
+++ b/res/drawable-mdpi-v11/notification_close.png
Binary files differ
diff --git a/res/drawable-mdpi-v11/notification_next.png b/res/drawable-mdpi-v11/notification_next.png
new file mode 100644
index 00000000..7297577f
--- /dev/null
+++ b/res/drawable-mdpi-v11/notification_next.png
Binary files differ
diff --git a/res/drawable-mdpi-v11/notification_pause.png b/res/drawable-mdpi-v11/notification_pause.png
new file mode 100644
index 00000000..5d3ca3f2
--- /dev/null
+++ b/res/drawable-mdpi-v11/notification_pause.png
Binary files differ
diff --git a/res/drawable-mdpi-v11/notification_play.png b/res/drawable-mdpi-v11/notification_play.png
new file mode 100644
index 00000000..999ce798
--- /dev/null
+++ b/res/drawable-mdpi-v11/notification_play.png
Binary files differ
diff --git a/res/drawable-mdpi-v11/notification_previous.png b/res/drawable-mdpi-v11/notification_previous.png
new file mode 100644
index 00000000..55a1f326
--- /dev/null
+++ b/res/drawable-mdpi-v11/notification_previous.png
Binary files differ
diff --git a/res/drawable-mdpi-v11/stat_notify_download.png b/res/drawable-mdpi-v11/stat_notify_download.png
new file mode 100644
index 00000000..4164e0fa
--- /dev/null
+++ b/res/drawable-mdpi-v11/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-mdpi-v11/stat_notify_playing.png b/res/drawable-mdpi-v11/stat_notify_playing.png
new file mode 100644
index 00000000..999ce798
--- /dev/null
+++ b/res/drawable-mdpi-v11/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-mdpi/action_toggle_list_dark.png b/res/drawable-mdpi/action_toggle_list_dark.png
new file mode 100644
index 00000000..ace7fcee
--- /dev/null
+++ b/res/drawable-mdpi/action_toggle_list_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/action_toggle_list_light.png b/res/drawable-mdpi/action_toggle_list_light.png
new file mode 100644
index 00000000..fa6432da
--- /dev/null
+++ b/res/drawable-mdpi/action_toggle_list_light.png
Binary files differ
diff --git a/res/drawable-mdpi/download_cached.png b/res/drawable-mdpi/download_cached.png
new file mode 100644
index 00000000..fa02cc7c
--- /dev/null
+++ b/res/drawable-mdpi/download_cached.png
Binary files differ
diff --git a/res/drawable-mdpi/download_none_dark.png b/res/drawable-mdpi/download_none_dark.png
new file mode 100644
index 00000000..b6d614fc
--- /dev/null
+++ b/res/drawable-mdpi/download_none_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/download_none_light.png b/res/drawable-mdpi/download_none_light.png
new file mode 100644
index 00000000..2485c570
--- /dev/null
+++ b/res/drawable-mdpi/download_none_light.png
Binary files differ
diff --git a/res/drawable-mdpi/download_pinned.png b/res/drawable-mdpi/download_pinned.png
new file mode 100644
index 00000000..8e6e8e7a
--- /dev/null
+++ b/res/drawable-mdpi/download_pinned.png
Binary files differ
diff --git a/res/drawable-mdpi/downloading_dark.png b/res/drawable-mdpi/downloading_dark.png
new file mode 100644
index 00000000..ae6c5c9c
--- /dev/null
+++ b/res/drawable-mdpi/downloading_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/downloading_light.png b/res/drawable-mdpi/downloading_light.png
new file mode 100644
index 00000000..abd5b748
--- /dev/null
+++ b/res/drawable-mdpi/downloading_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_volume_dark.png b/res/drawable-mdpi/ic_action_volume_dark.png
new file mode 100644
index 00000000..2b5f1d11
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_volume_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_action_volume_light.png b/res/drawable-mdpi/ic_action_volume_light.png
new file mode 100644
index 00000000..47071ccf
--- /dev/null
+++ b/res/drawable-mdpi/ic_action_volume_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_drawer.png b/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 00000000..1ed2c56e
--- /dev/null
+++ b/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_bookmark_dark.png b/res/drawable-mdpi/ic_menu_bookmark_dark.png
new file mode 100644
index 00000000..3360f37e
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_bookmark_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_bookmark_light.png b/res/drawable-mdpi/ic_menu_bookmark_light.png
new file mode 100644
index 00000000..b4d916fb
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_bookmark_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_chat_dark.png b/res/drawable-mdpi/ic_menu_chat_dark.png
new file mode 100644
index 00000000..74d98888
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_chat_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_chat_light.png b/res/drawable-mdpi/ic_menu_chat_light.png
new file mode 100644
index 00000000..468c1220
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_chat_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_chat_send_dark.png b/res/drawable-mdpi/ic_menu_chat_send_dark.png
new file mode 100644
index 00000000..91db4a4a
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_chat_send_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_chat_send_light.png b/res/drawable-mdpi/ic_menu_chat_send_light.png
new file mode 100644
index 00000000..f2a3e724
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_chat_send_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_library_dark.png b/res/drawable-mdpi/ic_menu_library_dark.png
new file mode 100644
index 00000000..0102d7ad
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_library_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_library_light.png b/res/drawable-mdpi/ic_menu_library_light.png
new file mode 100644
index 00000000..a30b4d39
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_library_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_playlist_dark.png b/res/drawable-mdpi/ic_menu_playlist_dark.png
new file mode 100644
index 00000000..ebf00427
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_playlist_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_playlist_light.png b/res/drawable-mdpi/ic_menu_playlist_light.png
new file mode 100644
index 00000000..e248a488
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_playlist_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_podcast_dark.png b/res/drawable-mdpi/ic_menu_podcast_dark.png
new file mode 100644
index 00000000..ad69156a
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_podcast_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_podcast_light.png b/res/drawable-mdpi/ic_menu_podcast_light.png
new file mode 100644
index 00000000..c15cb03f
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_podcast_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_refresh_dark.png b/res/drawable-mdpi/ic_menu_refresh_dark.png
new file mode 100644
index 00000000..554c07dc
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_refresh_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_refresh_light.png b/res/drawable-mdpi/ic_menu_refresh_light.png
new file mode 100644
index 00000000..a2d90c16
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_refresh_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_remove_dark.png b/res/drawable-mdpi/ic_menu_remove_dark.png
new file mode 100644
index 00000000..5ba24546
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_remove_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_remove_light.png b/res/drawable-mdpi/ic_menu_remove_light.png
new file mode 100644
index 00000000..93483b6c
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_remove_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_save_dark.png b/res/drawable-mdpi/ic_menu_save_dark.png
new file mode 100644
index 00000000..89aa17cc
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_save_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_save_light.png b/res/drawable-mdpi/ic_menu_save_light.png
new file mode 100644
index 00000000..dcb3a2f6
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_save_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_search_dark.png b/res/drawable-mdpi/ic_menu_search_dark.png
new file mode 100644
index 00000000..076085c5
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_search_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_search_light.png b/res/drawable-mdpi/ic_menu_search_light.png
new file mode 100644
index 00000000..026c8498
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_search_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_settings_dark.png b/res/drawable-mdpi/ic_menu_settings_dark.png
new file mode 100644
index 00000000..fc2bf8c3
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_settings_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_settings_light.png b/res/drawable-mdpi/ic_menu_settings_light.png
new file mode 100644
index 00000000..0e65c682
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_settings_light.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_shuffle_dark.png b/res/drawable-mdpi/ic_menu_shuffle_dark.png
new file mode 100644
index 00000000..7007fde5
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_shuffle_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_shuffle_light.png b/res/drawable-mdpi/ic_menu_shuffle_light.png
new file mode 100644
index 00000000..4d07c3b4
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_shuffle_light.png
Binary files differ
diff --git a/res/drawable-mdpi/launch.png b/res/drawable-mdpi/launch.png
index c07fc594..22e094eb 100644
--- a/res/drawable-mdpi/launch.png
+++ b/res/drawable-mdpi/launch.png
Binary files differ
diff --git a/res/drawable-mdpi/main_offline_dark.png b/res/drawable-mdpi/main_offline_dark.png
new file mode 100644
index 00000000..4990fb8e
--- /dev/null
+++ b/res/drawable-mdpi/main_offline_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/main_offline_light.png b/res/drawable-mdpi/main_offline_light.png
new file mode 100644
index 00000000..e70ec1c2
--- /dev/null
+++ b/res/drawable-mdpi/main_offline_light.png
Binary files differ
diff --git a/res/drawable-mdpi/main_select_server_dark.png b/res/drawable-mdpi/main_select_server_dark.png
new file mode 100644
index 00000000..119b1573
--- /dev/null
+++ b/res/drawable-mdpi/main_select_server_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/main_select_server_light.png b/res/drawable-mdpi/main_select_server_light.png
new file mode 100644
index 00000000..7d8dad34
--- /dev/null
+++ b/res/drawable-mdpi/main_select_server_light.png
Binary files differ
diff --git a/res/drawable-mdpi/media_backward_dark.png b/res/drawable-mdpi/media_backward_dark.png
new file mode 100644
index 00000000..4f2233a1
--- /dev/null
+++ b/res/drawable-mdpi/media_backward_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/media_backward_light.png b/res/drawable-mdpi/media_backward_light.png
new file mode 100644
index 00000000..425f2df7
--- /dev/null
+++ b/res/drawable-mdpi/media_backward_light.png
Binary files differ
diff --git a/res/drawable-mdpi/media_forward_dark.png b/res/drawable-mdpi/media_forward_dark.png
new file mode 100644
index 00000000..1641c0fa
--- /dev/null
+++ b/res/drawable-mdpi/media_forward_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/media_forward_light.png b/res/drawable-mdpi/media_forward_light.png
new file mode 100644
index 00000000..2e66868f
--- /dev/null
+++ b/res/drawable-mdpi/media_forward_light.png
Binary files differ
diff --git a/res/drawable-mdpi/media_pause_dark.png b/res/drawable-mdpi/media_pause_dark.png
new file mode 100644
index 00000000..3580dab4
--- /dev/null
+++ b/res/drawable-mdpi/media_pause_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/media_pause_light.png b/res/drawable-mdpi/media_pause_light.png
new file mode 100644
index 00000000..7e9ade73
--- /dev/null
+++ b/res/drawable-mdpi/media_pause_light.png
Binary files differ
diff --git a/res/drawable-mdpi/media_start_dark.png b/res/drawable-mdpi/media_start_dark.png
new file mode 100644
index 00000000..a2f198ae
--- /dev/null
+++ b/res/drawable-mdpi/media_start_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/media_start_light.png b/res/drawable-mdpi/media_start_light.png
new file mode 100644
index 00000000..d69107ba
--- /dev/null
+++ b/res/drawable-mdpi/media_start_light.png
Binary files differ
diff --git a/res/drawable-mdpi/media_stop_dark.png b/res/drawable-mdpi/media_stop_dark.png
new file mode 100644
index 00000000..944482e6
--- /dev/null
+++ b/res/drawable-mdpi/media_stop_dark.png
Binary files differ
diff --git a/res/drawable-mdpi/media_stop_light.png b/res/drawable-mdpi/media_stop_light.png
new file mode 100644
index 00000000..ff1932a1
--- /dev/null
+++ b/res/drawable-mdpi/media_stop_light.png
Binary files differ
diff --git a/res/drawable-mdpi/notification_close.png b/res/drawable-mdpi/notification_close.png
new file mode 100644
index 00000000..2a8f9a36
--- /dev/null
+++ b/res/drawable-mdpi/notification_close.png
Binary files differ
diff --git a/res/drawable-mdpi/notification_next.png b/res/drawable-mdpi/notification_next.png
new file mode 100644
index 00000000..f85d45a5
--- /dev/null
+++ b/res/drawable-mdpi/notification_next.png
Binary files differ
diff --git a/res/drawable-mdpi/notification_pause.png b/res/drawable-mdpi/notification_pause.png
new file mode 100644
index 00000000..06c3cf9d
--- /dev/null
+++ b/res/drawable-mdpi/notification_pause.png
Binary files differ
diff --git a/res/drawable-mdpi/notification_play.png b/res/drawable-mdpi/notification_play.png
new file mode 100644
index 00000000..0248c1cc
--- /dev/null
+++ b/res/drawable-mdpi/notification_play.png
Binary files differ
diff --git a/res/drawable-mdpi/notification_previous.png b/res/drawable-mdpi/notification_previous.png
new file mode 100644
index 00000000..167d7d05
--- /dev/null
+++ b/res/drawable-mdpi/notification_previous.png
Binary files differ
diff --git a/res/drawable-mdpi/now_playing.png b/res/drawable-mdpi/now_playing.png
new file mode 100644
index 00000000..0248c1cc
--- /dev/null
+++ b/res/drawable-mdpi/now_playing.png
Binary files differ
diff --git a/res/drawable-mdpi/stat_notify_download.png b/res/drawable-mdpi/stat_notify_download.png
new file mode 100644
index 00000000..4c2a22de
--- /dev/null
+++ b/res/drawable-mdpi/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-mdpi/stat_notify_playing.png b/res/drawable-mdpi/stat_notify_playing.png
new file mode 100644
index 00000000..0248c1cc
--- /dev/null
+++ b/res/drawable-mdpi/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/notification_close.png b/res/drawable-xhdpi-v11/notification_close.png
new file mode 100644
index 00000000..f1013578
--- /dev/null
+++ b/res/drawable-xhdpi-v11/notification_close.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/notification_next.png b/res/drawable-xhdpi-v11/notification_next.png
new file mode 100644
index 00000000..ad070680
--- /dev/null
+++ b/res/drawable-xhdpi-v11/notification_next.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/notification_pause.png b/res/drawable-xhdpi-v11/notification_pause.png
new file mode 100644
index 00000000..709602aa
--- /dev/null
+++ b/res/drawable-xhdpi-v11/notification_pause.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/notification_play.png b/res/drawable-xhdpi-v11/notification_play.png
new file mode 100644
index 00000000..e2bafa6a
--- /dev/null
+++ b/res/drawable-xhdpi-v11/notification_play.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/notification_previous.png b/res/drawable-xhdpi-v11/notification_previous.png
new file mode 100644
index 00000000..d22488cb
--- /dev/null
+++ b/res/drawable-xhdpi-v11/notification_previous.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/stat_notify_download.png b/res/drawable-xhdpi-v11/stat_notify_download.png
new file mode 100644
index 00000000..96ceb383
--- /dev/null
+++ b/res/drawable-xhdpi-v11/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-xhdpi-v11/stat_notify_playing.png b/res/drawable-xhdpi-v11/stat_notify_playing.png
new file mode 100644
index 00000000..e2bafa6a
--- /dev/null
+++ b/res/drawable-xhdpi-v11/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-xhdpi/action_toggle_list_dark.png b/res/drawable-xhdpi/action_toggle_list_dark.png
new file mode 100644
index 00000000..92003c6b
--- /dev/null
+++ b/res/drawable-xhdpi/action_toggle_list_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/action_toggle_list_light.png b/res/drawable-xhdpi/action_toggle_list_light.png
new file mode 100644
index 00000000..a4007ea5
--- /dev/null
+++ b/res/drawable-xhdpi/action_toggle_list_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/download_cached.png b/res/drawable-xhdpi/download_cached.png
new file mode 100644
index 00000000..1ef7c805
--- /dev/null
+++ b/res/drawable-xhdpi/download_cached.png
Binary files differ
diff --git a/res/drawable-xhdpi/download_none_dark.png b/res/drawable-xhdpi/download_none_dark.png
new file mode 100644
index 00000000..7be3c2a4
--- /dev/null
+++ b/res/drawable-xhdpi/download_none_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/download_none_light.png b/res/drawable-xhdpi/download_none_light.png
new file mode 100644
index 00000000..817651d7
--- /dev/null
+++ b/res/drawable-xhdpi/download_none_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/download_pinned.png b/res/drawable-xhdpi/download_pinned.png
new file mode 100644
index 00000000..09eb6ffb
--- /dev/null
+++ b/res/drawable-xhdpi/download_pinned.png
Binary files differ
diff --git a/res/drawable-xhdpi/downloading_dark.png b/res/drawable-xhdpi/downloading_dark.png
new file mode 100644
index 00000000..3f14bdf4
--- /dev/null
+++ b/res/drawable-xhdpi/downloading_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/downloading_light.png b/res/drawable-xhdpi/downloading_light.png
new file mode 100644
index 00000000..643c15d0
--- /dev/null
+++ b/res/drawable-xhdpi/downloading_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_volume_dark.png b/res/drawable-xhdpi/ic_action_volume_dark.png
new file mode 100644
index 00000000..400de38b
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_volume_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_action_volume_light.png b/res/drawable-xhdpi/ic_action_volume_light.png
new file mode 100644
index 00000000..9a1128c1
--- /dev/null
+++ b/res/drawable-xhdpi/ic_action_volume_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_drawer.png b/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 00000000..a5fa74de
--- /dev/null
+++ b/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_bookmark_dark.png b/res/drawable-xhdpi/ic_menu_bookmark_dark.png
new file mode 100644
index 00000000..18f71365
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_bookmark_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_bookmark_light.png b/res/drawable-xhdpi/ic_menu_bookmark_light.png
new file mode 100644
index 00000000..d5776317
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_bookmark_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_chat_dark.png b/res/drawable-xhdpi/ic_menu_chat_dark.png
new file mode 100644
index 00000000..28318219
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_chat_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_chat_light.png b/res/drawable-xhdpi/ic_menu_chat_light.png
new file mode 100644
index 00000000..dcc95dcb
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_chat_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_chat_send_dark.png b/res/drawable-xhdpi/ic_menu_chat_send_dark.png
new file mode 100644
index 00000000..c0a5a3eb
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_chat_send_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_chat_send_light.png b/res/drawable-xhdpi/ic_menu_chat_send_light.png
new file mode 100644
index 00000000..f9c3b9bb
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_chat_send_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_library_dark.png b/res/drawable-xhdpi/ic_menu_library_dark.png
new file mode 100644
index 00000000..b1612f65
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_library_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_library_light.png b/res/drawable-xhdpi/ic_menu_library_light.png
new file mode 100644
index 00000000..1f93c8f2
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_library_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_playlist_dark.png b/res/drawable-xhdpi/ic_menu_playlist_dark.png
new file mode 100644
index 00000000..fd6cd498
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_playlist_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_playlist_light.png b/res/drawable-xhdpi/ic_menu_playlist_light.png
new file mode 100644
index 00000000..e7e510d0
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_playlist_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_podcast_dark.png b/res/drawable-xhdpi/ic_menu_podcast_dark.png
new file mode 100644
index 00000000..40469b46
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_podcast_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_podcast_light.png b/res/drawable-xhdpi/ic_menu_podcast_light.png
new file mode 100644
index 00000000..3748526a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_podcast_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_refresh_dark.png b/res/drawable-xhdpi/ic_menu_refresh_dark.png
new file mode 100644
index 00000000..b6801006
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_refresh_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_refresh_light.png b/res/drawable-xhdpi/ic_menu_refresh_light.png
new file mode 100644
index 00000000..38943f82
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_refresh_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_remove_dark.png b/res/drawable-xhdpi/ic_menu_remove_dark.png
new file mode 100644
index 00000000..09ce75e2
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_remove_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_remove_light.png b/res/drawable-xhdpi/ic_menu_remove_light.png
new file mode 100644
index 00000000..94f7c8c1
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_remove_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_save_dark.png b/res/drawable-xhdpi/ic_menu_save_dark.png
new file mode 100644
index 00000000..1612fd0a
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_save_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_save_light.png b/res/drawable-xhdpi/ic_menu_save_light.png
new file mode 100644
index 00000000..5dcd75d7
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_save_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_search_dark.png b/res/drawable-xhdpi/ic_menu_search_dark.png
new file mode 100644
index 00000000..1ae3dff0
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_search_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_search_light.png b/res/drawable-xhdpi/ic_menu_search_light.png
new file mode 100644
index 00000000..705074bd
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_search_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_settings_dark.png b/res/drawable-xhdpi/ic_menu_settings_dark.png
new file mode 100644
index 00000000..ae917587
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_settings_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_settings_light.png b/res/drawable-xhdpi/ic_menu_settings_light.png
new file mode 100644
index 00000000..29f961b2
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_settings_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_shuffle_dark.png b/res/drawable-xhdpi/ic_menu_shuffle_dark.png
new file mode 100644
index 00000000..e3a31a84
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_shuffle_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_shuffle_light.png b/res/drawable-xhdpi/ic_menu_shuffle_light.png
new file mode 100644
index 00000000..14eb942c
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_shuffle_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/launch.png b/res/drawable-xhdpi/launch.png
index b9379f27..f73729d0 100644
--- a/res/drawable-xhdpi/launch.png
+++ b/res/drawable-xhdpi/launch.png
Binary files differ
diff --git a/res/drawable-xhdpi/main_offline_dark.png b/res/drawable-xhdpi/main_offline_dark.png
new file mode 100644
index 00000000..231e4715
--- /dev/null
+++ b/res/drawable-xhdpi/main_offline_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/main_offline_light.png b/res/drawable-xhdpi/main_offline_light.png
new file mode 100644
index 00000000..87937fcb
--- /dev/null
+++ b/res/drawable-xhdpi/main_offline_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/main_select_server_dark.png b/res/drawable-xhdpi/main_select_server_dark.png
new file mode 100644
index 00000000..b84f1851
--- /dev/null
+++ b/res/drawable-xhdpi/main_select_server_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/main_select_server_light.png b/res/drawable-xhdpi/main_select_server_light.png
new file mode 100644
index 00000000..ee154cc7
--- /dev/null
+++ b/res/drawable-xhdpi/main_select_server_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_backward_dark.png b/res/drawable-xhdpi/media_backward_dark.png
new file mode 100644
index 00000000..3c9921a8
--- /dev/null
+++ b/res/drawable-xhdpi/media_backward_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_backward_light.png b/res/drawable-xhdpi/media_backward_light.png
new file mode 100644
index 00000000..aafd76fa
--- /dev/null
+++ b/res/drawable-xhdpi/media_backward_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_forward_dark.png b/res/drawable-xhdpi/media_forward_dark.png
new file mode 100644
index 00000000..b082b3a6
--- /dev/null
+++ b/res/drawable-xhdpi/media_forward_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_forward_light.png b/res/drawable-xhdpi/media_forward_light.png
new file mode 100644
index 00000000..20772843
--- /dev/null
+++ b/res/drawable-xhdpi/media_forward_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_pause_dark.png b/res/drawable-xhdpi/media_pause_dark.png
new file mode 100644
index 00000000..aafdd4aa
--- /dev/null
+++ b/res/drawable-xhdpi/media_pause_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_pause_light.png b/res/drawable-xhdpi/media_pause_light.png
new file mode 100644
index 00000000..2639777d
--- /dev/null
+++ b/res/drawable-xhdpi/media_pause_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_start_dark.png b/res/drawable-xhdpi/media_start_dark.png
new file mode 100644
index 00000000..9e63c90b
--- /dev/null
+++ b/res/drawable-xhdpi/media_start_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_start_light.png b/res/drawable-xhdpi/media_start_light.png
new file mode 100644
index 00000000..2ff8c399
--- /dev/null
+++ b/res/drawable-xhdpi/media_start_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_stop_dark.png b/res/drawable-xhdpi/media_stop_dark.png
new file mode 100644
index 00000000..9cb32909
--- /dev/null
+++ b/res/drawable-xhdpi/media_stop_dark.png
Binary files differ
diff --git a/res/drawable-xhdpi/media_stop_light.png b/res/drawable-xhdpi/media_stop_light.png
new file mode 100644
index 00000000..edf13ccf
--- /dev/null
+++ b/res/drawable-xhdpi/media_stop_light.png
Binary files differ
diff --git a/res/drawable-xhdpi/notification_close.png b/res/drawable-xhdpi/notification_close.png
new file mode 100644
index 00000000..4230842e
--- /dev/null
+++ b/res/drawable-xhdpi/notification_close.png
Binary files differ
diff --git a/res/drawable-xhdpi/notification_next.png b/res/drawable-xhdpi/notification_next.png
new file mode 100644
index 00000000..44dbbd12
--- /dev/null
+++ b/res/drawable-xhdpi/notification_next.png
Binary files differ
diff --git a/res/drawable-xhdpi/notification_pause.png b/res/drawable-xhdpi/notification_pause.png
new file mode 100644
index 00000000..e8d8c535
--- /dev/null
+++ b/res/drawable-xhdpi/notification_pause.png
Binary files differ
diff --git a/res/drawable-xhdpi/notification_play.png b/res/drawable-xhdpi/notification_play.png
new file mode 100644
index 00000000..532041fa
--- /dev/null
+++ b/res/drawable-xhdpi/notification_play.png
Binary files differ
diff --git a/res/drawable-xhdpi/notification_previous.png b/res/drawable-xhdpi/notification_previous.png
new file mode 100644
index 00000000..87ee8d2f
--- /dev/null
+++ b/res/drawable-xhdpi/notification_previous.png
Binary files differ
diff --git a/res/drawable-xhdpi/now_playing.png b/res/drawable-xhdpi/now_playing.png
new file mode 100644
index 00000000..532041fa
--- /dev/null
+++ b/res/drawable-xhdpi/now_playing.png
Binary files differ
diff --git a/res/drawable-xhdpi/stat_notify_download.png b/res/drawable-xhdpi/stat_notify_download.png
new file mode 100644
index 00000000..bd4cb567
--- /dev/null
+++ b/res/drawable-xhdpi/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-xhdpi/stat_notify_playing.png b/res/drawable-xhdpi/stat_notify_playing.png
new file mode 100644
index 00000000..532041fa
--- /dev/null
+++ b/res/drawable-xhdpi/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/notification_close.png b/res/drawable-xxhdpi-v11/notification_close.png
new file mode 100644
index 00000000..c3ac026a
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/notification_close.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/notification_next.png b/res/drawable-xxhdpi-v11/notification_next.png
new file mode 100644
index 00000000..06911082
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/notification_next.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/notification_pause.png b/res/drawable-xxhdpi-v11/notification_pause.png
new file mode 100644
index 00000000..1513f9d9
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/notification_pause.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/notification_play.png b/res/drawable-xxhdpi-v11/notification_play.png
new file mode 100644
index 00000000..9138a760
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/notification_play.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/notification_previous.png b/res/drawable-xxhdpi-v11/notification_previous.png
new file mode 100644
index 00000000..b4456c16
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/notification_previous.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/stat_notify_download.png b/res/drawable-xxhdpi-v11/stat_notify_download.png
new file mode 100644
index 00000000..b2dc5651
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-xxhdpi-v11/stat_notify_playing.png b/res/drawable-xxhdpi-v11/stat_notify_playing.png
new file mode 100644
index 00000000..9138a760
--- /dev/null
+++ b/res/drawable-xxhdpi-v11/stat_notify_playing.png
Binary files differ
diff --git a/res/drawable-xxhdpi/action_toggle_list_dark.png b/res/drawable-xxhdpi/action_toggle_list_dark.png
new file mode 100644
index 00000000..598fc312
--- /dev/null
+++ b/res/drawable-xxhdpi/action_toggle_list_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/action_toggle_list_light.png b/res/drawable-xxhdpi/action_toggle_list_light.png
new file mode 100644
index 00000000..ceb3fade
--- /dev/null
+++ b/res/drawable-xxhdpi/action_toggle_list_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/download_none_dark.png b/res/drawable-xxhdpi/download_none_dark.png
new file mode 100644
index 00000000..a0cb8a41
--- /dev/null
+++ b/res/drawable-xxhdpi/download_none_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/download_none_light.png b/res/drawable-xxhdpi/download_none_light.png
new file mode 100644
index 00000000..7a1639ef
--- /dev/null
+++ b/res/drawable-xxhdpi/download_none_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/downloading_dark.png b/res/drawable-xxhdpi/downloading_dark.png
new file mode 100644
index 00000000..afc4bf84
--- /dev/null
+++ b/res/drawable-xxhdpi/downloading_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/downloading_light.png b/res/drawable-xxhdpi/downloading_light.png
new file mode 100644
index 00000000..ba31a979
--- /dev/null
+++ b/res/drawable-xxhdpi/downloading_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_volume_dark.png b/res/drawable-xxhdpi/ic_action_volume_dark.png
new file mode 100644
index 00000000..7991a65d
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_volume_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_action_volume_light.png b/res/drawable-xxhdpi/ic_action_volume_light.png
new file mode 100644
index 00000000..8dfbf3f5
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_action_volume_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_drawer.png b/res/drawable-xxhdpi/ic_drawer.png
new file mode 100644
index 00000000..9c4685d6
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_drawer.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_bookmark_dark.png b/res/drawable-xxhdpi/ic_menu_bookmark_dark.png
new file mode 100644
index 00000000..2523e14c
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_bookmark_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_bookmark_light.png b/res/drawable-xxhdpi/ic_menu_bookmark_light.png
new file mode 100644
index 00000000..9e8c4591
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_bookmark_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_chat_dark.png b/res/drawable-xxhdpi/ic_menu_chat_dark.png
new file mode 100644
index 00000000..60efb47d
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_chat_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_chat_light.png b/res/drawable-xxhdpi/ic_menu_chat_light.png
new file mode 100644
index 00000000..02c89560
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_chat_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_chat_send_dark.png b/res/drawable-xxhdpi/ic_menu_chat_send_dark.png
new file mode 100644
index 00000000..b86ca3d3
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_chat_send_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_chat_send_light.png b/res/drawable-xxhdpi/ic_menu_chat_send_light.png
new file mode 100644
index 00000000..048b8aac
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_chat_send_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_library_dark.png b/res/drawable-xxhdpi/ic_menu_library_dark.png
new file mode 100644
index 00000000..02a4f3f2
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_library_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_library_light.png b/res/drawable-xxhdpi/ic_menu_library_light.png
new file mode 100644
index 00000000..52ce8203
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_library_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_playlist_dark.png b/res/drawable-xxhdpi/ic_menu_playlist_dark.png
new file mode 100644
index 00000000..2c955eee
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_playlist_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_playlist_light.png b/res/drawable-xxhdpi/ic_menu_playlist_light.png
new file mode 100644
index 00000000..d1877328
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_playlist_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_podcast_dark.png b/res/drawable-xxhdpi/ic_menu_podcast_dark.png
new file mode 100644
index 00000000..a748dc60
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_podcast_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_podcast_light.png b/res/drawable-xxhdpi/ic_menu_podcast_light.png
new file mode 100644
index 00000000..efa7b037
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_podcast_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_refresh_dark.png b/res/drawable-xxhdpi/ic_menu_refresh_dark.png
new file mode 100644
index 00000000..0e5616bd
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_refresh_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_refresh_light.png b/res/drawable-xxhdpi/ic_menu_refresh_light.png
new file mode 100644
index 00000000..7dea70df
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_refresh_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_remove_dark.png b/res/drawable-xxhdpi/ic_menu_remove_dark.png
new file mode 100644
index 00000000..d5952ea0
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_remove_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_remove_light.png b/res/drawable-xxhdpi/ic_menu_remove_light.png
new file mode 100644
index 00000000..c814869e
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_remove_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_save_dark.png b/res/drawable-xxhdpi/ic_menu_save_dark.png
new file mode 100644
index 00000000..acb264ec
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_save_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_save_light.png b/res/drawable-xxhdpi/ic_menu_save_light.png
new file mode 100644
index 00000000..fcd18ccd
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_save_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_search_dark.png b/res/drawable-xxhdpi/ic_menu_search_dark.png
new file mode 100644
index 00000000..500ac03a
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_search_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_search_light.png b/res/drawable-xxhdpi/ic_menu_search_light.png
new file mode 100644
index 00000000..fa64f9e8
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_search_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_settings_dark.png b/res/drawable-xxhdpi/ic_menu_settings_dark.png
new file mode 100644
index 00000000..ded5dbb5
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_settings_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_settings_light.png b/res/drawable-xxhdpi/ic_menu_settings_light.png
new file mode 100644
index 00000000..cd242306
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_settings_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_shuffle_dark.png b/res/drawable-xxhdpi/ic_menu_shuffle_dark.png
new file mode 100644
index 00000000..b53733df
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_shuffle_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_shuffle_light.png b/res/drawable-xxhdpi/ic_menu_shuffle_light.png
new file mode 100644
index 00000000..4d5dff32
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_shuffle_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/launch.png b/res/drawable-xxhdpi/launch.png
index 797104fe..b067bd9f 100644
--- a/res/drawable-xxhdpi/launch.png
+++ b/res/drawable-xxhdpi/launch.png
Binary files differ
diff --git a/res/drawable-xxhdpi/main_offline_dark.png b/res/drawable-xxhdpi/main_offline_dark.png
new file mode 100644
index 00000000..c415e0a5
--- /dev/null
+++ b/res/drawable-xxhdpi/main_offline_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/main_offline_light.png b/res/drawable-xxhdpi/main_offline_light.png
new file mode 100644
index 00000000..b7e1c380
--- /dev/null
+++ b/res/drawable-xxhdpi/main_offline_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/main_select_server_dark.png b/res/drawable-xxhdpi/main_select_server_dark.png
new file mode 100644
index 00000000..b85e3a1e
--- /dev/null
+++ b/res/drawable-xxhdpi/main_select_server_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/main_select_server_light.png b/res/drawable-xxhdpi/main_select_server_light.png
new file mode 100644
index 00000000..8fc39eff
--- /dev/null
+++ b/res/drawable-xxhdpi/main_select_server_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_backward_dark.png b/res/drawable-xxhdpi/media_backward_dark.png
new file mode 100644
index 00000000..5b6c6148
--- /dev/null
+++ b/res/drawable-xxhdpi/media_backward_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_backward_light.png b/res/drawable-xxhdpi/media_backward_light.png
new file mode 100644
index 00000000..32f7d3bc
--- /dev/null
+++ b/res/drawable-xxhdpi/media_backward_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_forward_dark.png b/res/drawable-xxhdpi/media_forward_dark.png
new file mode 100644
index 00000000..ca4ee295
--- /dev/null
+++ b/res/drawable-xxhdpi/media_forward_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_forward_light.png b/res/drawable-xxhdpi/media_forward_light.png
new file mode 100644
index 00000000..208e46e9
--- /dev/null
+++ b/res/drawable-xxhdpi/media_forward_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_pause_dark.png b/res/drawable-xxhdpi/media_pause_dark.png
new file mode 100644
index 00000000..4b5aacbc
--- /dev/null
+++ b/res/drawable-xxhdpi/media_pause_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_pause_light.png b/res/drawable-xxhdpi/media_pause_light.png
new file mode 100644
index 00000000..111f6d00
--- /dev/null
+++ b/res/drawable-xxhdpi/media_pause_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_start_dark.png b/res/drawable-xxhdpi/media_start_dark.png
new file mode 100644
index 00000000..641ad544
--- /dev/null
+++ b/res/drawable-xxhdpi/media_start_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_start_light.png b/res/drawable-xxhdpi/media_start_light.png
new file mode 100644
index 00000000..a6286203
--- /dev/null
+++ b/res/drawable-xxhdpi/media_start_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_stop_dark.png b/res/drawable-xxhdpi/media_stop_dark.png
new file mode 100644
index 00000000..9a9c432a
--- /dev/null
+++ b/res/drawable-xxhdpi/media_stop_dark.png
Binary files differ
diff --git a/res/drawable-xxhdpi/media_stop_light.png b/res/drawable-xxhdpi/media_stop_light.png
new file mode 100644
index 00000000..79eb8d95
--- /dev/null
+++ b/res/drawable-xxhdpi/media_stop_light.png
Binary files differ
diff --git a/res/drawable-xxhdpi/notification_close.png b/res/drawable-xxhdpi/notification_close.png
new file mode 100644
index 00000000..022a6780
--- /dev/null
+++ b/res/drawable-xxhdpi/notification_close.png
Binary files differ
diff --git a/res/drawable-xxhdpi/notification_next.png b/res/drawable-xxhdpi/notification_next.png
new file mode 100644
index 00000000..dfe129db
--- /dev/null
+++ b/res/drawable-xxhdpi/notification_next.png
Binary files differ
diff --git a/res/drawable-xxhdpi/notification_pause.png b/res/drawable-xxhdpi/notification_pause.png
new file mode 100644
index 00000000..9c952207
--- /dev/null
+++ b/res/drawable-xxhdpi/notification_pause.png
Binary files differ
diff --git a/res/drawable-xxhdpi/notification_play.png b/res/drawable-xxhdpi/notification_play.png
new file mode 100644
index 00000000..4ee0a5eb
--- /dev/null
+++ b/res/drawable-xxhdpi/notification_play.png
Binary files differ
diff --git a/res/drawable-xxhdpi/notification_previous.png b/res/drawable-xxhdpi/notification_previous.png
new file mode 100644
index 00000000..e6908126
--- /dev/null
+++ b/res/drawable-xxhdpi/notification_previous.png
Binary files differ
diff --git a/res/drawable-xxhdpi/now_playing.png b/res/drawable-xxhdpi/now_playing.png
new file mode 100644
index 00000000..4ee0a5eb
--- /dev/null
+++ b/res/drawable-xxhdpi/now_playing.png
Binary files differ
diff --git a/res/drawable-xxhdpi/stat_notify_download.png b/res/drawable-xxhdpi/stat_notify_download.png
new file mode 100644
index 00000000..9d9a7f3e
--- /dev/null
+++ b/res/drawable-xxhdpi/stat_notify_download.png
Binary files differ
diff --git a/res/drawable-xxhdpi/stat_notify_playing.png b/res/drawable-xxhdpi/stat_notify_playing.png
new file mode 100644
index 00000000..4ee0a5eb
--- /dev/null
+++ b/res/drawable-xxhdpi/stat_notify_playing.png
Binary files differ
diff --git a/res/layout-land/download.xml b/res/layout-land/download.xml
index 5b4db35e..b896509e 100644
--- a/res/layout-land/download.xml
+++ b/res/layout-land/download.xml
@@ -40,55 +40,11 @@
android:layout_weight="1"
android:background="@android:color/transparent">
- <LinearLayout
- android:id="@+id/download_other_controls_layout"
- android:orientation="horizontal"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_horizontal">
-
- <Button
- android:id="@+id/download_jukebox"
- android:text="RC"
- android:textStyle="bold"
- android:textSize="22sp"
- android:background="@drawable/menubar_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dip"
- android:padding="9dip"/>
- <Button
- android:id="@+id/download_equalizer"
- android:text="EQ"
- android:textStyle="bold"
- android:textSize="22sp"
- android:background="@drawable/menubar_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dip"
- android:padding="9dip"/>
- <Button
- android:id="@+id/download_visualizer"
- android:text="VIS"
- android:textStyle="bold"
- android:textSize="22sp"
- android:background="@drawable/menubar_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="3dip"
- android:padding="9dip"/>
- <ImageButton
- android:id="@+id/download_star"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:background="@drawable/menubar_button"
- android:src="@android:drawable/star_big_off"
- android:padding="10dip"/>
- </LinearLayout>
+ <include layout="@layout/download_action_buttons"/>
<LinearLayout
android:id="@+id/download_visualizer_view_layout"
+ android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:layout_marginLeft="12dip"
diff --git a/res/layout-large-land/abstract_fragment_container.xml b/res/layout-large-land/abstract_fragment_container.xml
new file mode 100644
index 00000000..511d63aa
--- /dev/null
+++ b/res/layout-large-land/abstract_fragment_container.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1">
+
+ <FrameLayout
+ android:id="@+id/fragment_container"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="4"/>
+
+ <FrameLayout
+ android:id="@+id/fragment_second_container"
+ android:layout_width="0px"
+ android:layout_height="match_parent"
+ android:layout_weight="6"
+ android:visibility="gone"/>
+
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout-port/download.xml b/res/layout-port/download.xml
index 4b39286a..38ab069f 100644
--- a/res/layout-port/download.xml
+++ b/res/layout-port/download.xml
@@ -25,9 +25,8 @@
android:background="@android:color/transparent">
<RelativeLayout android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_weight="1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_above="@+id/download_song_title">
<ImageView
@@ -38,70 +37,25 @@
android:layout_alignParentTop="true"
android:scaleType="centerCrop"/>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/download_overlay_buttons"
- android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/overlayColor"
android:layout_alignParentBottom="true">
- <Button
- android:id="@+id/download_jukebox"
- android:text="RC"
- android:textStyle="bold"
- android:textSize="22sp"
- android:background="@drawable/menubar_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:paddingTop="4dip"
- android:paddingLeft="14dip"
- android:paddingBottom="4dip"/>
-
- <Button
- android:id="@+id/download_equalizer"
- android:text="EQ"
- android:textStyle="bold"
- android:textSize="22sp"
- android:background="@drawable/menubar_button"
+ <LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:paddingTop="4dip"
- android:paddingLeft="7dip"
- android:paddingRight="7dip"
- android:paddingBottom="4dip"/>
-
- <Button
- android:id="@+id/download_visualizer"
- android:text="VIS"
- android:textStyle="bold"
- android:textSize="22sp"
- android:background="@drawable/menubar_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom"
- android:paddingTop="4dip"
- android:paddingLeft="7dip"
- android:paddingRight="7dip"
- android:paddingBottom="4dip"/>
-
- <ImageButton
- android:id="@+id/download_star"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_below="@+id/download_jukebox"
- android:background="@drawable/menubar_button"
- android:src="@android:drawable/star_big_off"
- android:paddingTop="8dip"
- android:paddingLeft="10dip"
- android:paddingRight="10dip"
- android:paddingBottom="8dip"/>
- </LinearLayout>
+ android:layout_centerHorizontal="true">
+
+ <include layout="@layout/download_action_buttons"/>
+ </LinearLayout>
+ </RelativeLayout>
<LinearLayout
android:id="@+id/download_visualizer_view_layout"
+ android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="60dip"
android:layout_marginLeft="16dip"
diff --git a/res/layout/abstract_activity.xml b/res/layout/abstract_activity.xml
new file mode 100644
index 00000000..ed16c695
--- /dev/null
+++ b/res/layout/abstract_activity.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<android.support.v4.widget.DrawerLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+ <!-- The main content view -->
+ <FrameLayout
+ android:id="@+id/content_frame"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+ <!-- The navigation drawer -->
+ <ListView android:id="@+id/left_drawer"
+ android:layout_width="240dp"
+ android:layout_height="match_parent"
+ android:layout_gravity="start"
+ android:choiceMode="singleChoice"
+ android:divider="@android:color/transparent"
+ android:dividerHeight="0dp"
+ android:background="?android:windowBackground"/>
+</android.support.v4.widget.DrawerLayout> \ No newline at end of file
diff --git a/res/layout/main.xml b/res/layout/abstract_fragment_activity.xml
index f1509db6..605b988a 100644
--- a/res/layout/main.xml
+++ b/res/layout/abstract_fragment_activity.xml
@@ -1,81 +1,85 @@
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center_horizontal"
- android:orientation="vertical" >
-
- <android.support.v4.view.ViewPager
- android:id="@+id/pager"
- android:layout_width="fill_parent"
- android:layout_height="0px"
- android:layout_weight="1" >
- </android.support.v4.view.ViewPager>
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
-
- <LinearLayout
- android:id="@+id/bottom_bar"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/media_button"
- android:orientation="horizontal">
-
- <ImageView
- android:id="@+id/album_art"
- android:layout_width="50dip"
- android:layout_height="50dip"
- android:layout_gravity="left|center"
- android:scaleType="fitStart"
- android:src="@drawable/unknown_album"/>
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1"
- android:orientation="vertical"
- android:paddingLeft="8dip">
-
- <TextView
- android:id="@+id/track_name"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textColor="?android:textColorPrimary"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textSize="13sp"
- android:text="@string/search.artists"/>
-
- <TextView
- android:id="@+id/artist_name"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:textColor="?android:textColorSecondary"
- android:singleLine="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textSize="12sp"
- android:text="@string/search.albums"/>
- </LinearLayout>
-
- <ImageButton
- style="@style/PlaybackControl.Small"
- android:id="@+id/download_previous"
- android:src="?attr/media_button_backward"
- android:layout_centerVertical="true"/>
-
- <ImageButton
- style="@style/PlaybackControl.Small"
- android:id="@+id/download_start"
- android:src="?attr/media_button_start"
- android:layout_centerVertical="true"/>
-
- <ImageButton
- style="@style/PlaybackControl.Small"
- android:id="@+id/download_next"
- android:src="?attr/media_button_forward"
- android:layout_centerVertical="true"/>
- </LinearLayout>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:gravity="center_horizontal"
+ android:orientation="vertical" >
+
+ <include layout="@layout/abstract_fragment_container" />
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
+
+ <LinearLayout
+ android:id="@+id/bottom_bar"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@drawable/media_button"
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/album_art"
+ android:layout_width="50dip"
+ android:layout_height="50dip"
+ android:layout_gravity="left|center"
+ android:scaleType="fitStart"
+ android:src="@drawable/unknown_album"/>
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:paddingLeft="8dip">
+
+ <TextView
+ android:id="@+id/track_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="?android:textColorPrimary"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textSize="13sp"
+ android:text="@string/search.artists"/>
+
+ <TextView
+ android:id="@+id/artist_name"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:textColor="?android:textColorSecondary"
+ android:singleLine="true"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textSize="12sp"
+ android:text="@string/search.albums"/>
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_height="wrap_content"
+ android:layout_width="0dp"
+ android:layout_weight="1">
+
+ <ImageButton
+ style="@style/PlaybackControl.Small"
+ android:id="@+id/download_previous"
+ android:src="?attr/media_button_backward"
+ android:layout_width="0dp"
+ android:layout_weight="1"/>
+
+ <ImageButton
+ style="@style/PlaybackControl.Small"
+ android:id="@+id/download_start"
+ android:src="?attr/media_button_start"
+ android:layout_width="0dp"
+ android:layout_weight="1"/>
+
+ <ImageButton
+ style="@style/PlaybackControl.Small"
+ android:id="@+id/download_next"
+ android:src="?attr/media_button_forward"
+ android:layout_width="0dp"
+ android:layout_weight="1"/>
+ </LinearLayout>
+ </LinearLayout>
</LinearLayout> \ No newline at end of file
diff --git a/res/layout/abstract_fragment_container.xml b/res/layout/abstract_fragment_container.xml
new file mode 100644
index 00000000..d4a8607f
--- /dev/null
+++ b/res/layout/abstract_fragment_container.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"/> \ No newline at end of file
diff --git a/res/layout/select_podcasts.xml b/res/layout/abstract_list_fragment.xml
index ea4fb07c..bfce4792 100644
--- a/res/layout/select_podcasts.xml
+++ b/res/layout/abstract_list_fragment.xml
@@ -1,29 +1,29 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/select_podcasts_layout"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
-
- <include layout="@layout/tab_progress" />
-
- <TextView
- android:id="@+id/select_podcasts_empty"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"
- android:text="@string/select_podcasts.empty"
- android:visibility="gone" />
-
- <ListView
- android:id="@+id/select_podcasts_list"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:fastScrollEnabled="true"/>
-</LinearLayout>
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/fragment_list_layout"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical" >
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1px"
+ android:background="@color/dividerColor"/>
+
+ <include layout="@layout/tab_progress" />
+
+ <TextView
+ android:id="@+id/fragment_list_empty"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:text="@string/common.empty"
+ android:visibility="gone" />
+
+ <ListView
+ android:id="@+id/fragment_list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0"
+ android:fastScrollEnabled="true"/>
+</LinearLayout>
diff --git a/res/layout/album_list_item.xml b/res/layout/album_list_item.xml
index ee710539..9051a72e 100644
--- a/res/layout/album_list_item.xml
+++ b/res/layout/album_list_item.xml
@@ -51,10 +51,10 @@
<ImageView
android:id="@+id/album_more"
- android:src="@drawable/list_item_more"
+ android:src="?attr/download_none"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="right|center_vertical"
- android:paddingRight="6dip"
+ android:paddingRight="10dip"
android:background="@drawable/menubar_button"/>
</LinearLayout>
diff --git a/res/layout/appwidget4x1.xml b/res/layout/appwidget4x1.xml
index 5e55aa37..68fecb9a 100644
--- a/res/layout/appwidget4x1.xml
+++ b/res/layout/appwidget4x1.xml
@@ -5,7 +5,8 @@
android:minWidth="250dp"
android:minHeight="40dp"
android:background="@drawable/appwidget_bg"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ android:id="@+id/widget_root">
<ImageView
android:id="@+id/appwidget_coverart"
diff --git a/res/layout/appwidget4x2.xml b/res/layout/appwidget4x2.xml
index 575ae1c2..8409bbbf 100644
--- a/res/layout/appwidget4x2.xml
+++ b/res/layout/appwidget4x2.xml
@@ -5,7 +5,8 @@
android:minWidth="250dp"
android:minHeight="110dp"
android:background="@drawable/appwidget_bg"
- android:orientation="horizontal" >
+ android:orientation="horizontal"
+ android:id="@+id/widget_root">
<ImageView
android:id="@+id/appwidget_coverart"
diff --git a/res/layout/appwidget4x3.xml b/res/layout/appwidget4x3.xml
index b4f685bc..e72a266d 100644
--- a/res/layout/appwidget4x3.xml
+++ b/res/layout/appwidget4x3.xml
@@ -3,7 +3,8 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/appwidget_bg"
- android:orientation="vertical" >
+ android:orientation="vertical"
+ android:id="@+id/widget_root">
<ImageView
android:id="@+id/appwidget_coverart"
diff --git a/res/layout/appwidget4x4.xml b/res/layout/appwidget4x4.xml
index 6e6c12ab..c885829b 100644
--- a/res/layout/appwidget4x4.xml
+++ b/res/layout/appwidget4x4.xml
@@ -3,7 +3,8 @@
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
- android:background="@drawable/appwidget_bg" >
+ android:background="@drawable/appwidget_bg"
+ android:id="@+id/widget_root">
<ImageView
android:id="@+id/appwidget_coverart"
diff --git a/res/layout/artist_list_item.xml b/res/layout/basic_list_item.xml
index edf1930e..2295a9ba 100644
--- a/res/layout/artist_list_item.xml
+++ b/res/layout/basic_list_item.xml
@@ -1,38 +1,38 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@android:color/transparent">
-
- <TextView
- android:id="@+id/artist_name"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="left|center_vertical"
- android:paddingLeft="6dip"
- android:paddingRight="6dip"
- android:minHeight="50dip"
- android:background="@android:color/transparent"/>
-
- <ImageButton
- android:id="@+id/artist_star"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right|center_vertical"
- android:src="@drawable/ic_stat_star"
- android:background="@android:color/transparent"
- android:focusable="false"
- android:visibility="gone"/>
-
- <ImageView
- android:id="@+id/artist_more"
- android:src="@drawable/list_item_more"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_gravity="right|center_vertical"
- android:paddingRight="6dip"
- android:background="@drawable/menubar_button"/>
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:background="@android:color/transparent">
+
+ <TextView
+ android:id="@+id/item_name"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:gravity="left|center_vertical"
+ android:paddingLeft="6dip"
+ android:paddingRight="6dip"
+ android:minHeight="50dip"
+ android:background="@android:color/transparent"/>
+
+ <ImageButton
+ android:id="@+id/item_star"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|center_vertical"
+ android:src="@drawable/ic_stat_star"
+ android:background="@android:color/transparent"
+ android:focusable="false"
+ android:visibility="gone"/>
+
+ <ImageView
+ android:id="@+id/item_more"
+ android:src="?attr/download_none"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_gravity="right|center_vertical"
+ android:paddingRight="10dip"
+ android:background="@drawable/menubar_button"/>
</LinearLayout> \ No newline at end of file
diff --git a/res/layout/create_bookmark.xml b/res/layout/create_bookmark.xml
new file mode 100644
index 00000000..f72b39d8
--- /dev/null
+++ b/res/layout/create_bookmark.xml
@@ -0,0 +1,26 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:id="@+id/comment_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="4dp"
+ android:textSize="20dp"
+ android:text="@string/common.comment" />
+ <EditText
+ android:id="@+id/comment_text"
+ android:inputType="text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginLeft="4dp" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/res/layout/download_action_buttons.xml b/res/layout/download_action_buttons.xml
new file mode 100644
index 00000000..e3a45151
--- /dev/null
+++ b/res/layout/download_action_buttons.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/download_other_controls_layout"
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/download_jukebox"
+ android:text="RC"
+ style="@style/DownloadActionButton"/>
+
+ <Button
+ android:id="@+id/download_equalizer"
+ android:text="EQ"
+ style="@style/DownloadActionButton"/>
+
+ <Button
+ android:id="@+id/download_visualizer"
+ android:text="VIS"
+ style="@style/DownloadActionButton"/>
+
+ <ImageButton
+ android:id="@+id/download_star"
+ style="@style/DownloadActionImageButton"
+ android:src="@android:drawable/star_big_off"/>
+
+ <ImageButton
+ android:id="@+id/download_bookmark"
+ style="@style/DownloadActionImageButton"
+ android:src="?attr/bookmark"/>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/download_media_buttons.xml b/res/layout/download_media_buttons.xml
index 1835a373..1ccf6c68 100644
--- a/res/layout/download_media_buttons.xml
+++ b/res/layout/download_media_buttons.xml
@@ -54,7 +54,7 @@
<ImageButton
style="@style/PlaybackControl.Small"
android:id="@+id/download_toggle_list"
- android:src="@drawable/action_toggle_list"
+ android:src="?attr/toggle_list"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
/>
diff --git a/res/layout/drawer_list_item.xml b/res/layout/drawer_list_item.xml
new file mode 100644
index 00000000..a85d043e
--- /dev/null
+++ b/res/layout/drawer_list_item.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="8dip"
+ android:paddingBottom="9dip">
+
+ <ImageView
+ android:id="@+id/drawer_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left|center_vertical"
+ android:paddingTop="1dip"
+ android:paddingBottom="1dip"
+ android:paddingRight="8dip"
+ android:paddingLeft="10dip"/>
+
+ <TextView
+ android:id="@+id/drawer_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textSize="26sp"
+ android:textStyle="bold"
+ android:singleLine="true"/>
+</LinearLayout> \ No newline at end of file
diff --git a/res/layout/equalizer.xml b/res/layout/equalizer.xml
index ee1a9560..6e3c7e5c 100644
--- a/res/layout/equalizer.xml
+++ b/res/layout/equalizer.xml
@@ -4,7 +4,6 @@
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- android:background="@drawable/album_art_background"
android:padding="16dip">
<CheckBox
@@ -12,7 +11,6 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/equalizer.enabled"
- android:textColor="#c0c0c0"
android:textAppearance="?android:attr/textAppearanceMedium"/>
<ScrollView
diff --git a/res/layout/equalizer_bar.xml b/res/layout/equalizer_bar.xml
index c34d1108..3a104e9b 100644
--- a/res/layout/equalizer_bar.xml
+++ b/res/layout/equalizer_bar.xml
@@ -6,8 +6,6 @@
<TextView
android:id="@+id/equalizer.frequency"
- android:textSize="12sp"
- android:textColor="#c0c0c0"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
@@ -18,7 +16,6 @@
android:id="@+id/equalizer.level"
android:text="0 dB"
android:textSize="12sp"
- android:textColor="#c0c0c0"
android:gravity="right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
diff --git a/res/layout/help.xml b/res/layout/help.xml
deleted file mode 100644
index f22dee37..00000000
--- a/res/layout/help.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <LinearLayout android:id="@+id/help_buttons"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_weight="0"
- android:layout_alignParentBottom="true"
- android:padding="4dip"
- android:gravity="center_horizontal"
- android:background="#ffcccccc">
-
- <Button android:id="@+id/help_back"
- android:text="@string/help.back"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_marginRight="5dip"
- android:paddingLeft="25dip"
- android:paddingRight="25dip"/>
-
- <Button android:id="@+id/help_close"
- android:text="@string/help.close"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_marginLeft="5dip"
- android:paddingLeft="25dip"
- android:paddingRight="25dip"/>
- </LinearLayout>
-
-
- <WebView
- android:id="@+id/help_contents"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_above="@id/help_buttons"
- android:layout_weight="1"
- android:fadingEdge="vertical"
- android:fadingEdgeLength="12dip"/>
-
- </RelativeLayout>
diff --git a/res/layout/jukebox_volume.xml b/res/layout/jukebox_volume.xml
index 4bccaec7..fd718326 100644
--- a/res/layout/jukebox_volume.xml
+++ b/res/layout/jukebox_volume.xml
@@ -32,7 +32,7 @@
android:paddingRight="12dip"
android:layout_alignParentLeft="true"
android:layout_below="@+id/jukebox_volume_title"
- android:src="@drawable/volume"/>
+ android:src="?attr/volume"/>
<SeekBar
android:layout_height="wrap_content"
diff --git a/res/layout/main_buttons.xml b/res/layout/main_buttons.xml
index 1e60838d..7729315c 100644
--- a/res/layout/main_buttons.xml
+++ b/res/layout/main_buttons.xml
@@ -15,7 +15,7 @@
android:minHeight="?android:attr/listPreferredItemHeight">
<ImageView
- android:src="@drawable/main_select_server"
+ android:src="?attr/select_server"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
@@ -71,7 +71,6 @@
<TextView
android:id="@+id/main_albums_newest"
android:text="@string/main.albums_newest"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -83,7 +82,6 @@
<TextView
android:id="@+id/main_albums_recent"
android:text="@string/main.albums_recent"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -95,7 +93,6 @@
<TextView
android:id="@+id/main_albums_frequent"
android:text="@string/main.albums_frequent"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -107,7 +104,6 @@
<TextView
android:id="@+id/main_albums_highest"
android:text="@string/main.albums_highest"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -119,7 +115,6 @@
<TextView
android:id="@+id/main_albums_starred"
android:text="@string/main.albums_starred"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -131,7 +126,6 @@
<TextView
android:id="@+id/main_albums_genres"
android:text="@string/main.albums_genres"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
@@ -143,7 +137,6 @@
<TextView
android:id="@+id/main_albums_random"
android:text="@string/main.albums_random"
- android:drawableRight="@drawable/list_item_more"
android:drawablePadding="6dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
diff --git a/res/layout/notification.xml b/res/layout/notification.xml
index 22e2cb63..55c7be2a 100644
--- a/res/layout/notification.xml
+++ b/res/layout/notification.xml
@@ -14,10 +14,12 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
android:orientation="vertical"
- android:paddingLeft="11.0dip">
+ android:paddingLeft="11.0dip"
+ android:layout_gravity="center_vertical">
<TextView
android:id="@+id/notification_title"
@@ -28,76 +30,54 @@
android:ellipsize="marquee"
android:focusable="true"
android:singleLine="true" />
-
- <LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal" >
-
- <LinearLayout
- android:layout_width="0.0dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_weight="1.0"
- android:orientation="vertical">
- <TextView
- android:id="@+id/notification_artist"
- style="@android:style/TextAppearance.StatusBar.EventContent"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:ellipsize="end"
- android:scrollHorizontally="true"
- android:singleLine="true" />
+ <TextView
+ android:id="@+id/notification_artist"
+ style="@android:style/TextAppearance.StatusBar.EventContent"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="left"
+ android:ellipsize="end"
+ android:scrollHorizontally="true"
+ android:singleLine="true" />
- <TextView
- android:id="@+id/notification_album"
- style="@android:style/TextAppearance.StatusBar.EventContent"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="left"
- android:ellipsize="end"
- android:scrollHorizontally="true"
- android:singleLine="true" />
- </LinearLayout>
+ <TextView
+ android:id="@+id/notification_album"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"/>
+ </LinearLayout>
- <ImageButton
- android:id="@+id/control_previous"
- android:src="@drawable/notification_prev"
- android:background="@drawable/btn_bg"
- android:layout_width="34dip"
- android:layout_height="34dip"
- android:layout_gravity="center|right"
- android:layout_marginRight="10dip"
- android:layout_marginTop="2dip"
- android:layout_weight="0.0"
- android:scaleType="fitXY"/>
+ <ImageButton
+ android:id="@+id/control_previous"
+ android:src="@drawable/notification_previous"
+ android:background="@drawable/btn_bg"
+ android:layout_width="46dip"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center|right"
+ android:padding="8.0dip"
+ android:layout_weight="0.0"
+ android:scaleType="fitCenter"/>
- <ImageButton
- android:id="@+id/control_pause"
- android:src="@drawable/notification_pause"
- android:background="@drawable/btn_bg"
- android:layout_width="34dip"
- android:layout_height="34dip"
- android:layout_gravity="center|right"
- android:layout_marginRight="10dip"
- android:layout_marginTop="2dip"
- android:layout_weight="0.0"
- android:scaleType="fitXY"/>
+ <ImageButton
+ android:id="@+id/control_pause"
+ android:src="@drawable/notification_pause"
+ android:background="@drawable/btn_bg"
+ android:layout_width="46dip"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center|right"
+ android:padding="8.0dip"
+ android:layout_weight="0.0"
+ android:scaleType="fitCenter"/>
- <ImageButton
- android:id="@+id/control_next"
- android:src="@drawable/notification_next"
- android:background="@drawable/btn_bg"
- android:layout_width="34dip"
- android:layout_height="34dip"
- android:layout_gravity="center|right"
- android:layout_marginRight="10dip"
- android:layout_marginTop="2dip"
- android:layout_weight="0.0"
- android:scaleType="fitXY"/>
- </LinearLayout>
- </LinearLayout>
+ <ImageButton
+ android:id="@+id/control_next"
+ android:src="@drawable/notification_next"
+ android:background="@drawable/btn_bg"
+ android:layout_width="46dip"
+ android:layout_height="fill_parent"
+ android:layout_gravity="center|right"
+ android:padding="8.0dip"
+ android:layout_weight="0.0"
+ android:scaleType="fitCenter"/>
</LinearLayout>
diff --git a/res/layout/notification_expanded.xml b/res/layout/notification_expanded.xml
index 70e7269c..e2246506 100644
--- a/res/layout/notification_expanded.xml
+++ b/res/layout/notification_expanded.xml
@@ -70,7 +70,7 @@
android:layout_weight="0.0"
android:background="@drawable/btn_bg"
android:scaleType="fitXY"
- android:src="@drawable/notification_prev" />
+ android:src="@drawable/notification_previous" />
<ImageButton
android:id="@+id/control_pause"
diff --git a/res/layout/play_video.xml b/res/layout/play_video.xml
deleted file mode 100644
index 6a9f3f74..00000000
--- a/res/layout/play_video.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <WebView
- android:id="@+id/play_video_contents"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"/>
-
-</FrameLayout>
diff --git a/res/layout/playlist_list_item.xml b/res/layout/playlist_list_item.xml
deleted file mode 100644
index 1ec5753f..00000000
--- a/res/layout/playlist_list_item.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <TextView
- android:id="@+id/playlist_name"
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="left|center_vertical"
- android:paddingLeft="6dip"
- android:paddingRight="6dip"
- android:minHeight="50dip"/>
-
- <ImageView
- android:id="@+id/playlist_more"
- android:src="@drawable/list_item_more"
- android:layout_width="wrap_content"
- android:layout_height="fill_parent"
- android:layout_gravity="right|center_vertical"
- android:paddingRight="6dip"
- android:background="@drawable/menubar_button"/>
-</LinearLayout> \ No newline at end of file
diff --git a/res/layout/search.xml b/res/layout/search.xml
deleted file mode 100644
index d1c5c84c..00000000
--- a/res/layout/search.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/search_layout"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
-
- <include layout="@layout/tab_progress"/>
-
- <ListView
- android:id="@+id/search_list"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:fastScrollEnabled="true"
- />
-</LinearLayout> \ No newline at end of file
diff --git a/res/layout/search_buttons.xml b/res/layout/search_buttons.xml
index 10b72166..3e3acfac 100644
--- a/res/layout/search_buttons.xml
+++ b/res/layout/search_buttons.xml
@@ -5,17 +5,6 @@
android:layout_height="wrap_content">
<TextView
- android:id="@+id/search_search"
- android:text="@string/search.search"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:drawablePadding="0dp"
- android:drawableLeft="@drawable/search"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:gravity="center"
- android:padding="12dp"/>
-
- <TextView
android:id="@+id/search_artists"
android:text="@string/search.artists"
android:layout_width="fill_parent"
@@ -82,4 +71,3 @@
android:paddingBottom="8dp"/>
</LinearLayout>
-
diff --git a/res/layout/select_album_footer.xml b/res/layout/select_album_footer.xml
deleted file mode 100644
index c1a30a1a..00000000
--- a/res/layout/select_album_footer.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:background="@android:color/transparent"
- android:paddingTop="6dp"
- android:paddingBottom="0dp"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content">
-
- <Button android:id="@+id/select_album_more"
- android:text="@string/select_album.more"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:visibility="gone"
- android:layout_marginLeft="6dp"
- android:layout_marginRight="6dp"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="fill_parent"/>
-
-</LinearLayout>
-
diff --git a/res/layout/select_artist.xml b/res/layout/select_artist.xml
deleted file mode 100644
index fef51d3c..00000000
--- a/res/layout/select_artist.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/select_artist_layout"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
-
- <include layout="@layout/tab_progress"/>
-
- <ListView android:id="@+id/select_artist_list"
- android:textFilterEnabled="true"
- android:fastScrollEnabled="true"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"/>
-</LinearLayout>
-
diff --git a/res/layout/select_artist_header.xml b/res/layout/select_artist_header.xml
index 0b3d151b..ba1b3d47 100644
--- a/res/layout/select_artist_header.xml
+++ b/res/layout/select_artist_header.xml
@@ -14,7 +14,7 @@
android:minHeight="?android:attr/listPreferredItemHeight">
<ImageView
- android:src="@drawable/main_select_server"
+ android:src="?attr/select_server"
android:layout_gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
diff --git a/res/layout/select_genres.xml b/res/layout/select_genres.xml
deleted file mode 100644
index 95f9d415..00000000
--- a/res/layout/select_genres.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/select_genre_layout"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
-
- <include layout="@layout/tab_progress" />
-
- <TextView
- android:id="@+id/select_genre_empty"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"
- android:text="@string/select_genre.empty"
- android:visibility="gone" />
-
- <ListView
- android:id="@+id/select_genre_list"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:textFilterEnabled="true"
- android:fastScrollEnabled="true"/>
- </LinearLayout>
-</FrameLayout> \ No newline at end of file
diff --git a/res/layout/select_playlist.xml b/res/layout/select_playlist.xml
deleted file mode 100644
index e18283bd..00000000
--- a/res/layout/select_playlist.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/select_playlist_layout"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <View
- android:layout_width="fill_parent"
- android:layout_height="1px"
- android:background="@color/dividerColor"/>
-
- <include layout="@layout/tab_progress"/>
-
- <TextView
- android:id="@+id/select_playlist_empty"
- android:text="@string/select_playlist.empty"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:padding="10dip"
- android:visibility="gone"/>
-
- <ListView android:id="@+id/select_playlist_list"
- android:layout_width="fill_parent"
- android:layout_height="0dip"
- android:layout_weight="1.0"
- android:fastScrollEnabled="true"/>
-
-</LinearLayout>
-
diff --git a/res/layout/song_list_item.xml b/res/layout/song_list_item.xml
index 90060894..3bf7ab44 100644
--- a/res/layout/song_list_item.xml
+++ b/res/layout/song_list_item.xml
@@ -48,12 +48,20 @@
android:visibility="gone"/>
<TextView
- android:id="@+id/song_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="right|center_vertical"
- android:drawablePadding="1dip"
- android:paddingRight="6dip"/>
+ android:id="@+id/song_status"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="right|center_vertical"
+ android:drawablePadding="1dip"
+ android:paddingRight="2dip"/>
+
+ <ImageView
+ android:id="@+id/song_status_icon"
+ android:layout_width="24dip"
+ android:layout_height="24dip"
+ android:layout_gravity="center_vertical"
+ android:src="?attr/downloading"
+ android:visibility="gone"/>
</LinearLayout>
<LinearLayout android:orientation="horizontal"
@@ -87,10 +95,10 @@
<ImageView
android:id="@+id/artist_more"
- android:src="@drawable/list_item_more"
+ android:src="?attr/download_none"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_gravity="right|center_vertical"
- android:paddingRight="6dip"
+ android:paddingRight="10dip"
android:background="@drawable/menubar_button"/>
</LinearLayout>
diff --git a/res/menu/chat.xml b/res/menu/abstract_top_menu.xml
index 685aba18..46419d0f 100644
--- a/res/menu/chat.xml
+++ b/res/menu/abstract_top_menu.xml
@@ -1,19 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:compat="http://schemas.android.com/apk/res-auto">
- <item
- android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
- android:title="@string/menu.refresh"
- compat:showAsAction="always|withText"/>
-
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/action_settings"
- android:title="@string/menu.settings"/>
-
- <item
- android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
- android:title="@string/menu.exit"/>
-</menu> \ No newline at end of file
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:compat="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/menu_refresh"
+ android:icon="?attr/refresh"
+ android:title="@string/menu.refresh"
+ compat:showAsAction="always|withText"/>
+
+ <item
+ android:id="@+id/menu_search"
+ android:icon="?attr/search"
+ android:title="@string/menu.search"
+ compat:showAsAction="always|withText"/>
+
+ <item
+ android:id="@+id/menu_exit"
+ android:title="@string/menu.exit"/>
+</menu>
diff --git a/res/menu/drawer_menu.xml b/res/menu/drawer_menu.xml
new file mode 100644
index 00000000..c2969938
--- /dev/null
+++ b/res/menu/drawer_menu.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:compat="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/menu_exit"
+ android:title="@string/menu.exit"/>
+</menu>
diff --git a/res/menu/empty.xml b/res/menu/empty.xml
index 979eefe4..9bb43bf7 100644
--- a/res/menu/empty.xml
+++ b/res/menu/empty.xml
@@ -3,7 +3,7 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
</menu>
diff --git a/res/menu/main.xml b/res/menu/main.xml
index 1390b68b..5e504242 100644
--- a/res/menu/main.xml
+++ b/res/menu/main.xml
@@ -3,24 +3,18 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_search"
- android:icon="@drawable/action_search"
+ android:icon="?attr/search"
android:title="@string/menu.search"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/menu.shuffle"
compat:showAsAction="always|withText"/>
-
- <item
- android:id="@+id/menu_help"
- android:icon="@drawable/action_help"
- android:title="@string/menu.help"/>
<item
android:id="@+id/menu_about"
- android:icon="@drawable/action_help"
android:title="@string/menu.about"/>
<item
@@ -31,14 +25,7 @@
android:id="@+id/menu_changelog"
android:title="@string/changelog_full_title"/>
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/action_settings"
- android:title="@string/menu.settings"/>
-
- <item
+ <item
android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
android:title="@string/menu.exit"/>
-
</menu>
diff --git a/res/menu/nowplaying.xml b/res/menu/nowplaying.xml
index ae411240..3c9c5ba6 100644
--- a/res/menu/nowplaying.xml
+++ b/res/menu/nowplaying.xml
@@ -3,27 +3,25 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/download.menu_shuffle"
compat:showAsAction="ifRoom|withText"/>
<item
android:id="@+id/menu_remove_all"
- android:icon="@drawable/action_remove_all"
+ android:icon="?attr/remove"
android:title="@string/download.menu_remove_all"
compat:showAsAction="ifRoom|withText"/>
<item
android:id="@+id/menu_save_playlist"
- android:icon="@drawable/action_save"
+ android:icon="?attr/save"
android:title="@string/download.menu_save"
compat:showAsAction="ifRoom|withText"/>
<item
android:id="@+id/menu_screen_on_off"
- android:icon="@drawable/action_screen_on_off"
- android:title="@string/download.menu_screen_on"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/download.menu_screen_on"/>
<item
android:id="@+id/menu_toggle_timer"
@@ -32,9 +30,8 @@
<item
android:id="@+id/menu_toggle_now_playing"
android:title="@string/download.show_downloading"/>
-
- <item
+
+ <item
android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
android:title="@string/menu.exit"/>
</menu>
diff --git a/res/menu/nowplaying_downloading.xml b/res/menu/nowplaying_downloading.xml
index fbdb78f4..50ab00f3 100644
--- a/res/menu/nowplaying_downloading.xml
+++ b/res/menu/nowplaying_downloading.xml
@@ -3,19 +3,9 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_remove_all"
- android:icon="@drawable/action_remove_all"
+ android:icon="?attr/remove"
android:title="@string/download.menu_remove_all"
compat:showAsAction="always|withText"/>
-
- <item
- android:id="@+id/menu_screen_on_off"
- android:icon="@drawable/action_screen_on_off"
- android:title="@string/download.menu_screen_on"
- compat:showAsAction="ifRoom|withText"/>
-
- <item
- android:id="@+id/menu_toggle_timer"
- android:title="@string/download.start_timer"/>
<item
android:id="@+id/menu_toggle_now_playing"
@@ -23,6 +13,5 @@
<item
android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
android:title="@string/menu.exit"/>
</menu>
diff --git a/res/menu/nowplaying_offline.xml b/res/menu/nowplaying_offline.xml
index 3800c013..41d1d5d1 100644
--- a/res/menu/nowplaying_offline.xml
+++ b/res/menu/nowplaying_offline.xml
@@ -4,28 +4,25 @@
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/download.menu_shuffle"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_remove_all"
- android:icon="@drawable/action_remove_all"
+ android:icon="?attr/remove"
android:title="@string/download.menu_remove_all"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_screen_on_off"
- android:icon="@drawable/action_screen_on_off"
- android:title="@string/download.menu_screen_on"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/download.menu_screen_on"/>
<item
android:id="@+id/menu_toggle_timer"
android:title="@string/download.start_timer"/>
- <item
+ <item
android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
android:title="@string/menu.exit"/>
</menu>
diff --git a/res/menu/search.xml b/res/menu/search.xml
index fa361566..cab9c4f6 100644
--- a/res/menu/search.xml
+++ b/res/menu/search.xml
@@ -3,23 +3,12 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_search"
- android:icon="@drawable/action_search"
+ android:icon="?attr/search"
android:title="@string/menu.search"
compat:showAsAction="ifRoom|withText"/>
<item
- android:id="@+id/menu_help"
- android:icon="@drawable/ic_menu_help"
- android:title="@string/menu.help"/>
-
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/ic_menu_settings"
- android:title="@string/menu.settings"/>
-
- <item
android:id="@+id/menu_exit"
- android:icon="@drawable/ic_menu_exit"
android:title="@string/menu.exit"/>
</menu>
diff --git a/res/menu/select_album.xml b/res/menu/select_album.xml
index 329c479c..469561f1 100644
--- a/res/menu/select_album.xml
+++ b/res/menu/select_album.xml
@@ -3,19 +3,19 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_play_now"
- android:icon="@drawable/action_play_all"
+ android:icon="?media_button_start"
android:title="@string/menu.play"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/menu.shuffle"
compat:showAsAction="ifRoom|withText"/>
</menu>
diff --git a/res/menu/select_album_list.xml b/res/menu/select_album_list.xml
index 635a36bf..60b636e3 100644
--- a/res/menu/select_album_list.xml
+++ b/res/menu/select_album_list.xml
@@ -3,7 +3,7 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
</menu>
diff --git a/res/menu/select_artist.xml b/res/menu/select_artist.xml
index 3c694cd2..d1e1f4e3 100644
--- a/res/menu/select_artist.xml
+++ b/res/menu/select_artist.xml
@@ -3,29 +3,23 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/menu.shuffle"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_search"
- android:icon="@drawable/action_search"
+ android:icon="?attr/search"
android:title="@string/menu.search"
compat:showAsAction="ifRoom|withText"/>
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/action_settings"
- android:title="@string/menu.settings"/>
-
- <item
+ <item
android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
android:title="@string/menu.exit"/>
</menu>
diff --git a/res/menu/select_bookmark_context.xml b/res/menu/select_bookmark_context.xml
new file mode 100644
index 00000000..af11c86f
--- /dev/null
+++ b/res/menu/select_bookmark_context.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:compat="http://schemas.android.com/apk/res-auto">
+
+ <item
+ android:id="@+id/bookmark_menu_info"
+ android:title="@string/common.info"/>
+
+ <item
+ android:id="@+id/song_menu_download"
+ android:title="@string/common.download"/>
+
+ <item
+ android:id="@+id/song_menu_pin"
+ android:title="@string/common.pin"/>
+
+ <item
+ android:id="@+id/song_menu_delete"
+ android:title="@string/common.delete"/>
+
+ <item
+ android:id="@+id/bookmark_menu_delete"
+ android:title="@string/bookmark.delete"/>
+</menu>
diff --git a/res/menu/select_genres.xml b/res/menu/select_genres.xml
index 7ce7f1a0..837b3534 100644
--- a/res/menu/select_genres.xml
+++ b/res/menu/select_genres.xml
@@ -3,17 +3,7 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
-
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/action_settings"
- android:title="@string/menu.settings"/>
-
- <item
- android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
- android:title="@string/menu.exit"/>
</menu> \ No newline at end of file
diff --git a/res/menu/select_playlist.xml b/res/menu/select_playlist.xml
deleted file mode 100644
index 4c4cc302..00000000
--- a/res/menu/select_playlist.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<menu xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:compat="http://schemas.android.com/apk/res-auto">
- <item
- android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
- android:title="@string/menu.refresh"
- compat:showAsAction="always|withText"/>
-
- <item
- android:id="@+id/menu_search"
- android:icon="@drawable/action_search"
- android:title="@string/menu.search"
- compat:showAsAction="always|withText"/>
-
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/action_settings"
- android:title="@string/menu.settings"/>
-
- <item
- android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
- android:title="@string/menu.exit"/>
-</menu>
diff --git a/res/menu/select_podcast_episode.xml b/res/menu/select_podcast_episode.xml
index 7e79d0f7..8472325a 100644
--- a/res/menu/select_podcast_episode.xml
+++ b/res/menu/select_podcast_episode.xml
@@ -3,7 +3,7 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
@@ -13,6 +13,5 @@
<item
android:id="@+id/menu_delete"
- android:icon="@drawable/action_remove_all"
android:title="@string/common.delete"/>
</menu>
diff --git a/res/menu/select_podcast_episode_offline.xml b/res/menu/select_podcast_episode_offline.xml
index cb6d1a3b..4d464c1f 100644
--- a/res/menu/select_podcast_episode_offline.xml
+++ b/res/menu/select_podcast_episode_offline.xml
@@ -3,12 +3,11 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_delete"
- android:icon="@drawable/action_remove_all"
android:title="@string/common.delete"/>
</menu>
diff --git a/res/menu/select_podcasts.xml b/res/menu/select_podcasts.xml
index 6c1ffa07..212feb04 100644
--- a/res/menu/select_podcasts.xml
+++ b/res/menu/select_podcasts.xml
@@ -3,27 +3,25 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
+ <item
+ android:id="@+id/menu_search"
+ android:icon="?attr/search"
+ android:title="@string/menu.search"
+ compat:showAsAction="always|withText"/>
+
<item
android:id="@+id/menu_add_podcast"
- android:icon="@drawable/action_exit"
android:title="@string/menu.add_podcast"/>
<item
android:id="@+id/menu_check"
- android:icon="@drawable/action_refresh"
android:title="@string/menu.check_podcasts"/>
- <item
- android:id="@+id/menu_settings"
- android:icon="@drawable/action_settings"
- android:title="@string/menu.settings"/>
-
- <item
+ <item
android:id="@+id/menu_exit"
- android:icon="@drawable/action_exit"
android:title="@string/menu.exit"/>
</menu> \ No newline at end of file
diff --git a/res/menu/select_podcasts_context_offline.xml b/res/menu/select_podcasts_context_offline.xml
new file mode 100644
index 00000000..cbc76224
--- /dev/null
+++ b/res/menu/select_podcasts_context_offline.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:compat="http://schemas.android.com/apk/res-auto">
+ <item
+ android:id="@+id/podcast_channel_info"
+ android:title="@string/common.info"/>
+</menu> \ No newline at end of file
diff --git a/res/menu/select_song.xml b/res/menu/select_song.xml
index 658e3ffe..d60dedac 100644
--- a/res/menu/select_song.xml
+++ b/res/menu/select_song.xml
@@ -3,45 +3,37 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_play_now"
- android:icon="@drawable/action_play_all"
+ android:icon="?attr/media_button_start"
android:title="@string/menu.play"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/menu.shuffle"
compat:showAsAction="ifRoom|withText"/>
<item
android:id="@+id/menu_select"
- android:icon="@drawable/action_select"
- android:title="@string/menu.select"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/menu.select"/>
<item
android:id="@+id/menu_download"
- android:icon="@drawable/action_save"
- android:title="@string/common.download"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/common.download"/>
<item
android:id="@+id/menu_cache"
- android:icon="@drawable/action_save"
- android:title="@string/common.pin"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/common.pin"/>
<item
android:id="@+id/menu_delete"
- android:icon="@drawable/action_remove_all"
- android:title="@string/common.delete"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/common.delete"/>
<item
android:id="@+id/menu_add_playlist"
@@ -53,7 +45,5 @@
<item
android:id="@+id/menu_play_last"
- android:icon="@drawable/action_play_all"
- android:title="@string/menu.play_last"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/menu.play_last"/>
</menu>
diff --git a/res/menu/select_song_offline.xml b/res/menu/select_song_offline.xml
index 7588d9ad..88e9758d 100644
--- a/res/menu/select_song_offline.xml
+++ b/res/menu/select_song_offline.xml
@@ -3,37 +3,31 @@
xmlns:compat="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_play_now"
- android:icon="@drawable/action_play_all"
+ android:icon="?attr/media_button_start"
android:title="@string/menu.play"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_refresh"
- android:icon="@drawable/action_refresh"
+ android:icon="?attr/refresh"
android:title="@string/menu.refresh"
compat:showAsAction="always|withText"/>
<item
android:id="@+id/menu_shuffle"
- android:icon="@drawable/action_shuffle"
+ android:icon="?attr/shuffle"
android:title="@string/menu.shuffle"
compat:showAsAction="ifRoom|withText"/>
<item
android:id="@+id/menu_select"
- android:icon="@drawable/action_select"
- android:title="@string/menu.select"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/menu.select"/>
<item
android:id="@+id/menu_delete"
- android:icon="@drawable/action_remove_all"
- android:title="@string/common.delete"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/common.delete"/>
<item
android:id="@+id/menu_play_last"
- android:icon="@drawable/action_play_all"
- android:title="@string/menu.play_last"
- compat:showAsAction="ifRoom|withText"/>
+ android:title="@string/menu.play_last"/>
</menu>
diff --git a/res/raw/changelog.xml b/res/raw/changelog.xml
index d4ec275a..819263ac 100644
--- a/res/raw/changelog.xml
+++ b/res/raw/changelog.xml
@@ -1,5 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<changelog>
+ <release version="4.2.0" versioncode="69" releasedate="11/14/2013">
+ <change>Changed from tabs to Pull Out Drawer like newer Google docs specify</change>
+ <change>Major UI update with better scaling icons</change>
+ <change>Updated main app icon (thanks Ben Sumner)</change>
+ <change>Added tablet layout that better uses extra space</change>
+ <change>New Bookmarks tab</change>
+ <change>Persistent notification is like other music apps now (change in settings)</change>
+ <change>Ability to hide Podcasts/Bookmarks/Chat tabs</change>
+ <change>Pressing next with repeat all on loops back to beginning</change>
+ <change>Increase right padding so context buttons are easier to press</change>
+ </release>
+ <release version="4.1.8" versioncode="66" releasedate="10/26/2013">
+ <change>Fix offline shuffle mode</change>
+ </release>
+ <release version="4.1.7" versioncode="65" releasedate="10/21/2013">
+ <change>Settings screen now broken down by sections</change>
+ <change>Added option to choose whether or not to pause on headphone/bluetooth disconnect</change>
+ <change>Added confirm for clearing current queue</change>
+ <change>Added option to hide widget while nothing is playing</change>
+ <change>Fix not being able to change position in Jukebox mode</change>
+ <change>Fix position not being saved sometimes when pausing during a streamed song</change>
+ <change>Fix sometimes the letters not matching the position on the artist list</change>
+ <change>Various minor bug fixes</change>
+ </release>
+ <release version="4.1.6" versioncode="64" releasedate="10/3/2013">
+ <change>Fix recent update sometimes messing up downloaded song</change>
+ <change>Fix changing position while streaming a song</change>
+ </release>
+ <release version="4.1.5" versioncode="63" releasedate="9/27/2013">
+ <change>Notification while doing background downloads, clicking will show you the download list</change>
+ <change>Put songs in the root directory in a new folder called Root at the bottom of the list</change>
+ <change>Speedup of saving/loading current playing list (mostly matters for those using large playlists)</change>
+ <change>Cache most common folder listings for better experience while network is intermittent</change>
+ <change>Speedup of offline playlist loading</change>
+ <change>Fix app reloading data/losing position on orientation change</change>
+ <change>Fix Show Album from now playing list</change>
+ <change>Fix using shuffle in offline mode sometimes using online songs</change>
+ <change>Various optimizations and bug fixes</change>
+ </release>
<release version="4.1.4" versioncode="61" releasedate="8/25/2013">
<change>Fix for freezes on 4.3</change>
<change>Fix for starred songs/albums not being clickable</change>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
new file mode 100644
index 00000000..594ff0b9
--- /dev/null
+++ b/res/values-es/strings.xml
@@ -0,0 +1,401 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="common.appname">DSub</string>
+ <string name="common.ok">OK</string>
+ <string name="common.save">Guardar</string>
+ <string name="common.cancel">Cancelar</string>
+ <string name="common.play_now">Reproducir</string>
+ <string name="common.play_shuffled">Reproducir en aleatorio</string>
+ <string name="common.play_next">Siguiente en la cola</string>
+ <string name="common.play_last">Reproducir al final</string>
+ <string name="common.download">Caché</string>
+ <string name="common.pin">Caché permanente</string>
+ <string name="common.delete">Borrar</string>
+ <string name="common.star">Poner estrella</string>
+ <string name="common.unstar">Quitar estrella</string>
+ <string name="common.info">Detalles</string>
+ <string name="common.name">Nombre</string>
+ <string name="common.comment">Comentar</string>
+ <string name="common.public">Público</string>
+ <string name="common.play_external">Reproducir vídeo</string>
+ <string name="common.stream_external">Stream Video</string>
+ <string name="common.confirm">Confirmar</string>
+ <string name="common.confirm_message">Quieres %1$s %2$s?</string>
+
+ <string name="button_bar.home">Inicio</string>
+ <string name="button_bar.browse">Biblioteca</string>
+ <string name="button_bar.search">Buscar</string>
+ <string name="button_bar.playlists">Listas de reproducción</string>
+ <string name="button_bar.now_playing">Ahora suena</string>
+ <string name="button_bar.podcasts">Podcasts</string>
+ <string name="button_bar.chat">Chat</string>
+
+ <string name="main.welcome_title">Bienvenido!</string>
+ <string name="main.welcome_text">Bienvenido a DSub! Ahora la aplicación está configurada para usar el servidor de demostración de Subsonic. Cuando configures tu servidor personal (disponible en <b>subsonic.org</b>), accede a <b>Preferencias</b> y cambia la configuración para conectarte.</string>
+ <string name="main.about_title">Acerca de DSub</string>
+ <string name="main.about_text">Autor: Scott Jackson
+ \nEmail: daneren2005@gmail.com
+ \nVersión: %1$s
+ \nEspacio usado: %2$s of %3$s
+ \nEspacio disponible: %4$s of %5$s</string>
+ <string name="main.select_server">Seleccionar servidor</string>
+ <string name="main.shuffle">Reproducción aleatoria</string>
+ <string name="main.offline">Modo Offline</string>
+ <string name="main.online">Modo Online</string>
+ <string name="main.settings">Preferencias</string>
+ <string name="main.albums_title">Discos</string>
+ <string name="main.albums_newest">Añadidos recientemente</string>
+ <string name="main.albums_recent">Reproducidos recientemente</string>
+ <string name="main.albums_frequent">Más reproducidos</string>
+ <string name="main.albums_highest">Mejor valorados</string>
+ <string name="main.albums_starred">Con estrella</string>
+ <string name="main.albums_random">Aleatorio</string>
+ <string name="main.albums_genres">Géneros</string>
+ <string name="main.back_confirm">Pulsa atrás de nuevo para salir</string>
+
+ <string name="menu.search">Buscar</string>
+ <string name="menu.shuffle">Aleatorio</string>
+ <string name="menu.refresh">Actualizar</string>
+ <string name="menu.select">Seleccionar todo</string>
+ <string name="menu.play">Reproducir</string>
+ <string name="menu.play_last">Reproducir al final</string>
+ <string name="menu.exit">Salir</string>
+ <string name="menu.settings">Preferencias</string>
+ <string name="menu.help">Ayuda</string>
+ <string name="menu.about">Acerca de</string>
+ <string name="menu.add_playlist">Añadir a lista de reproducción</string>
+ <string name="menu.remove_playlist">Borrar de lista de reproducción</string>
+ <string name="menu.deleted_playlist">Listas borradas %s</string>
+ <string name="menu.deleted_playlist_error">Error al borrar la lista de reproducción %s</string>
+ <string name="menu.log">Enviar Log</string>
+ <string name="menu.set_timer">Ajustar temporizador</string>
+ <string name="menu.check_podcasts">Comprobar nuevos episodios</string>
+ <string name="menu.add_podcast">Añadir canal</string>
+ <string name="menu.cast">Enviar al dispositivo</string>
+
+ <string name="playlist.label">Listas de reproducción</string>
+ <string name="playlist.update_info">Actualizar información</string>
+ <string name="playlist.updated_info">Información actualizada para la lista %s</string>
+ <string name="playlist.updated_info_error">Error al actualizar la información de la lista %s</string>
+ <string name="playlist.overwrite">Sobreescribir lista de reproducción actual</string>
+ <string name="playlist.add_to">Añadir a lista de reproducción</string>
+ <string name="playlist.create_new">Crear nueva</string>
+
+ <string name="help.label">Ayuda</string>
+ <string name="help.title">Bienvenido a DSub!</string>
+ <string name="help.back">Atrás</string>
+ <string name="help.close">Cerrar</string>
+ <string name="help.url">file:///android_asset/html/en/index.html</string>
+ <string name="help.loading">Cargando...</string>
+
+ <string name="play_video.loading">Cargando vídeo...</string>
+ <string name="play_video.noplugin">Por favor instala Adobe Flash player desde el Android Market.</string>
+
+ <string name="search.label">Buscar</string>
+ <string name="search.title">Buscar</string>
+ <string name="search.search">Click para buscar</string>
+ <string name="search.no_match">No hay coincidencias, inténtelo de nuevo</string>
+ <string name="search.artists">Artista</string>
+ <string name="search.albums">Disco</string>
+ <string name="search.songs">Canción</string>
+ <string name="search.more">Mostrar más</string>
+
+ <string name="progress.wait">Espere por favor...</string>
+
+ <string name="music_library.label">Biblioteca de medios</string>
+ <string name="music_library.label_offline">Archivos Offline</string>
+
+ <string name="select_album.empty">Vacío</string>
+ <string name="select_album.select">Seleccionar todo</string>
+ <string name="select_album.n_selected">Seleccionadas %d canciones</string>
+ <string name="select_album.n_unselected">%d canciones deseleccionadas</string>
+ <string name="select_album.more">Más</string>
+ <string name="select_album.offline">Offline</string>
+ <string name="select_album.searching">Buscando...</string>
+ <string name="select_album.no_sdcard">Error: No hay tarjeta SD disponible</string>
+ <string name="select_album.no_network">Aviso: No hay red disponible</string>
+ <string name="select_album.not_licensed">Servidor sin licencia. Quedan %d días de prueba</string>
+ <string name="select_album.donate_dialog_message">Consigue descargas ilimitadas haciendo una donación a Subsonic</string>
+ <string name="select_album.donate_dialog_now">Ahora</string>
+ <string name="select_album.donate_dialog_later">Más tarde</string>
+ <string name="select_album.donate_dialog_0_trial_days_left">Periodo de prueba terminado</string>
+
+ <string name="offline.sync_dialog_title">Canciones offline esperando a ser sincronizadas</string>
+ <string name="offline.sync_dialog_message">Procesar %1$d offline scrobbles?
+ \nProcesar %2$d estrellas offline?
+ </string>
+ <string name="offline.sync_dialog_default">Usar esta acción por defecto</string>
+ <string name="offline.sync_success">%1$d canciones sincronizadas correctamente</string>
+ <string name="offline.sync_partial">%1$d de %2$d canciones sincronizadas</string>
+ <string name="offline.sync_error">Error al sincronizar canciones</string>
+
+ <string name="select_genre.empty">No se han encontrado géneros</string>
+ <string name="select_genre.blank">Vacío</string>
+
+ <string name="select_podcasts.empty">No se han encontrado podcasts</string>
+ <string name="select_podcasts.error">Ha habido un error descargando este podcast en el servidor. El servidor debe descargarlo antes.</string>
+ <string name="select_podcasts.skipped">Este podcast no ha sido descargado en el servidor. El servidor debe descargarlo antes.</string>
+ <string name="select_podcasts.initializing">Este podcast está siendo reiniciado en el servidor. Por favor, actualice en unos segundos.</string>
+ <string name="select_podcasts.server_download">Descargar en el servidor</string>
+ <string name="select_podcasts.server_delete">Borrar en el servidor</string>
+ <string name="select_podcasts.downloading">Descargando %s en el servidor</string>
+ <string name="select_podcasts.refreshing">El servidor está comprobando nuevos podcasts ahora</string>
+ <string name="select_podcasts.deleted">Podcasts eliminados %s</string>
+ <string name="select_podcasts.deleted_error">Error al elimintar el podcast %s</string>
+ <string name="select_podcasts.add_url">URL:</string>
+ <string name="select_podcasts.created_error">Error al agregar podcast</string>
+ <string name="select_podcasts.invalid_podcast_channel">Canal de podcast no valido: %s</string>
+
+ <string name="select_playlist.empty">No hay listas de reproducción guardadas en el servidor</string>
+
+ <string name="download.empty">Lista de reproducción vaía</string>
+ <string name="download.shuffle_loading">Cargando lista aleatoria...</string>
+ <string name="download.playerstate_downloading">Descargando - %s</string>
+ <string name="download.playerstate_buffering">Buffering</string>
+ <string name="download.playerstate_playing_shuffle">Reproduciendo en aleatorio</string>
+ <string name="download.menu_show_album">Mostrar disco</string>
+ <string name="download.menu_lyrics">Letras</string>
+ <string name="download.menu_remove">Eliminar de la cola</string>
+ <string name="download.menu_delete">Borrar cache</string>
+ <string name="download.menu_remove_all">Borrar todo</string>
+ <string name="download.menu_screen_on">Pantalla encendida</string>
+ <string name="download.menu_screen_off">Pantalla apagada</string>
+ <string name="download.menu_shuffle">Aleatorio</string>
+ <string name="download.menu_toggle">Cambiar</string>
+ <string name="download.menu_save">Guardar lista de reproducción</string>
+ <string name="download.menu_shuffle_notification">Lista de reproducción en aleatorio</string>
+ <string name="download.playlist_title">Guardar lista de reproducción</string>
+ <string name="download.playlist_name">Introduce un nombre válido para la lista de reproducción:</string>
+ <string name="download.playlist_saving">Guardando lista de reproducción \"%s\"...</string>
+ <string name="download.playlist_done">Lista de reproducción guardada.</string>
+ <string name="download.playlist_error">Error al guardar la lista de reproducción, inténtelo más tarde.</string>
+ <string name="download.repeat_off">Repetir off</string>
+ <string name="download.repeat_all">Repetir todo</string>
+ <string name="download.repeat_single">Repetir canción</string>
+ <string name="download.visualizer_on">Visualizador encendido.</string>
+ <string name="download.visualizer_off">Visualizador apagado.</string>
+ <string name="download.jukebox_on">Control remoto encendido. La música se está reproduciendo en el ordenador.</string>
+ <string name="download.jukebox_off">Control remoto apagado. La música se está reproduciendo en el dispositivo móvil.</string>
+ <string name="download.jukebox_volume">Volumen remoto</string>
+ <string name="download.jukebox_server_too_old">Control remoto no soportado. Por favor, actualice su servidor Subsonic.</string>
+ <string name="download.jukebox_offline">Control remoto no disponible en modo offline.</string>
+ <string name="download.jukebox_not_authorized">Control remoto no permitido. Por favor, active el modo jukebox en <b>Users &gt; Settings</b> en su servidor Subsonic.</string>
+ <string name="download.show_downloading">Mostrar descargas</string>
+ <string name="download.show_now_playing">Mostrar reproduciendo ahora</string>
+ <string name="download.timer_length">Temporizador</string>
+ <string name="download.start_timer">Iniciar temporizador</string>
+ <string name="download.stop_timer">Detener temporizador</string>
+ <string name="download.need_download">El vídeo ha de ser descargado antes</string>
+ <string name="download.no_streaming_player">Ningún reproductor puede reproducir este stream</string>
+ <string name="download.playing_out_of">Reproduciendo: %1$d/%2$d</string>
+
+ <string name="starring_content_starred">Marcado con estrella \"%s\"</string>
+ <string name="starring_content_unstarred">Sin marca de estrella \"%s\"</string>
+ <string name="starring_content_error">Error al actualizar \"%s\", inténtelo más tarde.</string>
+
+ <string name="playlist_error">Error al obtener las listas de reproducción</string>
+ <string name="updated_playlist">Añadida %1$s canción a \"%2$s\"</string>
+ <string name="updated_playlist_error">Error al actualizar \"%s\", inténtelo más tarde.</string>
+ <string name="removed_playlist">Borrar %1$s canciones de \"%2$s\"</string>
+
+ <string name="song_details.all">%1$s %2$s</string>
+ <string name="song_details.kbps">%d kbps</string>
+ <string name="song_details.error">Error</string>
+ <string name="song_details.skipped">Saltados</string>
+ <string name="song_details.downloading">Descargando</string>
+
+ <string name="lyrics.nomatch">No se han encontrado letras</string>
+
+ <string name="error.label">Error</string>
+
+ <string name="settings.title">Ajustes de DSub</string>
+ <string name="settings.test_connection_title">Comprobar conexión</string>
+ <string name="settings.servers_add">Añadir servidor</string>
+ <string name="settings.servers_remove">Borrar servidor</string>
+ <string name="settings.servers_title">Servidores</string>
+ <string name="settings.server_unused">Sin usar</string>
+ <string name="settings.server_name">Nombre</string>
+ <string name="settings.server_address">Dirección del servidor</string>
+ <string name="settings.server_username">Usuario</string>
+ <string name="settings.server_password">Contraseña</string>
+ <string name="settings.server_open_browser">Abrir en el navegador</string>
+ <string name="settings.cache_title">Caché de música</string>
+ <string name="settings.preload_wifi">Canciones para precargar (Wifi)</string>
+ <string name="settings.preload_mobile">Canciones pare precargar (Móvil)</string>
+ <string name="settings.cache_size">Tamaño de caché (MB)</string>
+ <string name="settings.cache_location">Ruta de caché</string>
+ <string name="settings.cache_location_error">Ruta de caché no válida. Utilizando la opción por defecto.</string>
+ <string name="settings.cache_clear">Limpiar cache</string>
+ <string name="settings.cache_clear_complete">Caché limpiada</string>
+ <string name="settings.testing_connection">Probando conexión...</string>
+ <string name="settings.testing_ok">Conexión correcta</string>
+ <string name="settings.testing_unlicensed">Conexión correcta. Servidor sin licencia.</string>
+ <string name="settings.connection_failure">Error de conexión.</string>
+ <string name="settings.invalid_url">Introduzca una URL válida.</string>
+ <string name="settings.invalid_username">Por favor, especifique un usuario válido.</string>
+ <string name="settings.appearance_title">Apariencia</string>
+ <string name="settings.theme_title">Tema</string>
+ <string name="settings.theme_light">Claro</string>
+ <string name="settings.theme_dark">Oscuro</string>
+ <string name="settings.theme_black">Negro</string>
+ <string name="settings.theme_holo">Holo</string>
+ <string name="settings.theme_light_fullscreen">Claro pantalla completa</string>
+ <string name="settings.theme_dark_fullscreen">Oscuro pantalla completa</string>
+ <string name="settings.theme_black_fullscreen">Negro pantalla completa</string>
+ <string name="settings.theme_holo_fullscreen">Holo pantalla completa</string>
+ <string name="settings.track_title">Mostrar número de pista</string>
+ <string name="settings.track_summary">Mostrar número de pista al inicio de la canción si existe</string>
+ <string name="settings.network_title">Red</string>
+ <string name="settings.max_bitrate_wifi">Bitrate máximo - Wi-Fi</string>
+ <string name="settings.max_bitrate_mobile">Bitrate máximo - Móvil</string>
+ <string name="settings.max_bitrate_32">32 Kbps</string>
+ <string name="settings.max_bitrate_64">64 Kbps</string>
+ <string name="settings.max_bitrate_80">80 Kbps</string>
+ <string name="settings.max_bitrate_96">96 Kbps</string>
+ <string name="settings.max_bitrate_112">112 Kbps</string>
+ <string name="settings.max_bitrate_128">128 Kbps</string>
+ <string name="settings.max_bitrate_160">160 Kbps</string>
+ <string name="settings.max_bitrate_192">192 Kbps</string>
+ <string name="settings.max_bitrate_256">256 Kbps</string>
+ <string name="settings.max_bitrate_320">320 Kbps</string>
+ <string name="settings.max_video_bitrate_wifi">Bitrate de vídeo máximo - Wi-Fi</string>
+ <string name="settings.max_video_bitrate_mobile">Bitrate de vídeo máximo - Móvil</string>
+ <string name="settings.max_video_bitrate_200">200 Kbps</string>
+ <string name="settings.max_video_bitrate_300">300 Kbps</string>
+ <string name="settings.max_video_bitrate_400">400 Kbps</string>
+ <string name="settings.max_video_bitrate_500">500 Kbps</string>
+ <string name="settings.max_video_bitrate_700">700 Kbps</string>
+ <string name="settings.max_video_bitrate_1000">1000 Kbps</string>
+ <string name="settings.max_video_bitrate_1500">1500 Kbps</string>
+ <string name="settings.max_video_bitrate_2000">2000 Kbps</string>
+ <string name="settings.max_video_bitrate_3000">3000 Kbps</string>
+ <string name="settings.max_video_bitrate_5000">5000 Kbps</string>
+ <string name="settings.max_bitrate_unlimited">Ilimitado</string>
+ <string name="settings.wifi_required_title">Streaming sólo en Wi-Fi</string>
+ <string name="settings.wifi_required_summary">Sólo utilizar streaming si estás conectado a Wi-Fi</string>
+ <string name="settings.network_timeout_title">Network Timeout</string>
+ <string name="settings.network_timeout_10000">10 seconds</string>
+ <string name="settings.network_timeout_15000">15 seconds</string>
+ <string name="settings.network_timeout_30000">30 seconds</string>
+ <string name="settings.network_timeout_45000">45 seconds</string>
+ <string name="settings.network_timeout_60000">60 seconds</string>
+ <string name="settings.preload_1">1 canción</string>
+ <string name="settings.preload_2">2 canciones</string>
+ <string name="settings.preload_3">3 canciones</string>
+ <string name="settings.preload_5">5 canciones</string>
+ <string name="settings.preload_10">10 canciones</string>
+ <string name="settings.preload_unlimited">Ilimitado</string>
+ <string name="settings.clear_search_history">Borrar historial de búsqueda</string>
+ <string name="settings.search_history_cleared">Historial de búsqueda borrado</string>
+ <string name="settings.other_title">Otros ajustes</string>
+ <string name="settings.scrobble_title">Scrobblear a Last.fm</string>
+ <string name="settings.scrobble_summary">Recuerde configurar su usuario y contraseña de Last.fm en su servidor</string>
+ <string name="settings.hide_media_title">Ocultar del resto</string>
+ <string name="settings.hide_media_summary">Ocultar archivos de música de otras aplicaciones.</string>
+ <string name="settings.hide_media_toast">Se aplicará la próxima vez que Android escanee la música de su teléfono.</string>
+ <string name="settings.media_button_title">Botones multimedia</string>
+ <string name="settings.media_button_summary">Responder a los botones Bluetooth, teléfono y manos libres</string>
+ <string name="settings.screen_lit_title">Mantener pantalla encendida</string>
+ <string name="settings.screen_lit_summary">Mantener la pantalla encendida durantes las descargas mejora la velocidad de descarga.</string>
+ <string name="settings.playlist_title">Listas de reproducción</string>
+ <string name="settings.playlist_random_size_title">Tamaño aleatorio</string>
+ <string name="settings.buffer_length">Tamaño del buffer (0 = totalmente en caché)</string>
+ <string name="settings.sleep_timer_title">Temporizador</string>
+ <string name="settings.sleep_timer_duration_title">Duración del temporizador</string>
+ <string name="settings.sleep_timer_off">Encendido</string>
+ <string name="settings.sleep_timer_on">Apagado</string>
+ <string name="settings.sleep_timer_always_on">Siempre encendido</string>
+ <string name="settings.temp_loss_title">Pérdida temporal de foco</string>
+ <string name="settings.temp_loss_pause">Pausar siempre</string>
+ <string name="settings.temp_loss_pause_lower">Pausar, bajar el volumen cuando sea solicitado</string>
+ <string name="settings.temp_loss_lower">Bajar volumen siempre</string>
+ <string name="settings.temp_loss_nothing">No hacer nada</string>
+ <string name="settings.persistent_title">Notificación permanente</string>
+ <string name="settings.persistent_summary">Mostrar la notificación incluso tras pausar. Pulsar botón stop para quitarlo.</string>
+ <string name="settings.gapless_playback">Reproducción sin pausas</string>
+ <string name="settings.gapless_playback_summary">El Galaxy S3 parece sufrir algunos bloqueos y funcionamentos extraños desde la introducción de la reproducción sin pausas. Desmarca esta opción para solucionar el problema.</string>
+ <string name="settings.chat_refresh">Tiempo de actualización de chat (Segundos)</string>
+ <string name="settings.chat_enabled">Chat habilitado</string>
+ <string name="settings.chat_enabled_summary">Para mostrar o no mostrar la pestaña de chat. Reinicia la aplicación tras el cambio.</string>
+ <string name="settings.video_title">Vídeo</string>
+ <string name="settings.video_player">Reproductor de vídeo</string>
+ <string name="settings.video_raw">Raw (Requiere Subsonic 4.8+)</string>
+ <string name="settings.video_hls">HTTP Live Stream (HLS) (Requiere Subsonic 4.8+)</string>
+ <string name="settings.video_transcode">Transcodificación directa (Requisitos de vídeo -> configurar mp4 o similar en el servidor)</string>
+ <string name="settings.video_flash">Flash (Requiere Plugin)</string>
+
+ <string name="shuffle.title">Iniciar aleatorio por</string>
+ <string name="shuffle.startYear">Año inicial:</string>
+ <string name="shuffle.endYear">Año final:</string>
+ <string name="shuffle.genre">Género:</string>
+ <string name="shuffle.pick_genre">Seleccionar género</string>
+
+ <string name="music_service.retry">Error de red. Reintentando %1$d de %2$d.</string>
+
+ <string name="background_task.wait">Por favor, espere...</string>
+ <string name="background_task.loading">Cargando.</string>
+ <string name="background_task.no_network">Este programa requiere de acceso a la red. Encienda el Wi-Fi o la conexión de datos móviles.</string>
+ <string name="background_task.network_error">Error de red. Por favor, compruebe la dirección del servidor o inténtelo más tarde.</string>
+ <string name="background_task.not_found">Recurso no encontrado. Por favor, compruebe la dirección del servidor.</string>
+ <string name="background_task.parse_error">Respuesta desconocida. Por favor, compruebe la dirección del servidor.</string>
+
+ <string name="service.connecting">Conectando con el servidor, espere por favor.</string>
+
+ <string name="parser.reading">Leyendo desde el servidor.</string>
+ <string name="parser.reading_done">Leyendo desde el servidor. Hecho!</string>
+ <string name="parser.upgrade_client">Versiones incompatibles. Por favor, actualice la aplicación DSub de Android.</string>
+ <string name="parser.upgrade_server">Versiones incompatibles. Por favor, actualice su servidor Subsonic.</string>
+ <string name="parser.not_authenticated">Usuario o contraseña inconrrectos.</string>
+ <string name="parser.not_authorized">Sin autorización. Compruebe los permisos en el servidor Subsonic.</string>
+ <string name="parser.artist_count">Recibidos %d artistas.</string>
+
+ <string name="select_artist.refresh">Actualizar</string>
+ <string name="select_artist.folder">Seleccionar carpeta</string>
+ <string name="select_artist.all_folders">Todas las carpetas</string>
+
+ <string name="equalizer.label">Ecualizador</string>
+ <string name="equalizer.enabled">Activado</string>
+ <string name="equalizer.preset">Seleccionar preset</string>
+
+ <string name="widget.4x1">DSub (4x1)</string>
+ <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">Toca para seleccionar música</string>
+ <string name="widget.sdcard_busy">Tarjeta SD no disponible</string>
+ <string name="widget.sdcard_missing">No hay tarjeta SD</string>
+
+ <string name="util.bytes_format.gigabyte">0.00 GB</string>
+ <string name="util.bytes_format.megabyte">0.00 MB</string>
+ <string name="util.bytes_format.kilobyte">0 KB</string>
+ <string name="util.bytes_format.byte">0 B</string>
+
+ <string name="changelog_full_title">Log de cambios</string>
+ <string name="changelog_title">Novedades</string>
+ <string name="changelog_ok_button">OK</string>
+ <string name="changelog_show_full">Más…</string>
+
+ <string name="chat.send_a_message">Enviar un mensaje</string>
+
+ <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>
+
+ <plurals name="select_album_n_songs">
+ <item quantity="zero">Sin canciones</item>
+ <item quantity="one">Una canción</item>
+ <item quantity="other">%d canciones</item>
+ </plurals>
+ <plurals name="select_album_n_songs_downloading">
+ <item quantity="one">Una canción programada para descarga.</item>
+ <item quantity="other">%d canciones programadas para descarga.</item>
+ </plurals>
+ <plurals name="select_album_n_songs_added">
+ <item quantity="one">Canción añadida a la cola.</item>
+ <item quantity="other">%d canciones añadidas a la cola.</item>
+ </plurals>
+ <plurals name="select_album_donate_dialog_n_trial_days_left">
+ <item quantity="one">Queda un día del periodo de prueba</item>
+ <item quantity="other">Quedan %d días del periodo de prueba</item>
+ </plurals>
+
+</resources>
diff --git a/res/values-large/dimens.xml b/res/values-large/dimens.xml
new file mode 100644
index 00000000..4e29290d
--- /dev/null
+++ b/res/values-large/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="Button">64dip</dimen>
+ <dimen name="Button.Small">54dip</dimen>
+</resources> \ No newline at end of file
diff --git a/res/values-v16/themes.xml b/res/values-v16/themes.xml
new file mode 100644
index 00000000..aabcfaa9
--- /dev/null
+++ b/res/values-v16/themes.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <style name="DSub.TextViewStyle" parent="android:Widget.TextView">
+ <item name="android:fontFamily">sans-serif-light</item>
+ </style>
+
+ <style name="DSub.ButtonStyle" parent="android:Widget.Holo.Button">
+ <item name="android:fontFamily">sans-serif-light</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/res/values/arrays.xml b/res/values/arrays.xml
index b558d68e..7e90c727 100644
--- a/res/values/arrays.xml
+++ b/res/values/arrays.xml
@@ -1,5 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
+ <string-array name="drawerItems">
+ <item>@string/button_bar.home</item>
+ <item>@string/button_bar.browse</item>
+ <item>@string/button_bar.playlists</item>
+ <item>@string/button_bar.podcasts</item>
+ <item>@string/button_bar.bookmarks</item>
+ <item>@string/button_bar.chat</item>
+ <item>@string/menu.settings</item>
+ </string-array>
+
+ <string-array name="drawerItemsDescriptions">
+ <item>Home</item>
+ <item>Artist</item>
+ <item>Playlist</item>
+ <item>Podcast</item>
+ <item>Bookmark</item>
+ <item>Chat</item>
+ <item>Settings</item>
+ </string-array>
+
+ <array name="drawerItemIconsLight">
+ <item>@drawable/main_offline_light</item>
+ <item>@drawable/ic_menu_library_light</item>
+ <item>@drawable/ic_menu_playlist_light</item>
+ <item>@drawable/ic_menu_podcast_light</item>
+ <item>@drawable/ic_menu_bookmark_light</item>
+ <item>@drawable/ic_menu_chat_light</item>
+ <item>@drawable/ic_menu_settings_light</item>
+ </array>
+
+ <array name="drawerItemIconsDark">
+ <item>@drawable/main_offline_dark</item>
+ <item>@drawable/ic_menu_library_dark</item>
+ <item>@drawable/ic_menu_playlist_dark</item>
+ <item>@drawable/ic_menu_podcast_dark</item>
+ <item>@drawable/ic_menu_bookmark_dark</item>
+ <item>@drawable/ic_menu_chat_dark</item>
+ <item>@drawable/ic_menu_settings_dark</item>
+ </array>
<string-array name="themeValues">
<item>light</item>
@@ -137,6 +176,19 @@
<item>@string/settings.temp_loss_nothing</item>
</string-array>
+ <string-array name="disconnectPauseValues">
+ <item>0</item>
+ <item>1</item>
+ <item>2</item>
+ <item>3</item>
+ </string-array>
+ <string-array name="disconnectPauseNames">
+ <item>@string/settings.disconnect_pause_both</item>
+ <item>@string/settings.disconnect_pause_headphone</item>
+ <item>@string/settings.disconnect_pause_bluetooth</item>
+ <item>@string/settings.disconnect_pause_neither</item>
+ </string-array>
+
<string-array name="videoPlayerValues">
<item>raw</item>
<item>hls</item>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 8f669cd2..ae0939f1 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -7,6 +7,17 @@
<attr name="media_button_repeat_off" format="reference"/>
<attr name="media_button_start" format="reference"/>
<attr name="media_button_stop" format="reference"/>
- <attr name="chat" format="reference"/>
- <attr name="chat_send" format="reference" />
+ <attr name="chat_send" format="reference"/>
+ <attr name="download_none" format="reference"/>
+ <attr name="shuffle" format="reference"/>
+ <attr name="refresh" format="reference"/>
+ <attr name="search" format="reference"/>
+ <attr name="remove" format="reference"/>
+ <attr name="save" format="reference"/>
+ <attr name="volume" format="reference"/>
+ <attr name="toggle_list" format="reference"/>
+ <attr name="select_server" format="reference"/>
+ <attr name="downloading" format="reference"/>
+ <attr name="bookmark" format="reference"/>
+ <attr name="drawerItemsIcons" format="reference"/>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
new file mode 100644
index 00000000..b504b105
--- /dev/null
+++ b/res/values/dimens.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <dimen name="Button">54dip</dimen>
+ <dimen name="Button.Small">46dip</dimen>
+</resources> \ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 87667e51..52c899e2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -22,13 +22,15 @@
<string name="common.stream_external">Stream Video</string>
<string name="common.confirm">Confirm</string>
<string name="common.confirm_message">Do you want to %1$s %2$s?</string>
+ <string name="common.empty">None found</string>
<string name="button_bar.home">Home</string>
<string name="button_bar.browse">Library</string>
<string name="button_bar.search">Search</string>
<string name="button_bar.playlists">Playlists</string>
- <string name="button_bar.now_playing">Playing</string>
+ <string name="button_bar.now_playing">Now Playing</string>
<string name="button_bar.podcasts">Podcasts</string>
+ <string name="button_bar.bookmarks">Bookmarks</string>
<string name="button_bar.chat">Chat</string>
<string name="main.welcome_title">Welcome!</string>
@@ -130,10 +132,8 @@
<string name="offline.sync_partial">Successfully synced %1$d of %2$d songs</string>
<string name="offline.sync_error">Failed to sync songs</string>
- <string name="select_genre.empty">No genres found</string>
<string name="select_genre.blank">Blank</string>
- <string name="select_podcasts.empty">No podcasts found</string>
<string name="select_podcasts.error">This podcast had an error while downloading on the server. The server must download it first.</string>
<string name="select_podcasts.skipped">This podcast has not been downloaded on the server. The server must download it first.</string>
<string name="select_podcasts.initializing">This podcast channel is being initialized on the server. Please reload after a moment.</string>
@@ -147,8 +147,6 @@
<string name="select_podcasts.created_error">Failed to add podcast</string>
<string name="select_podcasts.invalid_podcast_channel">Invalid podcast channel: %s</string>
- <string name="select_playlist.empty">No saved playlists on server</string>
-
<string name="download.empty">Playlist is empty</string>
<string name="download.shuffle_loading">Shuffle list is loading...</string>
<string name="download.playerstate_downloading">Downloading - %s</string>
@@ -189,6 +187,8 @@
<string name="download.need_download">Video needs to be downloaded first</string>
<string name="download.no_streaming_player">No player can play this stream</string>
<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="starring_content_starred">Starred \"%s\"</string>
<string name="starring_content_unstarred">Unstarred \"%s\"</string>
@@ -198,6 +198,17 @@
<string name="updated_playlist">Added %1$s songs to \"%2$s\"</string>
<string name="updated_playlist_error">Failed to update \"%s\", please try later.</string>
<string name="removed_playlist">Removed %1$s songs from \"%2$s\"</string>
+
+ <string name="bookmark.delete">Delete bookmark</string>
+ <string name="bookmark.delete_title">Delete the bookmark for</string>
+ <string name="bookmark.deleted">Deleted the bookmark for \"%s\"</string>
+ <string name="bookmark.deleted_error">Failed to delete the bookmark for \"%s\"</string>
+ <string name="bookmark.details_title">Bookmark Details</string>
+ <string name="bookmark.details">Song: %1$s
+ \nPosition: %2$s
+ \nCreated: %3$s
+ \nLast Updated: %4$s
+ \nComment: %5$s</string>
<string name="song_details.all">%1$s %2$s</string>
<string name="song_details.kbps">%d kbps</string>
@@ -290,7 +301,7 @@
<string name="settings.search_history_cleared">Search history cleared</string>
<string name="settings.other_title">Other settings</string>
<string name="settings.scrobble_title">Scrobble to Last.fm</string>
- <string name="settings.scrobble_summary">Remember to set up your Last.fm user and password on the DSub server</string>
+ <string name="settings.scrobble_summary">Remember to set up your Last.fm user and password on the Subsonic server</string>
<string name="settings.hide_media_title">Hide from other</string>
<string name="settings.hide_media_summary">Hide music files from other apps.</string>
<string name="settings.hide_media_toast">Takes effect next time Android scans your phone for music.</string>
@@ -311,19 +322,32 @@
<string name="settings.temp_loss_pause_lower">Pause, lower volume when requested</string>
<string name="settings.temp_loss_lower">Always lower volume</string>
<string name="settings.temp_loss_nothing">Do Nothing</string>
+ <string name="settings.disconnect_pause_title">Pause on Disconnect</string>
+ <string name="settings.disconnect_pause_both">Pause on either</string>
+ <string name="settings.disconnect_pause_headphone">Pause only for headphone</string>
+ <string name="settings.disconnect_pause_bluetooth">Pause only for bluetooth</string>
+ <string name="settings.disconnect_pause_neither">Do Nothing</string>
<string name="settings.persistent_title">Persistent Notification</string>
<string name="settings.persistent_summary">Show the notification even after pausing. Press the stop button to clear it away.</string>
<string name="settings.gapless_playback">Gapless Playback</string>
<string name="settings.gapless_playback_summary">The Galaxy S3 seems to be experiencing freezes/other weird issue since the introduction of gapless playback. Turn this off to fix the issue.</string>
<string name="settings.chat_refresh">Chat Refresh Rate (Secs)</string>
<string name="settings.chat_enabled">Chat Enabled</string>
- <string name="settings.chat_enabled_summary">Whether or not to display the chat tab. Restart app after changing.</string>
+ <string name="settings.chat_enabled_summary">Whether or not to display the chat listing in the pull out drawer</string>
<string name="settings.video_title">Video</string>
<string name="settings.video_player">Video Player</string>
<string name="settings.video_raw">Raw (Requires Subsonic 4.8+)</string>
<string name="settings.video_hls">HTTP Live Stream (HLS) (Requires Subsonic 4.8+)</string>
<string name="settings.video_transcode">Direct Transcode (Requires video -> mp4 or similar setup on Server)</string>
<string name="settings.video_flash">Flash (Requires Plugin)</string>
+ <string name="settings.cache_screen_title">Cache/Network</string>
+ <string name="settings.playback_title">Playback</string>
+ <string name="settings.hide_widget_title">Hide Widget</string>
+ <string name="settings.hide_widget_summary">Hide widget after exiting app</string>
+ <string name="settings.podcasts_enabled">Podcasts Enabled</string>
+ <string name="settings.podcasts_enabled_summary">Whether or not to display the podcast listing in the pull out drawer</string>
+ <string name="settings.bookmarks_enabled">Bookmarks Enabled</string>
+ <string name="settings.bookmarks_enabled_summary">Whether or not to display the bookmarks listing in the pull out drawer</string>
<string name="settings.sync_title">Sync</string>
<string name="settings.sync_enabled">Sync Enabled</string>
<string name="settings.sync_enabled_summary">Whether or not playlists or podcasts are periodically checked for changes</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 4dcce34f..b1475eb6 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -6,15 +6,15 @@
<item name="android:padding">6dip</item>
<item name="android:layout_marginLeft">4dip</item>
<item name="android:layout_marginRight">4dip</item>
- <item name="android:layout_width">54dip</item>
- <item name="android:layout_height">54dip</item>
+ <item name="android:layout_width">@dimen/Button</item>
+ <item name="android:layout_height">@dimen/Button</item>
<item name="android:contentDescription">@null</item>
</style>
<style name="PlaybackControl.Small" parent="@style/PlaybackControl">
<item name="android:padding">4dip</item>
- <item name="android:layout_width">46dip</item>
- <item name="android:layout_height">46dip</item>
+ <item name="android:layout_width">@dimen/Button.Small</item>
+ <item name="android:layout_height">@dimen/Button.Small</item>
</style>
<style name="MenuBarButton">
@@ -27,6 +27,28 @@
<item name="android:textColor">?android:textColorPrimary</item>
</style>
+ <style name="DownloadActionButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:textStyle">bold</item>
+ <item name="android:textSize">22sp</item>
+ <item name="android:background">@drawable/menubar_button</item>
+ <item name="android:paddingTop">4dip</item>
+ <item name="android:paddingBottom">4dip</item>
+ <item name="android:paddingRight">4dip</item>
+ <item name="android:paddingLeft">4dip</item>
+ </style>
+
+ <style name="DownloadActionImageButton">
+ <item name="android:layout_width">wrap_content</item>
+ <item name="android:layout_height">wrap_content</item>
+ <item name="android:background">@drawable/menubar_button</item>
+ <item name="android:paddingTop">8dip</item>
+ <item name="android:paddingBottom">8dip</item>
+ <item name="android:paddingRight">16dip</item>
+ <item name="android:paddingLeft">16dip</item>
+ </style>
+
<style name="DragDropListView">
<item name="drag_enabled">true</item>
<item name="collapsed_height">1dp</item>
diff --git a/res/values/themes.xml b/res/values/themes.xml
index b2aa8277..1b2078a7 100644
--- a/res/values/themes.xml
+++ b/res/values/themes.xml
@@ -10,22 +10,48 @@
<item name="media_button_repeat_off">@drawable/media_repeat_off_light</item>
<item name="media_button_start">@drawable/media_start_light</item>
<item name="media_button_stop">@drawable/media_stop_light</item>
- <item name="chat">@drawable/ic_menu_chat_light</item>
- <item name="chat_send">@drawable/ic_menu_chat_send_light</item>
+ <item name="chat_send">@drawable/ic_menu_chat_send_light</item>
+ <item name="download_none">@drawable/download_none_light</item>
+ <item name="shuffle">@drawable/ic_menu_shuffle_light</item>
+ <item name="refresh">@drawable/ic_menu_refresh_light</item>
+ <item name="search">@drawable/ic_menu_search_light</item>
+ <item name="remove">@drawable/ic_menu_remove_light</item>
+ <item name="save">@drawable/ic_menu_save_light</item>
+ <item name="volume">@drawable/ic_action_volume_light</item>
+ <item name="toggle_list">@drawable/action_toggle_list_light</item>
+ <item name="select_server">@drawable/main_select_server_light</item>
+ <item name="downloading">@drawable/downloading_light</item>
+ <item name="bookmark">@drawable/ic_menu_bookmark_light</item>
+ <item name="drawerItemsIcons">@array/drawerItemIconsLight</item>
+ <item name="android:textViewStyle">@style/DSub.TextViewStyle</item>
+ <item name="android:buttonStyle">@style/DSub.ButtonStyle</item>
</style>
<style name="Theme.DSub.Dark" parent="@style/Theme.AppCompat">
<item name="actionBarStyle">@style/Widget.DSub.ActionBarStyle.Dark</item>
<item name="android:actionBarStyle">@style/Widget.DSub.ActionBarStyle.Dark</item>
<item name="android:textColorSecondary">@color/cyan</item>
- <item name="offline_icon">@drawable/main_offline</item>
- <item name="media_button_backward">@drawable/media_backward</item>
- <item name="media_button_forward">@drawable/media_forward</item>
- <item name="media_button_pause">@drawable/media_pause</item>
+ <item name="offline_icon">@drawable/main_offline_dark</item>
+ <item name="media_button_backward">@drawable/media_backward_dark</item>
+ <item name="media_button_forward">@drawable/media_forward_dark</item>
+ <item name="media_button_pause">@drawable/media_pause_dark</item>
<item name="media_button_repeat_off">@drawable/media_repeat_off</item>
- <item name="media_button_start">@drawable/media_start</item>
- <item name="media_button_stop">@drawable/media_stop</item>
- <item name="chat">@drawable/ic_menu_chat_dark</item>
- <item name="chat_send">@drawable/ic_menu_chat_send_dark</item>
+ <item name="media_button_start">@drawable/media_start_dark</item>
+ <item name="media_button_stop">@drawable/media_stop_dark</item>
+ <item name="chat_send">@drawable/ic_menu_chat_send_dark</item>
+ <item name="download_none">@drawable/download_none_dark</item>
+ <item name="shuffle">@drawable/ic_menu_shuffle_dark</item>
+ <item name="refresh">@drawable/ic_menu_refresh_dark</item>
+ <item name="search">@drawable/ic_menu_search_dark</item>
+ <item name="remove">@drawable/ic_menu_remove_dark</item>
+ <item name="save">@drawable/ic_menu_save_dark</item>
+ <item name="volume">@drawable/ic_action_volume_dark</item>
+ <item name="toggle_list">@drawable/action_toggle_list_dark</item>
+ <item name="select_server">@drawable/main_select_server_dark</item>
+ <item name="downloading">@drawable/downloading_dark</item>
+ <item name="bookmark">@drawable/ic_menu_bookmark_dark</item>
+ <item name="drawerItemsIcons">@array/drawerItemIconsDark</item>
+ <item name="android:textViewStyle">@style/DSub.TextViewStyle</item>
+ <item name="android:buttonStyle">@style/DSub.ButtonStyle</item>
</style>
<style name="Theme.DSub.Black" parent="Theme.DSub.Dark">
<item name="android:windowBackground">@android:color/black</item>
@@ -33,17 +59,29 @@
<style name="Theme.DSub.Holo" parent="@style/Theme.AppCompat">
<item name="actionBarStyle">@style/Widget.DSub.ActionBarStyle.Holo</item>
<item name="android:actionBarStyle">@style/Widget.DSub.ActionBarStyle.Holo</item>
- <item name="android:textColorSecondary">@color/cyan</item>
<item name="android:windowBackground">@drawable/background</item>
- <item name="offline_icon">@drawable/main_offline</item>
- <item name="media_button_backward">@drawable/media_backward</item>
- <item name="media_button_forward">@drawable/media_forward</item>
- <item name="media_button_pause">@drawable/media_pause</item>
+ <item name="offline_icon">@drawable/main_offline_dark</item>
+ <item name="media_button_backward">@drawable/media_backward_dark</item>
+ <item name="media_button_forward">@drawable/media_forward_dark</item>
+ <item name="media_button_pause">@drawable/media_pause_dark</item>
<item name="media_button_repeat_off">@drawable/media_repeat_off</item>
- <item name="media_button_start">@drawable/media_start</item>
- <item name="media_button_stop">@drawable/media_stop</item>
- <item name="chat">@drawable/ic_menu_chat_dark</item>
+ <item name="media_button_start">@drawable/media_start_dark</item>
+ <item name="media_button_stop">@drawable/media_stop_dark</item>
<item name="chat_send">@drawable/ic_menu_chat_send_dark</item>
+ <item name="download_none">@drawable/download_none_dark</item>
+ <item name="shuffle">@drawable/ic_menu_shuffle_dark</item>
+ <item name="refresh">@drawable/ic_menu_refresh_dark</item>
+ <item name="search">@drawable/ic_menu_search_dark</item>
+ <item name="remove">@drawable/ic_menu_remove_dark</item>
+ <item name="save">@drawable/ic_menu_save_dark</item>
+ <item name="volume">@drawable/ic_action_volume_dark</item>
+ <item name="toggle_list">@drawable/action_toggle_list_dark</item>
+ <item name="select_server">@drawable/main_select_server_dark</item>
+ <item name="downloading">@drawable/downloading_dark</item>
+ <item name="bookmark">@drawable/ic_menu_bookmark_dark</item>
+ <item name="drawerItemsIcons">@array/drawerItemIconsDark</item>
+ <item name="android:textViewStyle">@style/DSub.TextViewStyle</item>
+ <item name="android:buttonStyle">@style/DSub.ButtonStyle</item>
</style>
<style name="Theme.DSub.Light.Fullscreen" parent="Theme.DSub.Light">
@@ -79,4 +117,10 @@
<item name="backgroundStacked">@android:color/transparent</item>
<item name="android:backgroundStacked">@android:color/transparent</item>
</style>
+
+ <style name="DSub.TextViewStyle" parent="android:Widget.TextView">
+ </style>
+
+ <style name="DSub.ButtonStyle" parent="android:Widget.Holo.Button">
+ </style>
</resources>
diff --git a/res/xml/settings.xml b/res/xml/settings.xml
index feb7a81e..6f7527ab 100644
--- a/res/xml/settings.xml
+++ b/res/xml/settings.xml
@@ -1,232 +1,279 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
- android:title="@string/settings.title">
+ android:title="@string/settings.title">
- <PreferenceCategory
+ <PreferenceScreen
+ android:title="@string/settings.servers_title">
+
+ <PreferenceCategory
android:key="server"
- android:title="@string/settings.servers_title">
-
- <Preference
- android:key="serverAdd"
- android:title="@string/settings.servers_add"/>
-
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.appearance_title">
-
- <ListPreference
- android:title="@string/settings.theme_title"
- android:key="theme"
- android:defaultValue="holo"
- android:entryValues="@array/themeValues"
- android:entries="@array/themeNames"/>
-
- <CheckBoxPreference
- android:title="@string/settings.track_title"
- android:summary="@string/settings.track_summary"
- android:key="displayTrack"
- android:defaultValue="false"/>
-
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.video_title">
-
- <ListPreference
- android:title="@string/settings.video_player"
- android:key="videoPlayer"
- android:defaultValue="raw"
- android:entryValues="@array/videoPlayerValues"
- android:entries="@array/videoPlayerNames"/>
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.network_title">
-
- <ListPreference
- android:title="@string/settings.max_bitrate_wifi"
- android:key="maxBitrateWifi"
- android:defaultValue="0"
- android:entryValues="@array/maxBitrateValues"
- android:entries="@array/maxBitrateNames"/>
-
- <ListPreference
- android:title="@string/settings.max_bitrate_mobile"
- android:key="maxBitrateMobile"
- android:defaultValue="0"
- android:entryValues="@array/maxBitrateValues"
- android:entries="@array/maxBitrateNames"/>
-
- <ListPreference
- android:title="@string/settings.max_video_bitrate_wifi"
- android:key="maxVideoBitrateWifi"
- android:defaultValue="0"
- android:entryValues="@array/maxVideoBitrateValues"
- android:entries="@array/maxVideoBitrateNames"/>
-
- <ListPreference
- android:title="@string/settings.max_video_bitrate_mobile"
- android:key="maxVideoBitrateMobile"
- android:defaultValue="0"
- android:entryValues="@array/maxVideoBitrateValues"
- android:entries="@array/maxVideoBitrateNames"/>
-
- <CheckBoxPreference
- android:title="@string/settings.wifi_required_title"
- android:summary="@string/settings.wifi_required_summary"
- android:key="wifiRequiredForDownload"
- android:defaultValue="false"/>
-
- <ListPreference
- android:title="@string/settings.network_timeout_title"
- android:key="networkTimeout"
- android:defaultValue="15000"
- android:entryValues="@array/networkTimeoutValues"
- android:entries="@array/networkTimeoutNames"/>
-
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.playlist_title">
+ android:title="@string/settings.servers_title">
+
+ <Preference
+ android:key="serverAdd"
+ android:order="1000000"
+ android:title="@string/settings.servers_add"/>
+ </PreferenceCategory>
+
+ </PreferenceScreen>
+
+ <PreferenceScreen
+ android:title="@string/settings.appearance_title">
+
+ <PreferenceCategory
+ android:title="@string/settings.appearance_title">
+
+ <ListPreference
+ android:title="@string/settings.theme_title"
+ android:key="theme"
+ android:defaultValue="holo"
+ android:entryValues="@array/themeValues"
+ android:entries="@array/themeNames"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.track_title"
+ android:summary="@string/settings.track_summary"
+ android:key="displayTrack"
+ android:defaultValue="false"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.hide_widget_title"
+ android:summary="@string/settings.hide_widget_summary"
+ android:key="hideWidget"
+ android:defaultValue="false"/>
+
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/button_bar.chat">
+
+ <CheckBoxPreference
+ android:title="@string/settings.chat_enabled"
+ android:summary="@string/settings.chat_enabled_summary"
+ android:key="chatEnabled"
+ android:defaultValue="true"/>
<EditTextPreference
- android:title="@string/settings.buffer_length"
- android:key="bufferLength"
- android:defaultValue="5"
- android:digits="0123456789"/>
-
- <EditTextPreference
- android:title="@string/settings.playlist_random_size_title"
- android:key="randomSize"
- android:defaultValue="20"
+ android:title="@string/settings.chat_refresh"
+ android:key="chatRefreshRate"
+ android:defaultValue="30"
android:digits="0123456789"/>
-
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/settings.other_title">
+
+ <CheckBoxPreference
+ android:title="@string/settings.podcasts_enabled"
+ android:summary="@string/settings.podcasts_enabled_summary"
+ android:key="podcastsEnabled"
+ android:defaultValue="true"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.bookmarks_enabled"
+ android:summary="@string/settings.bookmarks_enabled_summary"
+ android:key="bookmarksEnabled"
+ android:defaultValue="true"/>
+ </PreferenceCategory>
+ </PreferenceScreen>
+
+ <PreferenceScreen
+ android:title="@string/settings.cache_screen_title">
+
+ <PreferenceCategory
+ android:title="@string/settings.network_title">
+
+ <ListPreference
+ android:title="@string/settings.max_bitrate_wifi"
+ android:key="maxBitrateWifi"
+ android:defaultValue="0"
+ android:entryValues="@array/maxBitrateValues"
+ android:entries="@array/maxBitrateNames"/>
+
+ <ListPreference
+ android:title="@string/settings.max_bitrate_mobile"
+ android:key="maxBitrateMobile"
+ android:defaultValue="0"
+ android:entryValues="@array/maxBitrateValues"
+ android:entries="@array/maxBitrateNames"/>
+
+ <ListPreference
+ android:title="@string/settings.max_video_bitrate_wifi"
+ android:key="maxVideoBitrateWifi"
+ android:defaultValue="0"
+ android:entryValues="@array/maxVideoBitrateValues"
+ android:entries="@array/maxVideoBitrateNames"/>
+
<ListPreference
- android:title="@string/settings.temp_loss_title"
- android:key="tempLoss"
- android:defaultValue="1"
- android:entryValues="@array/tempLossValues"
- android:entries="@array/tempLossNames"/>
+ android:title="@string/settings.max_video_bitrate_mobile"
+ android:key="maxVideoBitrateMobile"
+ android:defaultValue="0"
+ android:entryValues="@array/maxVideoBitrateValues"
+ android:entries="@array/maxVideoBitrateNames"/>
<CheckBoxPreference
- android:title="@string/settings.persistent_title"
- android:summary="@string/settings.persistent_summary"
- android:key="persistentNotification"
- android:defaultValue="false"/>
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.cache_title">
-
- <EditTextPreference
- android:title="@string/settings.cache_size"
- android:key="cacheSize"
- android:defaultValue="2000"
+ android:title="@string/settings.wifi_required_title"
+ android:summary="@string/settings.wifi_required_summary"
+ android:key="wifiRequiredForDownload"
+ android:defaultValue="false"/>
+
+ <ListPreference
+ android:title="@string/settings.network_timeout_title"
+ android:key="networkTimeout"
+ android:defaultValue="15000"
+ android:entryValues="@array/networkTimeoutValues"
+ android:entries="@array/networkTimeoutNames"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/settings.cache_title">
+
+ <EditTextPreference
+ android:title="@string/settings.cache_size"
+ android:key="cacheSize"
+ android:defaultValue="2000"
android:digits="0123456789"/>
- <EditTextPreference
- android:title="@string/settings.cache_location"
- android:key="cacheLocation"/>
-
- <ListPreference
- android:title="@string/settings.preload_wifi"
- android:key="preloadCountWifi"
- android:defaultValue="3"
- android:entryValues="@array/preloadCountValues"
- android:entries="@array/preloadCountNames"/>
-
- <ListPreference
- android:title="@string/settings.preload_mobile"
- android:key="preloadCountMobile"
- android:defaultValue="3"
- android:entryValues="@array/preloadCountValues"
- android:entries="@array/preloadCountNames"/>
-
- <Preference
+ <EditTextPreference
+ android:title="@string/settings.cache_location"
+ android:key="cacheLocation"/>
+
+ <ListPreference
+ android:title="@string/settings.preload_wifi"
+ android:key="preloadCountWifi"
+ android:defaultValue="3"
+ android:entryValues="@array/preloadCountValues"
+ android:entries="@array/preloadCountNames"/>
+
+ <ListPreference
+ android:title="@string/settings.preload_mobile"
+ android:key="preloadCountMobile"
+ android:defaultValue="3"
+ android:entryValues="@array/preloadCountValues"
+ android:entries="@array/preloadCountNames"/>
+
+ <Preference
android:key="clearCache"
android:title="@string/settings.cache_clear"
android:persistent="false"/>
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.sync_title">
-
- <CheckBoxPreference
- android:title="@string/settings.sync_enabled"
- android:summary="@string/settings.sync_enabled_summary"
- android:key="syncEnabled"
- android:defaultValue="true"/>
-
- <ListPreference
- android:title="@string/settings.sync_interval"
- android:key="syncInterval"
- android:defaultValue="60"
- android:entryValues="@array/syncIntervalValues"
- android:entries="@array/syncIntervalNames"/>
-
- <CheckBoxPreference
- android:title="@string/settings.sync_wifi"
- android:summary="@string/settings.sync_wifi_summary"
- android:key="syncWifi"
- android:defaultValue="true"/>
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/button_bar.chat">
-
- <CheckBoxPreference
- android:title="@string/settings.chat_enabled"
- android:summary="@string/settings.chat_enabled_summary"
- android:key="chatEnabled"
- android:defaultValue="true"/>
-
- <EditTextPreference
- android:title="@string/settings.chat_refresh"
- android:key="chatRefreshRate"
- android:defaultValue="30"
- android:digits="0123456789"/>
- </PreferenceCategory>
-
- <PreferenceCategory
- android:title="@string/settings.other_title">
-
- <CheckBoxPreference
- android:title="@string/settings.scrobble_title"
- android:summary="@string/settings.scrobble_summary"
- android:key="scrobble"
- android:defaultValue="false"/>
-
- <CheckBoxPreference
- android:title="@string/settings.hide_media_title"
- android:summary="@string/settings.hide_media_summary"
- android:key="hideMedia"
- android:defaultValue="false"/>
-
- <CheckBoxPreference
- android:title="@string/settings.media_button_title"
- android:summary="@string/settings.media_button_summary"
- android:key="mediaButtons"
- android:defaultValue="true"/>
-
- <CheckBoxPreference
- android:title="@string/settings.screen_lit_title"
- android:summary="@string/settings.screen_lit_summary"
- android:key="screenLitOnDownload"
- android:defaultValue="true"/>
-
- <CheckBoxPreference
- android:title="@string/settings.gapless_playback"
- android:summary="@string/settings.gapless_playback_summary"
- android:key="gaplessPlayback"
- android:defaultValue="true"/>
-
- <Preference
- android:key="clearSearchHistory"
- android:title="@string/settings.clear_search_history"
- android:persistent="false"/>
-
- </PreferenceCategory>
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/settings.sync_title">
+
+ <CheckBoxPreference
+ android:title="@string/settings.sync_enabled"
+ android:summary="@string/settings.sync_enabled_summary"
+ android:key="syncEnabled"
+ android:defaultValue="true"/>
+
+ <ListPreference
+ android:title="@string/settings.sync_interval"
+ android:key="syncInterval"
+ android:defaultValue="60"
+ android:entryValues="@array/syncIntervalValues"
+ android:entries="@array/syncIntervalNames"/>
+ <CheckBoxPreference
+ android:title="@string/settings.sync_wifi"
+ android:summary="@string/settings.sync_wifi_summary"
+ android:key="syncWifi"
+ android:defaultValue="true"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/settings.other_title">
+
+ <CheckBoxPreference
+ android:title="@string/settings.hide_media_title"
+ android:summary="@string/settings.hide_media_summary"
+ android:key="hideMedia"
+ android:defaultValue="false"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.screen_lit_title"
+ android:summary="@string/settings.screen_lit_summary"
+ android:key="screenLitOnDownload"
+ android:defaultValue="true"/>
+
+ <Preference
+ android:key="clearSearchHistory"
+ android:title="@string/settings.clear_search_history"
+ android:persistent="false"/>
+ </PreferenceCategory>
+ </PreferenceScreen>
+
+ <PreferenceScreen
+ android:title="@string/settings.playback_title">
+
+ <PreferenceCategory
+ android:title="@string/settings.playback_title">
+
+ <EditTextPreference
+ android:title="@string/settings.buffer_length"
+ android:key="bufferLength"
+ android:defaultValue="5"
+ android:digits="0123456789"/>
+
+ <EditTextPreference
+ android:title="@string/settings.playlist_random_size_title"
+ android:key="randomSize"
+ android:defaultValue="20"
+ android:digits="0123456789"/>
+
+ <ListPreference
+ android:title="@string/settings.temp_loss_title"
+ android:key="tempLoss"
+ android:defaultValue="1"
+ android:entryValues="@array/tempLossValues"
+ android:entries="@array/tempLossNames"/>
+
+ <ListPreference
+ android:title="@string/settings.disconnect_pause_title"
+ android:key="pauseOnDisconnect"
+ android:defaultValue="0"
+ android:entryValues="@array/disconnectPauseValues"
+ android:entries="@array/disconnectPauseNames"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.persistent_title"
+ android:summary="@string/settings.persistent_summary"
+ android:key="persistentNotification"
+ android:defaultValue="false"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/settings.video_title">
+
+ <ListPreference
+ android:title="@string/settings.video_player"
+ android:key="videoPlayer"
+ android:defaultValue="raw"
+ android:entryValues="@array/videoPlayerValues"
+ android:entries="@array/videoPlayerNames"/>
+ </PreferenceCategory>
+
+ <PreferenceCategory
+ android:title="@string/settings.other_title">
+
+ <CheckBoxPreference
+ android:title="@string/settings.scrobble_title"
+ android:summary="@string/settings.scrobble_summary"
+ android:key="scrobble"
+ android:defaultValue="false"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.media_button_title"
+ android:summary="@string/settings.media_button_summary"
+ android:key="mediaButtons"
+ android:defaultValue="true"/>
+
+ <CheckBoxPreference
+ android:title="@string/settings.gapless_playback"
+ android:summary="@string/settings.gapless_playback_summary"
+ android:key="gaplessPlayback"
+ android:defaultValue="true"/>
+ </PreferenceCategory>
+ </PreferenceScreen>
</PreferenceScreen>
diff --git a/src/github/daneren2005/dsub/activity/DownloadActivity.java b/src/github/daneren2005/dsub/activity/DownloadActivity.java
index 447bbb34..e302d59e 100644
--- a/src/github/daneren2005/dsub/activity/DownloadActivity.java
+++ b/src/github/daneren2005/dsub/activity/DownloadActivity.java
@@ -23,25 +23,11 @@ import android.os.Bundle;
import android.view.MenuItem;
import android.view.MotionEvent;
import github.daneren2005.dsub.fragments.DownloadFragment;
-import android.app.Dialog;
-import android.view.LayoutInflater;
+
import android.widget.EditText;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import android.app.AlertDialog;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.util.Log;
-import android.view.View;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.service.DownloadFile;
-import github.daneren2005.dsub.service.MusicService;
-import github.daneren2005.dsub.service.MusicServiceFactory;
-import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import java.util.LinkedList;
-import java.util.List;
+
+import github.daneren2005.dsub.util.Constants;
public class DownloadActivity extends SubsonicActivity {
private static final String TAG = DownloadActivity.class.getSimpleName();
@@ -57,25 +43,14 @@ public class DownloadActivity extends SubsonicActivity {
if (findViewById(R.id.download_container) != null && savedInstanceState == null) {
currentFragment = new DownloadFragment();
+ if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) {
+ Bundle args = new Bundle();
+ args.putBoolean(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true);
+ currentFragment.setArguments(args);
+ }
currentFragment.setPrimaryFragment(true);
getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment, currentFragment.getSupportTag() + "").commit();
}
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setHomeButtonEnabled(true);
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if(item.getItemId() == android.R.id.home) {
- Intent i = new Intent();
- i.setClass(this, MainActivity.class);
- i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(i);
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
}
@Override
@@ -86,11 +61,4 @@ public class DownloadActivity extends SubsonicActivity {
return false;
}
}
-
- @Override
- public void onBackPressed() {
- if(onBackPressedSupport()) {
- super.onBackPressed();
- }
- }
}
diff --git a/src/github/daneren2005/dsub/activity/EqualizerActivity.java b/src/github/daneren2005/dsub/activity/EqualizerActivity.java
deleted file mode 100644
index d9605fc5..00000000
--- a/src/github/daneren2005/dsub/activity/EqualizerActivity.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2011 (C) Sindre Mehus
- */
-package github.daneren2005.dsub.activity;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import android.app.Activity;
-import android.content.SharedPreferences;
-import android.media.audiofx.Equalizer;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.ContextMenu;
-import android.view.LayoutInflater;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.LinearLayout;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.audiofx.EqualizerController;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.Util;
-
-/**
- * Equalizer controls.
- *
- * @author Sindre Mehus
- * @version $Id$
- */
-public class EqualizerActivity extends Activity {
- private static final String TAG = EqualizerActivity.class.getSimpleName();
-
- private static final int MENU_GROUP_PRESET = 100;
-
- private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>();
- private EqualizerController equalizerController;
- private Equalizer equalizer;
- private short masterLevel = 0;
-
- @Override
- public void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- setContentView(R.layout.equalizer);
- equalizerController = DownloadServiceImpl.getInstance().getEqualizerController();
- equalizer = equalizerController.getEqualizer();
-
- initEqualizer();
-
- final View presetButton = findViewById(R.id.equalizer_preset);
- registerForContextMenu(presetButton);
- presetButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- presetButton.showContextMenu();
- }
- });
-
- CheckBox enabledCheckBox = (CheckBox) findViewById(R.id.equalizer_enabled);
- enabledCheckBox.setChecked(equalizer.getEnabled());
- enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
- @Override
- public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
- setEqualizerEnabled(b);
- }
- });
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- equalizerController.saveSettings();
-
- if(!equalizer.getEnabled()) {
- equalizerController.release();
- }
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- equalizerController = DownloadServiceImpl.getInstance().getEqualizerController();
- equalizer = equalizerController.getEqualizer();
- }
-
- @Override
- public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
- super.onCreateContextMenu(menu, view, menuInfo);
-
- short currentPreset;
- try {
- currentPreset = equalizer.getCurrentPreset();
- } catch (Exception x) {
- currentPreset = -1;
- }
-
- for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++) {
- MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset));
- if (preset == currentPreset) {
- menuItem.setChecked(true);
- }
- }
- menu.setGroupCheckable(MENU_GROUP_PRESET, true, true);
- }
-
- @Override
- public boolean onContextItemSelected(MenuItem menuItem) {
- short preset = (short) menuItem.getItemId();
- equalizer.usePreset(preset);
- updateBars(false);
- return true;
- }
-
- private void setEqualizerEnabled(boolean enabled) {
- SharedPreferences prefs = Util.getPreferences(EqualizerActivity.this);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(Constants.PREFERENCES_EQUALIZER_ON, enabled);
- editor.commit();
- equalizer.setEnabled(enabled);
- updateBars(true);
- }
-
- private void updateBars(boolean changedEnabled) {
- boolean isEnabled = equalizer.getEnabled();
- short minEQLevel = equalizer.getBandLevelRange()[0];
- short maxEQLevel = equalizer.getBandLevelRange()[1];
- for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) {
- short band = entry.getKey();
- SeekBar bar = entry.getValue();
- bar.setEnabled(isEnabled);
- if(band >= (short)0) {
- short setLevel;
- if(changedEnabled) {
- setLevel = (short)(equalizer.getBandLevel(band) - masterLevel);
- bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
- } else {
- bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
- setLevel = (short)(equalizer.getBandLevel(band) + masterLevel);
- }
- if(setLevel < minEQLevel) {
- setLevel = minEQLevel;
- } else if(setLevel > maxEQLevel) {
- setLevel = maxEQLevel;
- }
- equalizer.setBandLevel(band, setLevel);
- } else if(!isEnabled) {
- bar.setProgress(-minEQLevel);
- }
- }
-
- if(!isEnabled) {
- masterLevel = 0;
- SharedPreferences prefs = Util.getPreferences(EqualizerActivity.this);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel);
- editor.commit();
- }
- }
-
- private void initEqualizer() {
- LinearLayout layout = (LinearLayout) findViewById(R.id.equalizer_layout);
-
- final short minEQLevel = equalizer.getBandLevelRange()[0];
- final short maxEQLevel = equalizer.getBandLevelRange()[1];
-
- // Setup Pregain
- SharedPreferences prefs = Util.getPreferences(this);
- masterLevel = (short)prefs.getInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, 0);
- initPregain(layout, minEQLevel, maxEQLevel);
-
- for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
- final short band = i;
-
- View bandBar = LayoutInflater.from(this).inflate(R.layout.equalizer_bar, null);
- TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
- final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
- SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
-
- freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
-
- bars.put(band, bar);
- bar.setMax(maxEQLevel - minEQLevel);
- short level = equalizer.getBandLevel(band);
- if(equalizer.getEnabled()) {
- level = (short) (level - masterLevel);
- }
- bar.setProgress(level - minEQLevel);
- bar.setEnabled(equalizer.getEnabled());
- updateLevelText(levelTextView, level);
-
- bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- short level = (short) (progress + minEQLevel);
- if (fromUser) {
- equalizer.setBandLevel(band, (short)(level + masterLevel));
- }
- updateLevelText(levelTextView, level);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- layout.addView(bandBar);
- }
- }
-
- private void initPregain(LinearLayout layout, final short minEQLevel, final short maxEQLevel) {
- View bandBar = LayoutInflater.from(this).inflate(R.layout.equalizer_bar, null);
- TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
- final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
- SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
-
- freqTextView.setText("Master");
-
- bars.put((short)-1, bar);
- bar.setMax(maxEQLevel - minEQLevel);
- bar.setProgress(masterLevel - minEQLevel);
- bar.setEnabled(equalizer.getEnabled());
- updateLevelText(levelTextView, masterLevel);
-
- bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- @Override
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- masterLevel = (short) (progress + minEQLevel);
- if (fromUser) {
- SharedPreferences prefs = Util.getPreferences(EqualizerActivity.this);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel);
- editor.commit();
- for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
- short level = (short) ((bars.get(i).getProgress() + minEQLevel) + masterLevel);
- equalizer.setBandLevel(i, level);
- }
- }
- updateLevelText(levelTextView, masterLevel);
- }
-
- @Override
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- @Override
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- layout.addView(bandBar);
- }
-
- private void updateLevelText(TextView levelTextView, short level) {
- levelTextView.setText((level > 0 ? "+" : "") + level / 100 + " dB");
- }
-
-}
diff --git a/src/github/daneren2005/dsub/activity/HelpActivity.java b/src/github/daneren2005/dsub/activity/HelpActivity.java
deleted file mode 100644
index 6dc516bf..00000000
--- a/src/github/daneren2005/dsub/activity/HelpActivity.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package github.daneren2005.dsub.activity;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.view.KeyEvent;
-import android.view.View;
-import android.view.Window;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-import android.widget.Button;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.util.Util;
-
-/**
- * An HTML-based help screen with Back and Done buttons at the bottom.
- *
- * @author Sindre Mehus
- */
-public final class HelpActivity extends Activity {
-
- private WebView webView;
- private Button backButton;
-
- @Override
- protected void onCreate(Bundle bundle) {
- super.onCreate(bundle);
- getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
-
- setContentView(R.layout.help);
-
- webView = (WebView) findViewById(R.id.help_contents);
- webView.getSettings().setJavaScriptEnabled(true);
- webView.setWebViewClient(new HelpClient());
- if (bundle != null) {
- webView.restoreState(bundle);
- } else {
- webView.loadUrl(getResources().getString(R.string.help_url));
- }
-
- backButton = (Button) findViewById(R.id.help_back);
- backButton.setOnClickListener(new Button.OnClickListener() {
- @Override
- public void onClick(View view) {
- webView.goBack();
- }
- });
-
- Button doneButton = (Button) findViewById(R.id.help_close);
- doneButton.setOnClickListener(new Button.OnClickListener() {
- @Override
- public void onClick(View view) {
- finish();
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- }
-
- @Override
- protected void onSaveInstanceState(Bundle state) {
- webView.saveState(state);
- }
-
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (webView.canGoBack()) {
- webView.goBack();
- return true;
- }
- }
- return super.onKeyDown(keyCode, event);
- }
-
- private final class HelpClient extends WebViewClient {
- @Override
- public void onLoadResource(WebView webView, String url) {
- setProgressBarIndeterminateVisibility(true);
- setTitle(getResources().getString(R.string.help_loading));
- super.onLoadResource(webView, url);
- }
-
- @Override
- public void onPageFinished(WebView view, String url) {
- setProgressBarIndeterminateVisibility(false);
- setTitle(view.getTitle());
- backButton.setEnabled(view.canGoBack());
- }
-
- @Override
- public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
- Util.toast(HelpActivity.this, description);
- }
- }
-}
diff --git a/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java b/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java
index 15d0c6a6..7a19fcb5 100644
--- a/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java
+++ b/src/github/daneren2005/dsub/activity/QueryReceiverActivity.java
@@ -24,12 +24,14 @@ import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
+
+import github.daneren2005.dsub.fragments.SubsonicFragment;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.Util;
import github.daneren2005.dsub.provider.DSubSearchProvider;
/**
- * Receives search queries and forwards to the SelectAlbumActivity.
+ * Receives search queries and forwards to the SearchFragment.
*
* @author Sindre Mehus
*/
@@ -46,8 +48,9 @@ public class QueryReceiverActivity extends Activity {
DSubSearchProvider.MODE);
suggestions.saveRecentQuery(query, null);
- Intent intent = new Intent(QueryReceiverActivity.this, SearchActivity.class);
+ Intent intent = new Intent(QueryReceiverActivity.this, SubsonicFragmentActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(QueryReceiverActivity.this, intent);
}
finish();
diff --git a/src/github/daneren2005/dsub/activity/SearchActivity.java b/src/github/daneren2005/dsub/activity/SearchActivity.java
deleted file mode 100644
index 1dfe4790..00000000
--- a/src/github/daneren2005/dsub/activity/SearchActivity.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- This file is part of Subsonic.
-
- Subsonic is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- Subsonic is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
-
- Copyright 2009 (C) Sindre Mehus
- */
-
-package github.daneren2005.dsub.activity;
-
-import github.daneren2005.dsub.R;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.MenuItem;
-
-import github.daneren2005.dsub.fragments.SearchFragment;
-import github.daneren2005.dsub.util.Constants;
-
-public class SearchActivity extends SubsonicActivity {
- private static final String TAG = SearchActivity.class.getSimpleName();
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.download_activity);
-
- if (findViewById(R.id.download_container) != null && savedInstanceState == null) {
- currentFragment = new SearchFragment();
- currentFragment.setPrimaryFragment(true);
- getSupportFragmentManager().beginTransaction().add(R.id.download_container, currentFragment, currentFragment.getSupportTag() + "").commit();
- }
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- getSupportActionBar().setHomeButtonEnabled(true);
- }
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
-
- if(currentFragment != null && currentFragment instanceof SearchFragment) {
- String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
- boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
- boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
-
- if (query != null) {
- ((SearchFragment)currentFragment).search(query, autoplay);
- } else {
- ((SearchFragment)currentFragment).populateList();
- if (requestsearch) {
- onSearchRequested();
- }
- }
- }
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if(item.getItemId() == android.R.id.home) {
- Intent i = new Intent();
- i.setClass(this, MainActivity.class);
- i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(i);
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- public void onSupportNewIntent(Intent intent) {
- onNewIntent(intent);
- }
-
- @Override
- public void onBackPressed() {
- if(onBackPressedSupport()) {
- super.onBackPressed();
- }
- }
-} \ No newline at end of file
diff --git a/src/github/daneren2005/dsub/activity/SettingsActivity.java b/src/github/daneren2005/dsub/activity/SettingsActivity.java
index 902c55d8..6bf3dde4 100644
--- a/src/github/daneren2005/dsub/activity/SettingsActivity.java
+++ b/src/github/daneren2005/dsub/activity/SettingsActivity.java
@@ -18,6 +18,7 @@
*/
package github.daneren2005.dsub.activity;
+import android.annotation.TargetApi;
import android.accounts.Account;
import android.content.ContentResolver;
import android.content.Context;
@@ -25,6 +26,7 @@ import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
+import android.os.Build;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
@@ -35,6 +37,8 @@ import android.preference.PreferenceScreen;
import android.provider.SearchRecentSuggestions;
import android.text.InputType;
import android.util.Log;
+import android.view.MenuItem;
+
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.provider.DSubSearchProvider;
import github.daneren2005.dsub.service.DownloadService;
@@ -70,6 +74,7 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
private ListPreference preloadCountMobile;
private EditTextPreference randomSize;
private ListPreference tempLoss;
+ private ListPreference pauseDisconnect;
private EditTextPreference bufferLength;
private Preference addServerPreference;
private PreferenceCategory serversCategory;
@@ -80,6 +85,7 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
private int serverCount = 3;
private SharedPreferences settings;
+ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
@Override
public void onCreate(Bundle savedInstanceState) {
applyTheme();
@@ -98,9 +104,10 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
preloadCountMobile = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT_MOBILE);
randomSize = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_RANDOM_SIZE);
tempLoss = (ListPreference) findPreference(Constants.PREFERENCES_KEY_TEMP_LOSS);
+ pauseDisconnect = (ListPreference) findPreference(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT);
bufferLength = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_BUFFER_LENGTH);
- addServerPreference = (Preference) findPreference(Constants.PREFERENCES_KEY_SERVER_ADD);
serversCategory = (PreferenceCategory) findPreference(Constants.PREFERENCES_KEY_SERVER_KEY);
+ addServerPreference = (Preference) findPreference(Constants.PREFERENCES_KEY_SERVER_ADD);
chatRefreshRate = (EditTextPreference) findPreference(Constants.PREFERENCES_KEY_CHAT_REFRESH);
videoPlayer = (ListPreference) findPreference(Constants.PREFERENCES_KEY_VIDEO_PLAYER);
syncInterval = (ListPreference) findPreference(Constants.PREFERENCES_KEY_SYNC_INTERVAL);
@@ -145,22 +152,20 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
return false;
}
});
-
+
addServerPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
- @Override
- public boolean onPreferenceClick(Preference preference) {
+ @Override
+ public boolean onPreferenceClick(Preference preference) {
serverCount++;
- String instance = String.valueOf(serverCount);
+ String instance = String.valueOf(serverCount);
+
+ Preference addServerPreference = findPreference(Constants.PREFERENCES_KEY_SERVER_ADD);
+ serversCategory.addPreference(addServer(serverCount));
- Preference addServerPreference = findPreference(Constants.PREFERENCES_KEY_SERVER_ADD);
- serversCategory.removePreference(addServerPreference);
- serversCategory.addPreference(addServer(serverCount));
- serversCategory.addPreference(addServerPreference);
-
SharedPreferences.Editor editor = settings.edit();
editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, serverCount);
editor.commit();
-
+
serverSettings.put(instance, new ServerSettings(instance));
return true;
@@ -192,18 +197,22 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
}
});
- serversCategory.removePreference(addServerPreference);
+ serversCategory.setOrderingAsAdded(false);
for (int i = 1; i <= serverCount; i++) {
String instance = String.valueOf(i);
serversCategory.addPreference(addServer(i));
serverSettings.put(instance, new ServerSettings(instance));
}
- serversCategory.addPreference(addServerPreference);
SharedPreferences prefs = Util.getPreferences(this);
prefs.registerOnSharedPreferenceChangeListener(this);
update();
+
+ if(Build.VERSION.SDK_INT > Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+ getActionBar().setDisplayHomeAsUpEnabled(true);
+ getActionBar().setHomeButtonEnabled(true);
+ }
}
@Override
@@ -214,6 +223,16 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
+ }
+
+ return false;
+ }
+
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Log.d(TAG, "Preference changed: " + key);
@@ -269,6 +288,7 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
preloadCountMobile.setSummary(preloadCountMobile.getEntry());
randomSize.setSummary(randomSize.getText());
tempLoss.setSummary(tempLoss.getEntry());
+ pauseDisconnect.setSummary(pauseDisconnect.getEntry());
bufferLength.setSummary(bufferLength.getText() + " seconds");
chatRefreshRate.setSummary(chatRefreshRate.getText());
videoPlayer.setSummary(videoPlayer.getEntry());
@@ -385,6 +405,8 @@ public class SettingsActivity extends PreferenceActivity implements SharedPrefer
screen.addPreference(serverTestConnectionPreference);
screen.addPreference(serverOpenBrowser);
+ screen.setOrder(instance);
+
return screen;
}
diff --git a/src/github/daneren2005/dsub/activity/SubsonicActivity.java b/src/github/daneren2005/dsub/activity/SubsonicActivity.java
index 5bb75657..83baeb6a 100644
--- a/src/github/daneren2005/dsub/activity/SubsonicActivity.java
+++ b/src/github/daneren2005/dsub/activity/SubsonicActivity.java
@@ -1,53 +1,97 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
package github.daneren2005.dsub.activity;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
+import android.content.res.TypedArray;
import android.media.AudioManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
+import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
+import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
+import android.widget.ListView;
import android.widget.Spinner;
import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.fragments.SearchFragment;
import github.daneren2005.dsub.fragments.SubsonicFragment;
import github.daneren2005.dsub.service.DownloadService;
import github.daneren2005.dsub.service.DownloadServiceImpl;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.ImageLoader;
import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.DrawerAdapter;
+
import java.io.File;
import java.io.PrintWriter;
+import java.util.AbstractList;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
public class SubsonicActivity extends ActionBarActivity implements OnItemSelectedListener {
private static final String TAG = SubsonicActivity.class.getSimpleName();
private static ImageLoader IMAGE_LOADER;
protected static String theme;
+ private String[] drawerItemsDescriptions;
+ private String[] drawerItems;
+ private boolean drawerIdle = true;
+ private boolean[] enabledItems = {true, true, true};
private boolean destroyed = false;
- protected TabPagerAdapter pagerAdapter;
- protected ViewPager viewPager;
+ private boolean finished = false;
protected List<SubsonicFragment> backStack = new ArrayList<SubsonicFragment>();
protected SubsonicFragment currentFragment;
+ protected View primaryContainer;
+ protected View secondaryContainer;
Spinner actionBarSpinner;
ArrayAdapter<CharSequence> spinnerAdapter;
+ ViewGroup rootView;
+ DrawerLayout drawer;
+ ActionBarDrawerToggle drawerToggle;
+ ListView drawerList;
+ View lastSelectedView = null;
+ int lastSelectedPosition = 0;
+ boolean drawerOpen = false;
@Override
protected void onCreate(Bundle bundle) {
@@ -65,6 +109,15 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
actionBarSpinner.setAdapter(spinnerAdapter);
getSupportActionBar().setCustomView(actionbar);
+ getSupportActionBar().setDisplayHomeAsUpEnabled(true);
+ getSupportActionBar().setHomeButtonEnabled(true);
+ }
+
+ @Override
+ protected void onPostCreate(Bundle savedInstanceState) {
+ super.onPostCreate(savedInstanceState);
+ // Sync the toggle state after onRestoreInstanceState has occurred.
+ drawerToggle.syncState();
}
@Override
@@ -76,6 +129,8 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
if (theme != null && !theme.equals(Util.getTheme(this))) {
restart();
}
+
+ populateDrawer();
}
@Override
@@ -90,50 +145,157 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
super.finish();
Util.disablePendingTransition(this);
}
+
+ @Override
+ public void setContentView(int viewId) {
+ super.setContentView(R.layout.abstract_activity);
+ rootView = (ViewGroup) findViewById(R.id.content_frame);
+ LayoutInflater layoutInflater = getLayoutInflater();
+ layoutInflater.inflate(viewId, rootView);
+
+
+ drawerList = (ListView) findViewById(R.id.left_drawer);
+
+ drawerList.setOnItemClickListener(new ListView.OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ if("Settings".equals(drawerItemsDescriptions[position])) {
+ startActivity(new Intent(SubsonicActivity.this, SettingsActivity.class));
+ drawer.closeDrawers();
+ } else {
+ startFragmentActivity(drawerItemsDescriptions[position]);
+
+ if(lastSelectedView != view) {
+ lastSelectedView.setBackgroundResource(android.R.color.transparent);
+ view.setBackgroundResource(R.color.dividerColor);
+ lastSelectedView = view;
+ lastSelectedPosition = position;
+ }
+ }
+ }
+ });
+
+ drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
+ drawerToggle = new ActionBarDrawerToggle(this, drawer, R.drawable.ic_drawer, R.string.common_appname, R.string.common_appname) {
+ @Override
+ public void onDrawerClosed(View view) {
+ setTitle(currentFragment.getTitle());
+
+ drawerIdle = true;
+ drawerOpen = false;
+
+ supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerOpened(View view) {
+ if(lastSelectedView == null) {
+ lastSelectedView = drawerList.getChildAt(lastSelectedPosition);
+ lastSelectedView.setBackgroundResource(R.color.dividerColor);
+ }
+
+ getSupportActionBar().setTitle(R.string.common_appname);
+ getSupportActionBar().setDisplayShowCustomEnabled(false);
+
+ drawerIdle = true;
+ drawerOpen = true;
+
+ supportInvalidateOptionsMenu();
+ }
+
+ @Override
+ public void onDrawerSlide(View drawerView, float slideOffset) {
+ super.onDrawerSlide(drawerView, slideOffset);
+ drawerIdle = false;
+ }
+ };
+ drawer.setDrawerListener(drawerToggle);
+ drawerToggle.setDrawerIndicatorEnabled(false);
+
+ drawer.setOnTouchListener(new View.OnTouchListener() {
+ public boolean onTouch(View v, MotionEvent event) {
+ if (drawerIdle && currentFragment != null && currentFragment.getGestureDetector() != null) {
+ return currentFragment.getGestureDetector().onTouchEvent(event);
+ } else {
+ return false;
+ }
+ }
+ });
+
+ // Check whether this is a tablet or not
+ secondaryContainer = findViewById(R.id.fragment_second_container);
+ if(secondaryContainer != null) {
+ primaryContainer = findViewById(R.id.fragment_container);
+ }
+ }
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
- if(viewPager == null) {
- String[] ids = new String[backStack.size() + 1];
- ids[0] = currentFragment.getTag();
- int i = 1;
- for(SubsonicFragment frag: backStack) {
- ids[i] = frag.getTag();
- i++;
- }
- savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK, ids);
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1);
- } else {
- pagerAdapter.onSaveInstanceState(savedInstanceState);
- }
+ String[] ids = new String[backStack.size() + 1];
+ ids[0] = currentFragment.getTag();
+ int i = 1;
+ for(SubsonicFragment frag: backStack) {
+ ids[i] = frag.getTag();
+ i++;
+ }
+ savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK, ids);
+ savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE, backStack.size() + 1);
+ savedInstanceState.putInt(Constants.FRAGMENT_POSITION, lastSelectedPosition);
}
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
- if(viewPager == null) {
- super.onRestoreInstanceState(savedInstanceState);
- int size = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE);
- String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK);
- FragmentManager fm = getSupportFragmentManager();
- currentFragment = (SubsonicFragment)fm.findFragmentByTag(ids[0]);
- currentFragment.setPrimaryFragment(true);
- supportInvalidateOptionsMenu();
- for(int i = 1; i < size; i++) {
- SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[i]);
- backStack.add(frag);
+ super.onRestoreInstanceState(savedInstanceState);
+ int size = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE);
+ String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK);
+ FragmentManager fm = getSupportFragmentManager();
+ currentFragment = (SubsonicFragment)fm.findFragmentByTag(ids[0]);
+ currentFragment.setPrimaryFragment(true);
+ currentFragment.setSupportTag(ids[0]);
+ supportInvalidateOptionsMenu();
+ for(int i = 1; i < size; i++) {
+ SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[i]);
+ frag.setSupportTag(ids[i]);
+ if(secondaryContainer != null) {
+ frag.setPrimaryFragment(false, true);
}
- recreateSpinner();
- } else {
- pagerAdapter.onRestoreInstanceState(savedInstanceState);
- super.onRestoreInstanceState(savedInstanceState);
+ backStack.add(frag);
+ }
+
+ // Current fragment is hidden in secondaryContainer
+ if(secondaryContainer == null && findViewById(currentFragment.getRootId()) == null) {
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.remove(currentFragment);
+ trans.commit();
+ getSupportFragmentManager().executePendingTransactions();
+
+ trans = getSupportFragmentManager().beginTransaction();
+ trans.add(backStack.get(backStack.size() - 1).getRootId(), currentFragment, ids[0]);
+ trans.commit();
+ }
+ // Current fragment needs to be moved over to secondaryContainer
+ else if(secondaryContainer != null && secondaryContainer.findViewById(currentFragment.getRootId()) == null && backStack.size() > 0) {
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.remove(currentFragment);
+ trans.commit();
+ getSupportFragmentManager().executePendingTransactions();
+
+ trans = getSupportFragmentManager().beginTransaction();
+ trans.add(R.id.fragment_second_container, currentFragment, ids[0]);
+ trans.commit();
+
+ secondaryContainer.setVisibility(View.VISIBLE);
}
+
+ lastSelectedPosition = savedInstanceState.getInt(Constants.FRAGMENT_POSITION);
+ recreateSpinner();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
- if(pagerAdapter != null) {
- pagerAdapter.onCreateOptionsMenu(menu, menuInflater);
+ if(drawerOpen == true) {
+ menuInflater.inflate(R.menu.drawer_menu, menu);
} else if(currentFragment != null) {
currentFragment.onCreateOptionsMenu(menu, menuInflater);
}
@@ -141,12 +303,14 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- if(pagerAdapter != null) {
- return pagerAdapter.onOptionsItemSelected(item);
- } else if(currentFragment != null) {
- return currentFragment.onOptionsItemSelected(item);
+ if(drawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ } else if(item.getItemId() == android.R.id.home) {
+ onBackPressed();
+ return true;
}
- return true;
+
+ return currentFragment.onOptionsItemSelected(item);
}
@Override
@@ -165,12 +329,8 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
@Override
public void setTitle(CharSequence title) {
- super.setTitle(title);
- if(pagerAdapter != null) {
- pagerAdapter.recreateSpinner();
- } else {
- recreateSpinner();
- }
+ getSupportActionBar().setTitle(title);
+ recreateSpinner();
}
public void setSubtitle(CharSequence title) {
getSupportActionBar().setSubtitle(title);
@@ -181,11 +341,7 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
int top = spinnerAdapter.getCount() - 1;
if(position < top) {
for(int i = top; i > position; i--) {
- if(pagerAdapter != null) {
- pagerAdapter.removeCurrent();
- } else {
- removeCurrent();
- }
+ removeCurrent();
}
}
}
@@ -194,40 +350,189 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
public void onNothingSelected(AdapterView<?> parent) {
}
-
- public boolean onBackPressedSupport() {
- if(pagerAdapter != null) {
- return pagerAdapter.onBackPressed();
- } else {
- if(backStack.size() > 0) {
- removeCurrent();
- return false;
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ super.onNewIntent(intent);
+
+ if(currentFragment != null && currentFragment instanceof SearchFragment) {
+ String query = intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY);
+ boolean autoplay = intent.getBooleanExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false);
+ boolean requestsearch = intent.getBooleanExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, false);
+
+ if (query != null) {
+ ((SearchFragment)currentFragment).search(query, autoplay);
} else {
- return true;
+ ((SearchFragment)currentFragment).populateList();
+ if (requestsearch) {
+ onSearchRequested();
+ }
}
+ } else if(intent.getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) {
+ setIntent(intent);
+
+ SearchFragment fragment = new SearchFragment();
+ replaceFragment(fragment, currentFragment.getRootId(), fragment.getSupportTag());
}
}
+ private void populateDrawer() {
+ SharedPreferences prefs = Util.getPreferences(this);
+ boolean podcastsEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_PODCASTS_ENABLED, true);
+ boolean bookmarksEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_BOOKMARKS_ENABLED, true) && !Util.isOffline(this);
+ boolean chatEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true) && !Util.isOffline(this);
+
+ if(drawerItems == null || !enabledItems[0] == podcastsEnabled || !enabledItems[1] == bookmarksEnabled || !enabledItems[2] == chatEnabled) {
+ drawerItems = getResources().getStringArray(R.array.drawerItems);
+ drawerItemsDescriptions = getResources().getStringArray(R.array.drawerItemsDescriptions);
+
+ // Remove listings that user wants hidden
+ int alreadyRemoved = 0;
+ List<String> drawerItemsList = new ArrayList<String>(Arrays.asList(drawerItems));
+ List<String> drawerItemsDescriptionsList = new ArrayList<String>(Arrays.asList(drawerItemsDescriptions));
+ List<Integer> drawerItemsIconsList = new ArrayList<Integer>();
+
+ int[] arrayAttr = {R.attr.drawerItemsIcons};
+ TypedArray arrayType = obtainStyledAttributes(arrayAttr);
+ int arrayId = arrayType.getResourceId(0, 0);
+ TypedArray iconType = getResources().obtainTypedArray(arrayId);
+ for(int i = 0; i < drawerItemsList.size(); i++) {
+ drawerItemsIconsList.add(iconType.getResourceId(i, 0));
+ }
+ iconType.recycle();
+ arrayType.recycle();
+
+ // Selectively remove podcast listing [3]
+ if(!podcastsEnabled) {
+ drawerItemsList.remove(3 - alreadyRemoved);
+ drawerItemsDescriptionsList.remove(3 - alreadyRemoved);
+ drawerItemsIconsList.remove(3 - alreadyRemoved);
+ alreadyRemoved++;
+ }
+
+ // Selectively remove bookmarks listing [4]
+ if(!bookmarksEnabled) {
+ drawerItemsList.remove(4 - alreadyRemoved);
+ drawerItemsDescriptionsList.remove(4 - alreadyRemoved);
+ drawerItemsIconsList.remove(4 - alreadyRemoved);
+ alreadyRemoved++;
+ }
+
+ // Selectively remove chat listing: [5]
+ if(!chatEnabled) {
+ drawerItemsList.remove(5 - alreadyRemoved);
+ drawerItemsDescriptionsList.remove(5 - alreadyRemoved);
+ drawerItemsIconsList.remove(5 - alreadyRemoved);
+ alreadyRemoved++;
+ }
+
+ // Put list back together
+ if(alreadyRemoved > 0) {
+ drawerItems = drawerItemsList.toArray(new String[0]);
+ drawerItemsDescriptions = drawerItemsDescriptionsList.toArray(new String[0]);
+ }
+
+ drawerList.setAdapter(new DrawerAdapter(this, drawerItemsList, drawerItemsIconsList));
+ enabledItems[0] = podcastsEnabled;
+ enabledItems[1] = bookmarksEnabled;
+ enabledItems[2] = chatEnabled;
+ }
+ }
+
+ public void startFragmentActivity(String fragmentType) {
+ Intent intent = new Intent();
+ intent.setClass(SubsonicActivity.this, SubsonicFragmentActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ if(!"".equals(fragmentType)) {
+ intent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, fragmentType);
+ }
+ startActivity(intent);
+ finish();
+ }
+
+ protected void exit() {
+ if(this.getClass() != SubsonicFragmentActivity.class) {
+ Intent intent = new Intent(this, SubsonicFragmentActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
+ Util.startActivityWithoutTransition(this, intent);
+ } else {
+ finished = true;
+ this.stopService(new Intent(this, DownloadServiceImpl.class));
+ this.finish();
+ }
+ }
+
+ public boolean onBackPressedSupport() {
+ if(backStack.size() > 0) {
+ removeCurrent();
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if(onBackPressedSupport()) {
+ super.onBackPressed();
+ }
+ }
+
public void replaceFragment(SubsonicFragment fragment, int id, int tag) {
- if(pagerAdapter != null) {
- pagerAdapter.replaceCurrent(fragment, id, tag);
+ replaceFragment(fragment, id, tag, false);
+ }
+ public void replaceFragment(SubsonicFragment fragment, int id, int tag, boolean replaceCurrent) {
+ if(currentFragment != null) {
+ currentFragment.setPrimaryFragment(false, secondaryContainer != null);
+ }
+ backStack.add(currentFragment);
+
+ currentFragment = fragment;
+ currentFragment.setPrimaryFragment(true);
+ supportInvalidateOptionsMenu();
+
+ if(secondaryContainer == null) {
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.add(id, fragment, tag + "");
+ trans.commit();
} else {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
+ // Make sure secondary container is visible now
+ secondaryContainer.setVisibility(View.VISIBLE);
+
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+
+ // Check to see if you need to put on top of old left or not
+ if(backStack.size() > 1) {
+ // Move old right to left if there is a backstack already
+ SubsonicFragment newLeftFragment = backStack.get(backStack.size() - 1);
+ trans.remove(newLeftFragment);
+
+ // Only move right to left if replaceCurrent is false
+ if(!replaceCurrent) {
+ SubsonicFragment oldLeftFragment = backStack.get(backStack.size() - 2);
+ int leftId = oldLeftFragment.getRootId();
+
+ // Make sure remove is finished before adding
+ trans.commit();
+ getSupportFragmentManager().executePendingTransactions();
+
+ trans = getSupportFragmentManager().beginTransaction();
+ trans.add(leftId, newLeftFragment, newLeftFragment.getSupportTag() + "");
+ } else {
+ backStack.remove(backStack.size() - 1);
+ }
}
- backStack.add(currentFragment);
- currentFragment = fragment;
- currentFragment.setPrimaryFragment(true);
- supportInvalidateOptionsMenu();
+ // Add fragment to the right container
+ trans.add(R.id.fragment_second_container, fragment, tag + "");
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.add(id, fragment, tag + "");
+ // Commit it all
trans.commit();
- recreateSpinner();
}
+ recreateSpinner();
}
- private void removeCurrent() {
+ public void removeCurrent() {
if(currentFragment != null) {
currentFragment.setPrimaryFragment(false);
}
@@ -237,13 +542,48 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
currentFragment.setPrimaryFragment(true);
supportInvalidateOptionsMenu();
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.remove(oldFrag);
- trans.commit();
+ if(secondaryContainer == null) {
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+ trans.remove(oldFrag);
+ trans.commit();
+ } else {
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+
+ // Remove old right fragment
+ trans.remove(oldFrag);
+
+ // Only switch places if there is a backstack, otherwise primary container is correct
+ if(backStack.size() > 0) {
+ // Add current left fragment to right side
+ trans.remove(currentFragment);
+
+ // Make sure remove is finished before adding
+ trans.commit();
+ getSupportFragmentManager().executePendingTransactions();
+
+ trans = getSupportFragmentManager().beginTransaction();
+ trans.add(R.id.fragment_second_container, currentFragment, currentFragment.getSupportTag() + "");
+ } else {
+ secondaryContainer.setVisibility(View.GONE);
+ }
+
+ trans.commit();
+ }
recreateSpinner();
}
+
+ public void invalidate() {
+ if(currentFragment != null) {
+ while(backStack.size() > 0) {
+ removeCurrent();
+ }
+
+ currentFragment.invalidate();
+ populateDrawer();
+ }
+ }
- private void recreateSpinner() {
+ protected void recreateSpinner() {
if(backStack.size() > 0) {
spinnerAdapter.clear();
for(int i = 0; i < backStack.size(); i++) {
@@ -257,13 +597,6 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
getSupportActionBar().setDisplayShowCustomEnabled(false);
}
}
-
- protected void addTab(int titleRes, Class fragmentClass, Bundle args) {
- pagerAdapter.addTab(getString(titleRes), fragmentClass, args);
- }
- protected void addTab(CharSequence title, Class fragmentClass, Bundle args) {
- pagerAdapter.addTab(title, fragmentClass, args);
- }
protected void restart() {
Intent intent = new Intent(this, this.getClass());
@@ -313,6 +646,10 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
}
public DownloadService getDownloadService() {
+ if(finished) {
+ return null;
+ }
+
// If service is not available, request it to start and wait for it.
for (int i = 0; i < 5; i++) {
DownloadService downloadService = DownloadServiceImpl.getInstance();
@@ -326,13 +663,6 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
return DownloadServiceImpl.getInstance();
}
- public ViewPager getViewPager() {
- return viewPager;
- }
- public TabPagerAdapter getPagerAdapter() {
- return pagerAdapter;
- }
-
public static String getThemeName() {
return theme;
}
@@ -383,258 +713,4 @@ public class SubsonicActivity extends ActionBarActivity implements OnItemSelecte
}
}
}
-
- public class TabPagerAdapter extends FragmentPagerAdapter implements ActionBar.TabListener, ViewPager.OnPageChangeListener {
- private ActionBarActivity activity;
- private ViewPager pager;
- private ActionBar actionBar;
- private SubsonicFragment currentFragment;
- private List<TabInfo> tabs = new ArrayList<TabInfo>();
- private List<List<SubsonicFragment>> frags = new ArrayList<List<SubsonicFragment>>();
- private List<QueuedFragment> queue = new ArrayList<QueuedFragment>();
- private int currentPosition;
-
- public TabPagerAdapter(ActionBarActivity activity, ViewPager pager) {
- super(activity.getSupportFragmentManager());
- this.activity = activity;
- this.actionBar = activity.getSupportActionBar();
- this.pager = pager;
- this.currentPosition = 0;
- }
-
- @Override
- public Fragment getItem(int i) {
- final TabInfo tabInfo = tabs.get(i);
- SubsonicFragment frag = (SubsonicFragment) Fragment.instantiate(activity, tabInfo.fragmentClass.getName(), tabInfo.args);
- List<SubsonicFragment> fragStack = new ArrayList<SubsonicFragment>();
- fragStack.add(frag);
- while(i > frags.size()) {
- frags.add(null);
- }
- if(i == frags.size()) {
- frags.add(i, fragStack);
- } else {
- frags.set(i, fragStack);
- }
- if(currentFragment == null || currentPosition == i) {
- currentFragment = frag;
- currentFragment.setPrimaryFragment(true);
- }
- return frag;
- }
-
- @Override
- public int getCount() {
- return tabs.size();
- }
-
- public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- if(currentFragment != null) {
- currentFragment.onCreateOptionsMenu(menu, menuInflater);
-
- for(QueuedFragment addFragment: queue) {
- replaceFragment(addFragment.fragment, addFragment.id, currentFragment.getSupportTag());
- currentFragment = addFragment.fragment;
- }
- currentFragment.setPrimaryFragment(true);
- queue.clear();
- }
- }
- public boolean onOptionsItemSelected(MenuItem item) {
- if(currentFragment != null) {
- return currentFragment.onOptionsItemSelected(item);
- } else {
- return false;
- }
- }
-
- public void onTabSelected(ActionBar.Tab tab, FragmentTransaction ft) {
- TabInfo tabInfo = (TabInfo) tab.getTag();
- for (int i = 0; i < tabs.size(); i++) {
- if ( tabs.get(i) == tabInfo ) {
- pager.setCurrentItem(i);
- break;
- }
- }
- }
-
- public void onTabUnselected(ActionBar.Tab tab, FragmentTransaction ft) {}
-
- public void onTabReselected(ActionBar.Tab tab, FragmentTransaction ft) {}
-
- public void onPageScrollStateChanged(int arg0) {}
-
- public void onPageScrolled(int arg0, float arg1, int arg2) {}
-
- public void onPageSelected(int position) {
- currentPosition = position;
- actionBar.setSelectedNavigationItem(position);
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- if(position <= frags.size()) {
- List<SubsonicFragment> fragStack = frags.get(position);
- currentFragment = fragStack.get(fragStack.size() - 1);
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(true);
- }
- activity.supportInvalidateOptionsMenu();
- recreateSpinner();
- }
- }
-
- public void addTab(CharSequence title, Class fragmentClass, Bundle args) {
- final TabInfo tabInfo = new TabInfo(fragmentClass, args);
-
- ActionBar.Tab tab = actionBar.newTab();
- tab.setText(title);
- tab.setTabListener(this);
- tab.setTag(tabInfo);
-
- tabs.add(tabInfo);
-
- actionBar.addTab(tab);
- notifyDataSetChanged();
- }
- public void queueFragment(SubsonicFragment fragment, int id) {
- QueuedFragment frag = new QueuedFragment();
- frag.fragment = fragment;
- frag.id = id;
- queue.add(frag);
- }
- public void replaceCurrent(SubsonicFragment fragment, int id, int tag) {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- fragStack.add(fragment);
-
- currentFragment = fragment;
- currentFragment.setPrimaryFragment(true);
- activity.supportInvalidateOptionsMenu();
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.add(id, fragment, tag + "");
- trans.commit();
- recreateSpinner();
- }
-
- public void removeCurrent() {
- if(currentFragment != null) {
- currentFragment.setPrimaryFragment(false);
- }
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- Fragment oldFrag = (Fragment)fragStack.remove(fragStack.size() - 1);
-
- currentFragment = fragStack.get(fragStack.size() - 1);
- currentFragment.setPrimaryFragment(true);
- activity.supportInvalidateOptionsMenu();
-
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- trans.remove(oldFrag);
- trans.commit();
- }
-
- public boolean onBackPressed() {
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- if(fragStack.size() > 1) {
- removeCurrent();
- recreateSpinner();
- return false;
- } else {
- if(currentPosition == 0) {
- return true;
- } else {
- viewPager.setCurrentItem(0);
- return false;
- }
- }
- }
-
- private void recreateSpinner() {
- if(frags.isEmpty()) {
- return;
- }
-
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- if(fragStack.size() > 1) {
- spinnerAdapter.clear();
- for(int i = 0; i < fragStack.size(); i++) {
- SubsonicFragment frag = fragStack.get(i);
- spinnerAdapter.add(frag.getTitle());
- }
- spinnerAdapter.notifyDataSetChanged();
- actionBarSpinner.setSelection(spinnerAdapter.getCount() - 1);
- actionBar.setDisplayShowCustomEnabled(true);
- } else {
- actionBar.setDisplayShowCustomEnabled(false);
- }
- }
-
- public void invalidate() {
- FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
- for (int i = 0; i < frags.size(); i++) {
- List<SubsonicFragment> fragStack = frags.get(i);
-
- for(int j = fragStack.size() - 1; j > 0; j--) {
- SubsonicFragment oldFrag = fragStack.remove(j);
- trans.remove((Fragment)oldFrag);
- }
-
- SubsonicFragment frag = (SubsonicFragment)fragStack.get(0);
- frag.invalidate();
- }
- trans.commit();
- }
-
- public void onSaveInstanceState(Bundle savedInstanceState) {
- for(int i = 0; i < frags.size(); i++) {
- List<SubsonicFragment> fragStack = frags.get(i);
- String[] ids = new String[fragStack.size()];
-
- for(int j = 0; j < fragStack.size(); j++) {
- ids[j] = fragStack.get(j).getTag();
- }
- savedInstanceState.putStringArray(Constants.MAIN_BACK_STACK + i, ids);
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_SIZE + i, fragStack.size());
- }
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_TABS, frags.size());
- savedInstanceState.putInt(Constants.MAIN_BACK_STACK_POSITION, currentPosition);
- }
-
- public void onRestoreInstanceState(Bundle savedInstanceState) {
- int tabCount = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_TABS);
- FragmentManager fm = activity.getSupportFragmentManager();
- for(int i = 0; i < tabCount; i++) {
- int stackSize = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_SIZE + i);
- String[] ids = savedInstanceState.getStringArray(Constants.MAIN_BACK_STACK + i);
- List<SubsonicFragment> fragStack = new ArrayList<SubsonicFragment>();
-
- for(int j = 0; j < stackSize; j++) {
- SubsonicFragment frag = (SubsonicFragment)fm.findFragmentByTag(ids[j]);
- fragStack.add(frag);
- }
-
- frags.add(i, fragStack);
- }
- currentPosition = savedInstanceState.getInt(Constants.MAIN_BACK_STACK_POSITION);
- List<SubsonicFragment> fragStack = frags.get(currentPosition);
- currentFragment = fragStack.get(fragStack.size() - 1);
- currentFragment.setPrimaryFragment(true);
- activity.supportInvalidateOptionsMenu();
- }
-
- private class TabInfo {
- public final Class fragmentClass;
- public final Bundle args;
- public TabInfo(Class fragmentClass, Bundle args) {
- this.fragmentClass = fragmentClass;
- this.args = args;
- }
- }
- private class QueuedFragment {
- public SubsonicFragment fragment;
- public int id;
- }
- }
}
diff --git a/src/github/daneren2005/dsub/activity/MainActivity.java b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java
index da46df71..29d192e7 100644
--- a/src/github/daneren2005/dsub/activity/MainActivity.java
+++ b/src/github/daneren2005/dsub/activity/SubsonicFragmentActivity.java
@@ -1,339 +1,436 @@
-package github.daneren2005.dsub.activity;
-
-import android.accounts.Account;
-import android.accounts.AccountManager;
-import android.app.AlertDialog;
-import android.content.ContentResolver;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.preference.PreferenceManager;
-import android.support.v4.view.ViewPager;
-import android.support.v7.app.ActionBar;
-import android.util.Log;
-import android.view.View;
-import android.widget.ImageButton;
-import android.widget.TextView;
-import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.domain.MusicDirectory;
-import github.daneren2005.dsub.domain.PlayerState;
-import github.daneren2005.dsub.fragments.ChatFragment;
-import github.daneren2005.dsub.fragments.MainFragment;
-import github.daneren2005.dsub.fragments.SelectArtistFragment;
-import github.daneren2005.dsub.fragments.SelectDirectoryFragment;
-import github.daneren2005.dsub.fragments.SelectPlaylistFragment;
-import github.daneren2005.dsub.fragments.SelectPodcastsFragment;
-import github.daneren2005.dsub.fragments.SubsonicFragment;
-import github.daneren2005.dsub.service.DownloadFile;
-import github.daneren2005.dsub.service.DownloadServiceImpl;
-import github.daneren2005.dsub.updates.Updater;
-import github.daneren2005.dsub.util.Constants;
-import github.daneren2005.dsub.util.FileUtil;
-import github.daneren2005.dsub.util.SilentBackgroundTask;
-import github.daneren2005.dsub.util.Util;
-import github.daneren2005.dsub.view.ChangeLog;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
-
-public class MainActivity extends SubsonicActivity {
- private static final String TAG = MainActivity.class.getSimpleName();
- private static boolean infoDialogDisplayed;
- private ScheduledExecutorService executorService;
- private View bottomBar;
- private View coverArtView;
- private TextView trackView;
- private TextView artistView;
- private ImageButton startButton;
- private long lastBackPressTime = 0;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
- stopService(new Intent(this, DownloadServiceImpl.class));
- finish();
- } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) {
- getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD);
- Intent intent = new Intent();
- intent.setClass(this, DownloadActivity.class);
- startActivity(intent);
- }
- setContentView(R.layout.main);
- loadSettings();
- createAccount();
-
- bottomBar = findViewById(R.id.bottom_bar);
- bottomBar.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- Intent intent = new Intent();
- intent.setClass(v.getContext(), DownloadActivity.class);
- startActivity(intent);
- }
- });
- coverArtView = bottomBar.findViewById(R.id.album_art);
- trackView = (TextView) bottomBar.findViewById(R.id.track_name);
- artistView = (TextView) bottomBar.findViewById(R.id.artist_name);
-
- ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous);
- previousButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new SilentBackgroundTask<Void>(MainActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- if(getDownloadService() == null) {
- return null;
- }
-
- getDownloadService().previous();
- return null;
- }
-
- @Override
- protected void done(Void result) {
- update();
- }
- }.execute();
- }
- });
-
- startButton = (ImageButton) findViewById(R.id.download_start);
- startButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new SilentBackgroundTask<Void>(MainActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- PlayerState state = getDownloadService().getPlayerState();
- if(state == PlayerState.STARTED) {
- getDownloadService().pause();
- } else {
- getDownloadService().start();
- }
-
- return null;
- }
-
- @Override
- protected void done(Void result) {
- update();
- }
- }.execute();
- }
- });
-
- ImageButton nextButton = (ImageButton) findViewById(R.id.download_next);
- nextButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- new SilentBackgroundTask<Void>(MainActivity.this) {
- @Override
- protected Void doInBackground() throws Throwable {
- if(getDownloadService() == null) {
- return null;
- }
-
- if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
- getDownloadService().next();
- }
- return null;
- }
-
- @Override
- protected void done(Void result) {
- update();
- }
- }.execute();
- }
- });
-
- viewPager = (ViewPager) findViewById(R.id.pager);
- viewPager.setOffscreenPageLimit(4);
- pagerAdapter = new TabPagerAdapter(this, viewPager);
- viewPager.setAdapter(pagerAdapter);
- viewPager.setOnPageChangeListener(pagerAdapter);
-
- addTab(R.string.button_bar_home, MainFragment.class, null);
- addTab(R.string.button_bar_browse, SelectArtistFragment.class, null);
- addTab(R.string.button_bar_playlists, SelectPlaylistFragment.class, null);
- addTab(R.string.button_bar_podcasts, SelectPodcastsFragment.class, null);
- SharedPreferences prefs = Util.getPreferences(this);
- if(prefs.getBoolean(Constants.PREFERENCES_KEY_CHAT_ENABLED, true)) {
- addTab(R.string.button_bar_chat, ChatFragment.class, null);
- }
-
- getSupportActionBar().setDisplayHomeAsUpEnabled(false);
- getSupportActionBar().setHomeButtonEnabled(false);
- getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
- }
-
- @Override
- protected void onPostCreate(Bundle bundle) {
- super.onPostCreate(bundle);
-
- showInfoDialog();
- checkUpdates();
-
- ChangeLog changeLog = new ChangeLog(this, Util.getPreferences(this));
- if(changeLog.isFirstRun()) {
- changeLog.getLogDialog().show();
- }
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- final Handler handler = new Handler();
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- handler.post(new Runnable() {
- @Override
- public void run() {
- update();
- }
- });
- }
- };
-
- if(getIntent().hasExtra(Constants.INTENT_EXTRA_VIEW_ALBUM)) {
- viewPager.setCurrentItem(1);
-
- int fragmentID = R.id.select_artist_layout;
- if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID)) {
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID));
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME));
- fragment.setArguments(args);
-
- pagerAdapter.queueFragment(fragment, R.id.select_artist_layout);
- fragmentID = fragment.getRootId();
- }
-
- SubsonicFragment fragment = new SelectDirectoryFragment();
- Bundle args = new Bundle();
- args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID));
- args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME));
- fragment.setArguments(args);
-
- pagerAdapter.queueFragment(fragment, fragmentID);
- getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM);
- }
-
- executorService = Executors.newSingleThreadScheduledExecutor();
- executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- executorService.shutdown();
- }
-
- @Override
- public void onBackPressed() {
- if(onBackPressedSupport()) {
- if(lastBackPressTime < (System.currentTimeMillis() - 4000)) {
- lastBackPressTime = System.currentTimeMillis();
- Util.toast(this, R.string.main_back_confirm);
- } else {
- finish();
- }
- }
- }
-
- private void update() {
- if (getDownloadService() == null) {
- return;
- }
-
- DownloadFile current = getDownloadService().getCurrentPlaying();
- if(current == null) {
- trackView.setText("Title");
- artistView.setText("Artist");
- getImageLoader().loadImage(coverArtView, null, false, false);
- return;
- }
-
- MusicDirectory.Entry song = current.getSong();
- trackView.setText(song.getTitle());
- artistView.setText(song.getArtist());
- getImageLoader().loadImage(coverArtView, song, false, false);
- int[] attrs = new int[] {(getDownloadService().getPlayerState() == PlayerState.STARTED) ? R.attr.media_button_pause : R.attr.media_button_start};
- TypedArray typedArray = this.obtainStyledAttributes(attrs);
- Drawable drawable = typedArray.getDrawable(0);
- startButton.setImageDrawable(drawable);
- typedArray.recycle();
- }
-
- public void checkUpdates() {
- try {
- String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
- int ver = Integer.parseInt(version.replace(".", ""));
- Updater updater = new Updater(ver);
- updater.checkUpdates(this);
- }
- catch(Exception e) {
-
- }
- }
-
- private void loadSettings() {
- PreferenceManager.setDefaultValues(this, R.xml.settings, false);
- SharedPreferences prefs = Util.getPreferences(this);
- if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
- editor.commit();
- }
-
- if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false);
-
- editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + 1, "Demo Server");
- editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + 1, "http://demo.subsonic.org");
- editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "android-guest");
- editor.putString(Constants.PREFERENCES_KEY_PASSWORD + 1, "guest");
- editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
- editor.commit();
- }
- if(!prefs.contains(Constants.PREFERENCES_KEY_SERVER_COUNT)) {
- SharedPreferences.Editor editor = prefs.edit();
- editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 3);
- editor.commit();
- }
- }
-
- private void createAccount() {
- AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
- Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE);
- accountManager.addAccountExplicitly(account, null, null);
-
- SharedPreferences prefs = Util.getPreferences(this);
- boolean syncEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_ENABLED, true);
- int syncInterval = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SYNC_INTERVAL, "60"));
-
- // Make sync run every hour
- ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled);
- ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval);
- ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, syncEnabled);
- ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, new Bundle(), 60L * syncInterval);
- }
-
- private void showInfoDialog() {
- if (!infoDialogDisplayed) {
- infoDialogDisplayed = true;
- Log.i(TAG, Util.getRestUrl(this, null));
- if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) {
- Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
- }
- }
- }
-}
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.activity;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.app.AlertDialog;
+import android.content.ContentResolver;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.preference.PreferenceManager;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentTransaction;
+import android.util.Log;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.TextView;
+
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.PlayerState;
+import github.daneren2005.dsub.fragments.ChatFragment;
+import github.daneren2005.dsub.fragments.MainFragment;
+import github.daneren2005.dsub.fragments.SearchFragment;
+import github.daneren2005.dsub.fragments.SelectArtistFragment;
+import github.daneren2005.dsub.fragments.SelectBookmarkFragment;
+import github.daneren2005.dsub.fragments.SelectDirectoryFragment;
+import github.daneren2005.dsub.fragments.SelectPlaylistFragment;
+import github.daneren2005.dsub.fragments.SelectPodcastsFragment;
+import github.daneren2005.dsub.fragments.SubsonicFragment;
+import github.daneren2005.dsub.service.DownloadFile;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.updates.Updater;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.FileUtil;
+import github.daneren2005.dsub.util.SilentBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.ChangeLog;
+
+/**
+ * Created by Scott on 10/14/13.
+ */
+public class SubsonicFragmentActivity extends SubsonicActivity {
+ private static String TAG = SubsonicFragmentActivity.class.getSimpleName();
+ private static boolean infoDialogDisplayed;
+ private ScheduledExecutorService executorService;
+ private View bottomBar;
+ private View coverArtView;
+ private TextView trackView;
+ private TextView artistView;
+ private ImageButton startButton;
+ private long lastBackPressTime = 0;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) {
+ stopService(new Intent(this, DownloadServiceImpl.class));
+ finish();
+ } else if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD)) {
+ getIntent().removeExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD);
+ Intent intent = new Intent();
+ intent.setClass(this, DownloadActivity.class);
+ if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) {
+ intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true);
+ }
+ startActivity(intent);
+ }
+ setContentView(R.layout.abstract_fragment_activity);
+
+ if (findViewById(R.id.fragment_container) != null && savedInstanceState == null) {
+ String fragmentType = getIntent().getStringExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE);
+ currentFragment = getNewFragment(fragmentType);
+
+ if("".equals(fragmentType) || fragmentType == null) {
+ // Initial startup stuff
+ loadSettings();
+ createAccount();
+ }
+
+ currentFragment.setPrimaryFragment(true);
+ getSupportFragmentManager().beginTransaction().add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "").commit();
+
+ if(getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_QUERY) != null) {
+ SearchFragment fragment = new SearchFragment();
+ replaceFragment(fragment, R.id.home_layout, fragment.getSupportTag());
+ }
+ }
+
+ bottomBar = findViewById(R.id.bottom_bar);
+ bottomBar.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ Intent intent = new Intent();
+ intent.setClass(v.getContext(), DownloadActivity.class);
+ startActivity(intent);
+ }
+ });
+ coverArtView = bottomBar.findViewById(R.id.album_art);
+ trackView = (TextView) bottomBar.findViewById(R.id.track_name);
+ artistView = (TextView) bottomBar.findViewById(R.id.artist_name);
+
+ ImageButton previousButton = (ImageButton) findViewById(R.id.download_previous);
+ previousButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ if(getDownloadService() == null) {
+ return null;
+ }
+
+ getDownloadService().previous();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ update();
+ }
+ }.execute();
+ }
+ });
+
+ startButton = (ImageButton) findViewById(R.id.download_start);
+ startButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ PlayerState state = getDownloadService().getPlayerState();
+ if(state == PlayerState.STARTED) {
+ getDownloadService().pause();
+ } else {
+ getDownloadService().start();
+ }
+
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ update();
+ }
+ }.execute();
+ }
+ });
+
+ ImageButton nextButton = (ImageButton) findViewById(R.id.download_next);
+ nextButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ new SilentBackgroundTask<Void>(SubsonicFragmentActivity.this) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ if(getDownloadService() == null) {
+ return null;
+ }
+
+ if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
+ getDownloadService().next();
+ }
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ update();
+ }
+ }.execute();
+ }
+ });
+ }
+
+ @Override
+ protected void onPostCreate(Bundle bundle) {
+ super.onPostCreate(bundle);
+
+ showInfoDialog();
+ checkUpdates();
+
+ ChangeLog changeLog = new ChangeLog(this, Util.getPreferences(this));
+ if(changeLog.isFirstRun()) {
+ changeLog.getLogDialog().show();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ final Handler handler = new Handler();
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ update();
+ }
+ });
+ }
+ };
+
+ if(getIntent().hasExtra(Constants.INTENT_EXTRA_VIEW_ALBUM)) {
+ int fragmentID = R.id.fragment_list_layout;
+ if(getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID)) {
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID));
+ args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_PARENT_NAME));
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, R.id.fragment_list_layout, currentFragment.getSupportTag());
+ fragmentID = fragment.getRootId();
+ }
+
+ SubsonicFragment fragment = new SelectDirectoryFragment();
+ Bundle args = new Bundle();
+ args.putString(Constants.INTENT_EXTRA_NAME_ID, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_ID));
+ args.putString(Constants.INTENT_EXTRA_NAME_NAME, getIntent().getStringExtra(Constants.INTENT_EXTRA_NAME_NAME));
+ fragment.setArguments(args);
+
+ replaceFragment(fragment, fragmentID, currentFragment.getSupportTag());
+ getIntent().removeExtra(Constants.INTENT_EXTRA_VIEW_ALBUM);
+ }
+
+ executorService = Executors.newSingleThreadScheduledExecutor();
+ executorService.scheduleWithFixedDelay(runnable, 0L, 1000L, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ executorService.shutdown();
+ }
+
+ @Override
+ public void setContentView(int viewId) {
+ super.setContentView(viewId);
+ drawerToggle.setDrawerIndicatorEnabled(true);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void onBackPressed() {
+ if(onBackPressedSupport()) {
+ if(lastBackPressTime < (System.currentTimeMillis() - 4000)) {
+ lastBackPressTime = System.currentTimeMillis();
+ Util.toast(this, R.string.main_back_confirm);
+ } else {
+ finish();
+ }
+ }
+ }
+
+ @Override
+ public void replaceFragment(SubsonicFragment fragment, int id, int tag, boolean replaceCurrent) {
+ super.replaceFragment(fragment, id, tag, replaceCurrent);
+ drawerToggle.setDrawerIndicatorEnabled(false);
+ }
+ @Override
+ public void removeCurrent() {
+ super.removeCurrent();
+ if(backStack.isEmpty()) {
+ drawerToggle.setDrawerIndicatorEnabled(true);
+ }
+ }
+
+ @Override
+ public void startFragmentActivity(String fragmentType) {
+ // Create a transaction that does all of this
+ FragmentTransaction trans = getSupportFragmentManager().beginTransaction();
+
+ // Clear existing stack
+ for(int i = backStack.size() - 1; i >= 0; i--) {
+ trans.remove(backStack.get(i));
+ }
+ trans.remove(currentFragment);
+ backStack.clear();
+
+ // Create new stack
+ currentFragment = getNewFragment(fragmentType);
+ currentFragment.setPrimaryFragment(true);
+ trans.add(R.id.fragment_container, currentFragment, currentFragment.getSupportTag() + "");
+
+ // Done, cleanup
+ trans.commit();
+ supportInvalidateOptionsMenu();
+ recreateSpinner();
+ drawer.closeDrawers();
+
+ if(secondaryContainer != null) {
+ secondaryContainer.setVisibility(View.GONE);
+ }
+ drawerToggle.setDrawerIndicatorEnabled(true);
+ }
+
+ private SubsonicFragment getNewFragment(String fragmentType) {
+ if("Artist".equals(fragmentType)) {
+ return new SelectArtistFragment();
+ } else if("Playlist".equals(fragmentType)) {
+ return new SelectPlaylistFragment();
+ } else if("Chat".equals(fragmentType)) {
+ return new ChatFragment();
+ } else if("Podcast".equals(fragmentType)) {
+ return new SelectPodcastsFragment();
+ } else if("Bookmark".equals(fragmentType)) {
+ return new SelectBookmarkFragment();
+ } else {
+ return new MainFragment();
+ }
+ }
+
+ private void update() {
+ if (getDownloadService() == null) {
+ return;
+ }
+
+ DownloadFile current = getDownloadService().getCurrentPlaying();
+ if(current == null) {
+ trackView.setText("Title");
+ artistView.setText("Artist");
+ getImageLoader().loadImage(coverArtView, null, false, false);
+ return;
+ }
+
+ MusicDirectory.Entry song = current.getSong();
+ trackView.setText(song.getTitle());
+ artistView.setText(song.getArtist());
+ getImageLoader().loadImage(coverArtView, song, false, false);
+ int[] attrs = new int[] {(getDownloadService().getPlayerState() == PlayerState.STARTED) ? R.attr.media_button_pause : R.attr.media_button_start};
+ TypedArray typedArray = this.obtainStyledAttributes(attrs);
+ startButton.setImageResource(typedArray.getResourceId(0, 0));
+ typedArray.recycle();
+ }
+
+ public void checkUpdates() {
+ try {
+ String version = getPackageManager().getPackageInfo(getPackageName(), 0).versionName;
+ int ver = Integer.parseInt(version.replace(".", ""));
+ Updater updater = new Updater(ver);
+ updater.checkUpdates(this);
+ }
+ catch(Exception e) {
+
+ }
+ }
+
+ private void loadSettings() {
+ PreferenceManager.setDefaultValues(this, R.xml.settings, false);
+ SharedPreferences prefs = Util.getPreferences(this);
+ if (!prefs.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
+ editor.commit();
+ }
+
+ if (!prefs.contains(Constants.PREFERENCES_KEY_OFFLINE)) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(Constants.PREFERENCES_KEY_OFFLINE, false);
+
+ editor.putString(Constants.PREFERENCES_KEY_SERVER_NAME + 1, "Demo Server");
+ editor.putString(Constants.PREFERENCES_KEY_SERVER_URL + 1, "http://demo.subsonic.org");
+ editor.putString(Constants.PREFERENCES_KEY_USERNAME + 1, "android-guest");
+ editor.putString(Constants.PREFERENCES_KEY_PASSWORD + 1, "guest");
+ editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
+ editor.commit();
+ }
+ if(!prefs.contains(Constants.PREFERENCES_KEY_SERVER_COUNT)) {
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(Constants.PREFERENCES_KEY_SERVER_COUNT, 3);
+ editor.commit();
+ }
+ }
+
+ private void createAccount() {
+ AccountManager accountManager = (AccountManager) this.getSystemService(ACCOUNT_SERVICE);
+ Account account = new Account(Constants.SYNC_ACCOUNT_NAME, Constants.SYNC_ACCOUNT_TYPE);
+ accountManager.addAccountExplicitly(account, null, null);
+
+ SharedPreferences prefs = Util.getPreferences(this);
+ boolean syncEnabled = prefs.getBoolean(Constants.PREFERENCES_KEY_SYNC_ENABLED, true);
+ int syncInterval = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_SYNC_INTERVAL, "60"));
+
+ // Make sync run every hour
+ ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, syncEnabled);
+ ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PLAYLIST_AUTHORITY, new Bundle(), 60L * syncInterval);
+ ContentResolver.setSyncAutomatically(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, syncEnabled);
+ ContentResolver.addPeriodicSync(account, Constants.SYNC_ACCOUNT_PODCAST_AUTHORITY, new Bundle(), 60L * syncInterval);
+ }
+
+ private void showInfoDialog() {
+ if (!infoDialogDisplayed) {
+ infoDialogDisplayed = true;
+ Log.i(TAG, Util.getRestUrl(this, null));
+ if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) {
+ Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text);
+ }
+ }
+ }
+}
diff --git a/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java b/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java
index 5cda9ee5..e37696d5 100644
--- a/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java
+++ b/src/github/daneren2005/dsub/activity/VoiceQueryReceiverActivity.java
@@ -24,12 +24,14 @@ import android.app.SearchManager;
import android.content.Intent;
import android.os.Bundle;
import android.provider.SearchRecentSuggestions;
+
+import github.daneren2005.dsub.fragments.SubsonicFragment;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.Util;
import github.daneren2005.dsub.provider.DSubSearchProvider;
/**
- * Receives voice search queries and forwards to the SearchActivity.
+ * Receives voice search queries and forwards to the SearchFragment.
*
* http://android-developers.blogspot.com/2010/09/supporting-new-music-voice-action.html
*
@@ -48,9 +50,10 @@ public class VoiceQueryReceiverActivity extends Activity {
DSubSearchProvider.MODE);
suggestions.saveRecentQuery(query, null);
- Intent intent = new Intent(VoiceQueryReceiverActivity.this, SearchActivity.class);
+ Intent intent = new Intent(VoiceQueryReceiverActivity.this, SubsonicFragmentActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_NAME_QUERY, query);
intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
+ intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(VoiceQueryReceiverActivity.this, intent);
}
finish();
diff --git a/src/github/daneren2005/dsub/audiofx/EqualizerController.java b/src/github/daneren2005/dsub/audiofx/EqualizerController.java
index 0dcee863..0e1c49b5 100644
--- a/src/github/daneren2005/dsub/audiofx/EqualizerController.java
+++ b/src/github/daneren2005/dsub/audiofx/EqualizerController.java
@@ -80,7 +80,7 @@ public class EqualizerController {
public void loadSettings() {
try {
if (isAvailable()) {
- EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat");
+ EqualizerSettings settings = FileUtil.deserialize(context, "equalizer.dat", EqualizerSettings.class);
if (settings != null) {
settings.apply(equalizer);
}
@@ -95,7 +95,11 @@ public class EqualizerController {
}
public boolean isEnabled() {
- return isAvailable() && equalizer.getEnabled();
+ try {
+ return isAvailable() && equalizer.getEnabled();
+ } catch(Exception e) {
+ return false;
+ }
}
public void release() {
@@ -120,10 +124,13 @@ public class EqualizerController {
private static class EqualizerSettings implements Serializable {
- private final short[] bandLevels;
+ private short[] bandLevels;
private short preset;
- private final boolean enabled;
+ private boolean enabled;
+ public EqualizerSettings() {
+
+ }
public EqualizerSettings(Equalizer equalizer) {
enabled = equalizer.getEnabled();
bandLevels = new short[equalizer.getNumberOfBands()];
diff --git a/src/github/daneren2005/dsub/domain/Bookmark.java b/src/github/daneren2005/dsub/domain/Bookmark.java
new file mode 100644
index 00000000..d1f470ce
--- /dev/null
+++ b/src/github/daneren2005/dsub/domain/Bookmark.java
@@ -0,0 +1,102 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2013 (C) Scott Jackson
+ */
+package github.daneren2005.dsub.domain;
+
+import java.io.Serializable;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * Created by Scott on 11/4/13.
+ */
+public class Bookmark implements Serializable {
+ private int position;
+ private String username;
+ private String comment;
+ private Date created;
+ private Date changed;
+ private MusicDirectory.Entry entry;
+
+ public int getPosition() {
+ return position;
+ }
+
+ public void setPosition(int position) {
+ this.position = position;
+ }
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getComment() {
+ return comment;
+ }
+
+ public void setComment(String comment) {
+ this.comment = comment;
+ }
+
+ public Date getCreated() {
+ return created;
+ }
+
+ public void setCreated(String created) {
+ if (created != null) {
+ try {
+ this.created = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(created);
+ } catch (ParseException e) {
+ this.created = null;
+ }
+ } else {
+ this.created = null;
+ }
+ }
+
+ public Date getChanged() {
+ return changed;
+ }
+
+ public void setChanged(String changed) {
+ if (changed != null) {
+ try {
+ this.changed = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH).parse(changed);
+ } catch (ParseException e) {
+ this.changed = null;
+ }
+ } else {
+ this.changed = null;
+ }
+ }
+
+ public MusicDirectory.Entry getEntry() {
+ return this.entry;
+ }
+
+ public void setEntry(MusicDirectory.Entry entry) {
+ this.entry = entry;
+ }
+}
diff --git a/src/github/daneren2005/dsub/domain/Indexes.java b/src/github/daneren2005/dsub/domain/Indexes.java
index 0bc44158..67eb33bc 100644
--- a/src/github/daneren2005/dsub/domain/Indexes.java
+++ b/src/github/daneren2005/dsub/domain/Indexes.java
@@ -18,6 +18,7 @@
*/
package github.daneren2005.dsub.domain;
+import java.util.ArrayList;
import java.util.List;
import java.io.Serializable;
@@ -26,15 +27,33 @@ import java.io.Serializable;
*/
public class Indexes implements Serializable {
- private final long lastModified;
- private final List<Artist> shortcuts;
- private final List<Artist> artists;
+ private long lastModified;
+ private List<Artist> shortcuts;
+ private List<Artist> artists;
+ private List<MusicDirectory.Entry> entries;
+ public Indexes() {
+
+ }
public Indexes(long lastModified, List<Artist> shortcuts, List<Artist> artists) {
this.lastModified = lastModified;
this.shortcuts = shortcuts;
this.artists = artists;
+ this.entries = new ArrayList<MusicDirectory.Entry>();
}
+ public Indexes(long lastModified, List<Artist> shortcuts, List<Artist> artists, List<MusicDirectory.Entry> entries) {
+ this.lastModified = lastModified;
+ this.shortcuts = shortcuts;
+ this.artists = artists;
+ this.entries = entries;
+ if(!entries.isEmpty()) {
+ Artist root = new Artist();
+ root.setId("root");
+ root.setName("Root");
+ root.setIndex("#");
+ artists.add(root);
+ }
+ }
public long getLastModified() {
return lastModified;
@@ -47,4 +66,8 @@ public class Indexes implements Serializable {
public List<Artist> getArtists() {
return artists;
}
+
+ public List<MusicDirectory.Entry> getEntries() {
+ return entries;
+ }
} \ 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 c05d1631..0b9be5fb 100644
--- a/src/github/daneren2005/dsub/domain/MusicDirectory.java
+++ b/src/github/daneren2005/dsub/domain/MusicDirectory.java
@@ -18,9 +18,11 @@
*/
package github.daneren2005.dsub.domain;
+import android.media.MediaMetadataRetriever;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
+import java.io.File;
import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
@@ -28,7 +30,7 @@ import java.util.Comparator;
/**
* @author Sindre Mehus
*/
-public class MusicDirectory {
+public class MusicDirectory implements Serializable {
private static final String TAG = MusicDirectory.class.getSimpleName();
private String name;
@@ -121,6 +123,37 @@ public class MusicDirectory {
private Integer discNumber;
private boolean starred;
private int closeness;
+
+ public void loadMetadata(File file) {
+ try {
+ MediaMetadataRetriever metadata = new MediaMetadataRetriever();
+ metadata.setDataSource(file.getAbsolutePath());
+ String discNumber = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER);
+ if(discNumber == null) {
+ discNumber = "1/1";
+ }
+ int slashIndex = discNumber.indexOf("/");
+ if(slashIndex > 0) {
+ discNumber = discNumber.substring(0, slashIndex);
+ }
+ setDiscNumber(Integer.parseInt(discNumber));
+ String bitrate = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE);
+ setBitRate(Integer.parseInt((bitrate != null) ? bitrate : "0") / 1000);
+ String length = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
+ setDuration(Integer.parseInt(length) / 1000);
+ String artist = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
+ if(artist != null) {
+ setArtist(artist);
+ }
+ String album = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
+ if(album != null) {
+ setAlbum(album);
+ }
+ metadata.release();
+ } catch(Exception e) {
+ Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver");
+ }
+ }
public String getId() {
return id;
diff --git a/src/github/daneren2005/dsub/domain/MusicFolder.java b/src/github/daneren2005/dsub/domain/MusicFolder.java
index 68a22bcc..99e86e23 100644
--- a/src/github/daneren2005/dsub/domain/MusicFolder.java
+++ b/src/github/daneren2005/dsub/domain/MusicFolder.java
@@ -28,9 +28,12 @@ import java.io.Serializable;
*/
public class MusicFolder implements Serializable {
- private final String id;
- private final String name;
+ private String id;
+ private String name;
+ public MusicFolder() {
+
+ }
public MusicFolder(String id, String name) {
this.id = id;
this.name = name;
diff --git a/src/github/daneren2005/dsub/domain/Playlist.java b/src/github/daneren2005/dsub/domain/Playlist.java
index c97659c7..663fa2b0 100644
--- a/src/github/daneren2005/dsub/domain/Playlist.java
+++ b/src/github/daneren2005/dsub/domain/Playlist.java
@@ -33,6 +33,9 @@ public class Playlist implements Serializable {
private String created;
private Boolean pub;
+ public Playlist() {
+
+ }
public Playlist(String id, String name) {
this.id = id;
this.name = name;
diff --git a/src/github/daneren2005/dsub/fragments/ChatFragment.java b/src/github/daneren2005/dsub/fragments/ChatFragment.java
index 198b93a4..ca3a4f76 100644
--- a/src/github/daneren2005/dsub/fragments/ChatFragment.java
+++ b/src/github/daneren2005/dsub/fragments/ChatFragment.java
@@ -170,7 +170,7 @@ public class ChatFragment extends SubsonicFragment {
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.chat, menu);
+ menuInflater.inflate(R.menu.abstract_top_menu, menu);
}
@Override
diff --git a/src/github/daneren2005/dsub/fragments/DownloadFragment.java b/src/github/daneren2005/dsub/fragments/DownloadFragment.java
index f1f4b7c0..d46fbec6 100644
--- a/src/github/daneren2005/dsub/fragments/DownloadFragment.java
+++ b/src/github/daneren2005/dsub/fragments/DownloadFragment.java
@@ -40,12 +40,15 @@ import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.ViewFlipper;
import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.domain.RemoteControlState;
import github.daneren2005.dsub.domain.RepeatMode;
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.util.Constants;
import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.view.FadeOutAnimation;
@@ -59,8 +62,6 @@ import github.daneren2005.dsub.view.AutoRepeatButton;
import java.util.ArrayList;
import java.util.concurrent.ScheduledFuture;
import com.mobeta.android.dslv.*;
-import github.daneren2005.dsub.activity.EqualizerActivity;
-import github.daneren2005.dsub.activity.MainActivity;
import github.daneren2005.dsub.activity.SubsonicActivity;
public class DownloadFragment extends SubsonicFragment implements OnGestureListener {
@@ -92,11 +93,11 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
private Button jukeboxButton;
private View toggleListButton;
private ImageButton starButton;
+ private ImageButton bookmarkButton;
private View mainLayout;
private ScheduledExecutorService executorService;
private DownloadFile currentPlaying;
private long currentRevision;
- private GestureDetector gestureScanner;
private int swipeDistance;
private int swipeVelocity;
private VisualizerView visualizerView;
@@ -104,6 +105,8 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
private ScheduledFuture<?> hideControlsFuture;
private SongListAdapter songListAdapter;
private SilentBackgroundTask<Void> onProgressChangedTask;
+ private SilentBackgroundTask<Void> onCurrentChangedTask;
+ private SilentBackgroundTask<Void> onDownloadListChangedTask;
private boolean seekInProgress = false;
private boolean startFlipped = false;
@@ -119,6 +122,13 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
startFlipped = true;
}
}
+ Bundle args = getArguments();
+ if(args != null) {
+ if(args.getBoolean(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW)) {
+ startFlipped = true;
+ nowPlaying = false;
+ }
+ }
}
@Override
@@ -161,6 +171,7 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
equalizerButton = (Button)rootView.findViewById(R.id.download_equalizer);
visualizerButton = (Button)rootView.findViewById(R.id.download_visualizer);
jukeboxButton = (Button)rootView.findViewById(R.id.download_jukebox);
+ bookmarkButton = (ImageButton) rootView.findViewById(R.id.download_bookmark);
LinearLayout visualizerViewLayout = (LinearLayout)rootView.findViewById(R.id.download_visualizer_view_layout);
toggleListButton =rootView.findViewById(R.id.download_toggle_list);
@@ -189,6 +200,7 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
equalizerButton.setOnTouchListener(touchListener);
visualizerButton.setOnTouchListener(touchListener);
jukeboxButton.setOnTouchListener(touchListener);
+ bookmarkButton.setOnTouchListener(touchListener);
emptyTextView.setOnTouchListener(touchListener);
albumArtImageView.setOnTouchListener(touchListener);
@@ -225,12 +237,8 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
new SilentBackgroundTask<Boolean>(context) {
@Override
protected Boolean doInBackground() throws Throwable {
- if (getDownloadService().getCurrentPlayingIndex() < getDownloadService().size() - 1) {
- getDownloadService().next();
- return true;
- } else {
- return false;
- }
+ getDownloadService().next();
+ return true;
}
@Override
@@ -337,7 +345,8 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
DownloadService downloadService = getDownloadService();
if(downloadService != null && downloadService.getEqualizerController() != null
&& downloadService.getEqualizerController().getEqualizer() != null) {
- context.startActivity(new Intent(context, EqualizerActivity.class));
+ SubsonicFragment fragment = new EqualizerFragment();
+ replaceFragment(fragment, R.id.download_layout_container);
setControlsVisible(true);
} else {
Util.toast(context, "Failed to start equalizer. Try restarting.");
@@ -373,6 +382,13 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
}
});
+ bookmarkButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ createBookmark();
+ }
+ });
+
toggleListButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
@@ -470,17 +486,12 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
visualizerViewLayout.addView(visualizerView, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT, LinearLayout.LayoutParams.FILL_PARENT));
}
- // TODO: Extract to utility method and cache.
- Typeface typeface = Typeface.createFromAsset(context.getAssets(), "fonts/Storopia.ttf");
- equalizerButton.setTypeface(typeface);
- visualizerButton.setTypeface(typeface);
- jukeboxButton.setTypeface(typeface);
-
return rootView;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ DownloadService downloadService = getDownloadService();
if(Util.isOffline(context)) {
menuInflater.inflate(R.menu.nowplaying_offline, menu);
} else {
@@ -491,11 +502,11 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
menuInflater.inflate(R.menu.nowplaying_downloading, menu);
}
- if(getDownloadService() != null && getDownloadService().getSleepTimer()) {
+ if(downloadService != null && downloadService.getSleepTimer()) {
menu.findItem(R.id.menu_toggle_timer).setTitle(R.string.download_stop_timer);
}
}
- if(getDownloadService() != null && getDownloadService().getKeepScreenOn()) {
+ if(downloadService != null && downloadService.getKeepScreenOn()) {
menu.findItem(R.id.menu_screen_on_off).setTitle(R.string.download_menu_screen_off);
}
}
@@ -512,6 +523,10 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
@Override
public void onCreateContextMenu(android.view.ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
+
if (view == playlistView) {
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
DownloadFile downloadFile = (DownloadFile) playlistView.getItemAtPosition(info.position);
@@ -546,10 +561,11 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
case R.id.menu_show_album:
MusicDirectory.Entry entry = song.getSong();
- Intent intent = new Intent(context, MainActivity.class);
+ Intent intent = new Intent(context, SubsonicFragmentActivity.class);
intent.putExtra(Constants.INTENT_EXTRA_VIEW_ALBUM, true);
intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, entry.getParent());
intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, entry.getAlbum());
+ intent.putExtra(Constants.INTENT_EXTRA_FRAGMENT_TYPE, "Artist");
if(entry.getGrandParent() != null) {
intent.putExtra(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.getGrandParent());
@@ -604,24 +620,29 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
getDownloadService().delete(songs);
return true;
case R.id.menu_remove_all:
- new SilentBackgroundTask<Void>(context) {
+ Util.confirmDialog(context, R.string.download_menu_remove_all, "", new DialogInterface.OnClickListener() {
@Override
- protected Void doInBackground() throws Throwable {
- getDownloadService().setShufflePlayEnabled(false);
- if(nowPlaying) {
- getDownloadService().clear();
- }
- else {
- getDownloadService().clearBackground();
- }
- return null;
- }
+ public void onClick(DialogInterface dialog, int which) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ getDownloadService().setShufflePlayEnabled(false);
+ if(nowPlaying) {
+ getDownloadService().clear();
+ }
+ else {
+ getDownloadService().clearBackground();
+ }
+ return null;
+ }
- @Override
- protected void done(Void result) {
- onDownloadListChanged();
+ @Override
+ protected void done(Void result) {
+ onDownloadListChanged();
+ }
+ }.execute();
}
- }.execute();
+ });
return true;
case R.id.menu_screen_on_off:
if (getDownloadService().getKeepScreenOn()) {
@@ -736,6 +757,7 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
if(rootView != null) {
if(primary) {
mainLayout.setVisibility(View.VISIBLE);
+ updateButtons();
} else {
mainLayout.setVisibility(View.GONE);
}
@@ -776,6 +798,10 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
}
private void updateButtons() {
+ if(context == null) {
+ return;
+ }
+
SharedPreferences prefs = Util.getPreferences(context);
boolean equalizerOn = prefs.getBoolean(Constants.PREFERENCES_EQUALIZER_ON, false);
if(equalizerOn && getDownloadService() != null && getDownloadService().getEqualizerController() != null &&
@@ -791,6 +817,12 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
boolean jukeboxEnabled = getDownloadService() != null && getDownloadService().isRemoteEnabled();
jukeboxButton.setTextColor(jukeboxEnabled ? COLOR_BUTTON_ENABLED : COLOR_BUTTON_DISABLED);
+
+ if(Util.isOffline(context)) {
+ bookmarkButton.setVisibility(View.GONE);
+ } else {
+ bookmarkButton.setVisibility(View.VISIBLE);
+ }
}
// Scroll to current playing/downloading.
@@ -896,74 +928,119 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
private void onDownloadListChanged() {
onDownloadListChanged(false);
}
- private void onDownloadListChanged(boolean refresh) {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
+ private void onDownloadListChanged(final boolean refresh) {
+ final DownloadService downloadService = getDownloadService();
+ if (downloadService == null || onDownloadListChangedTask != null) {
return;
}
- List<DownloadFile> list;
- if(nowPlaying) {
- list = downloadService.getSongs();
- }
- else {
- list = downloadService.getBackgroundDownloads();
- }
+ onDownloadListChangedTask = new SilentBackgroundTask<Void>(context) {
+ int currentPlayingIndex;
+ int size;
- if(downloadService.isShufflePlayEnabled()) {
- emptyTextView.setText(R.string.download_shuffle_loading);
- }
- else {
- emptyTextView.setText(R.string.download_empty);
- }
+ @Override
+ protected Void doInBackground() throws Throwable {
+ currentPlayingIndex = downloadService.getCurrentPlayingIndex() + 1;
+ size = downloadService.size();
+ return null;
+ }
- if(songListAdapter == null || refresh) {
- playlistView.setAdapter(songListAdapter = new SongListAdapter(list));
- } else {
- songListAdapter.notifyDataSetChanged();
- }
- emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
- currentRevision = downloadService.getDownloadListUpdateRevision();
+ @Override
+ protected void done(Void result) {
+ List<DownloadFile> list;
+ if(nowPlaying) {
+ list = downloadService.getSongs();
+ }
+ else {
+ list = downloadService.getBackgroundDownloads();
+ }
- switch (downloadService.getRepeatMode()) {
- case OFF:
- if("light".equals(SubsonicActivity.getThemeName()) | "light_fullscreen".equals(SubsonicActivity.getThemeName())) {
- repeatButton.setImageResource(R.drawable.media_repeat_off_light);
+ if(downloadService.isShufflePlayEnabled()) {
+ emptyTextView.setText(R.string.download_shuffle_loading);
+ }
+ else {
+ emptyTextView.setText(R.string.download_empty);
+ }
+
+ if(songListAdapter == null || refresh) {
+ playlistView.setAdapter(songListAdapter = new SongListAdapter(list));
} else {
- repeatButton.setImageResource(R.drawable.media_repeat_off);
+ songListAdapter.notifyDataSetChanged();
}
- break;
- case ALL:
- repeatButton.setImageResource(R.drawable.media_repeat_all);
- break;
- case SINGLE:
- repeatButton.setImageResource(R.drawable.media_repeat_single);
- break;
- default:
- break;
- }
-
- setSubtitle(context.getResources().getString(R.string.download_playing_out_of, downloadService.getCurrentPlayingIndex() + 1, downloadService.size()));
+ emptyTextView.setVisibility(list.isEmpty() ? View.VISIBLE : View.GONE);
+ currentRevision = downloadService.getDownloadListUpdateRevision();
+
+ switch (downloadService.getRepeatMode()) {
+ case OFF:
+ if("light".equals(SubsonicActivity.getThemeName()) | "light_fullscreen".equals(SubsonicActivity.getThemeName())) {
+ repeatButton.setImageResource(R.drawable.media_repeat_off_light);
+ } else {
+ repeatButton.setImageResource(R.drawable.media_repeat_off);
+ }
+ break;
+ case ALL:
+ repeatButton.setImageResource(R.drawable.media_repeat_all);
+ break;
+ case SINGLE:
+ repeatButton.setImageResource(R.drawable.media_repeat_single);
+ break;
+ default:
+ break;
+ }
+
+ setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, size));
+ onDownloadListChangedTask = null;
+ if(onCurrentChangedTask != null) {
+ onCurrentChangedTask.execute();
+ } else if(onProgressChangedTask != null) {
+ onProgressChangedTask.execute();
+ }
+ }
+ };
+ onDownloadListChangedTask.execute();
}
private void onCurrentChanged() {
- DownloadService downloadService = getDownloadService();
- if (downloadService == null) {
+ final DownloadService downloadService = getDownloadService();
+ if (downloadService == null || onCurrentChangedTask != null) {
return;
}
+
+ onCurrentChangedTask = new SilentBackgroundTask<Void>(context) {
+ int currentPlayingIndex;
+ int currentPlayingSize;
- currentPlaying = downloadService.getCurrentPlaying();
- if (currentPlaying != null) {
- MusicDirectory.Entry song = currentPlaying.getSong();
- songTitleTextView.setText(song.getTitle());
- getImageLoader().loadImage(albumArtImageView, song, true, true);
- starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
- setSubtitle(context.getResources().getString(R.string.download_playing_out_of, downloadService.getCurrentPlayingIndex() + 1, downloadService.size()));
- } else {
- songTitleTextView.setText(null);
- getImageLoader().loadImage(albumArtImageView, null, true, false);
- starButton.setImageResource(android.R.drawable.btn_star_big_off);
- setSubtitle(null);
+ @Override
+ protected Void doInBackground() throws Throwable {
+ currentPlaying = downloadService.getCurrentPlaying();
+ currentPlayingIndex = downloadService.getCurrentPlayingIndex() + 1;
+ currentPlayingSize = downloadService.size();
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ if (currentPlaying != null) {
+ MusicDirectory.Entry song = currentPlaying.getSong();
+ songTitleTextView.setText(song.getTitle());
+ getImageLoader().loadImage(albumArtImageView, song, true, true);
+ starButton.setImageResource(song.isStarred() ? android.R.drawable.btn_star_big_on : android.R.drawable.btn_star_big_off);
+ setSubtitle(context.getResources().getString(R.string.download_playing_out_of, currentPlayingIndex, currentPlayingSize));
+ } else {
+ songTitleTextView.setText(null);
+ getImageLoader().loadImage(albumArtImageView, null, true, false);
+ starButton.setImageResource(android.R.drawable.btn_star_big_off);
+ setSubtitle(null);
+ }
+ onCurrentChangedTask = null;
+ if(onProgressChangedTask != null) {
+ onProgressChangedTask.execute();
+ }
+ }
+ };
+
+ if(onDownloadListChangedTask == null) {
+ onCurrentChangedTask.execute();
}
}
@@ -1057,7 +1134,9 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
onProgressChangedTask = null;
}
};
- onProgressChangedTask.execute();
+ if(onDownloadListChangedTask == null && onCurrentChangedTask == null) {
+ onProgressChangedTask.execute();
+ }
}
private void changeProgress(final int ms) {
@@ -1094,6 +1173,54 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
}
}.execute();
}
+
+ private void createBookmark() {
+ DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return;
+ }
+
+ final DownloadFile currentDownload = downloadService.getCurrentPlaying();
+ if(currentDownload == null) {
+ return;
+ }
+
+ View dialogView = context.getLayoutInflater().inflate(R.layout.create_bookmark, null);
+ final EditText commentBox = (EditText)dialogView.findViewById(R.id.comment_text);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(context);
+ builder.setTitle(R.string.download_save_bookmark_title)
+ .setView(dialogView)
+ .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ String comment = commentBox.getText().toString();
+
+ createBookmark(currentDownload, comment);
+ }
+ })
+ .setNegativeButton(R.string.common_cancel, null);
+ AlertDialog dialog = builder.create();
+ dialog.show();
+ }
+ private void createBookmark(final DownloadFile currentDownload, final String comment) {
+ new SilentBackgroundTask<Void>(context) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicDirectory.Entry currentSong = currentDownload.getSong();
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.createBookmark(currentSong.getId(), getDownloadService().getPlayerPosition(), comment, context, null);
+
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ Util.toast(context, R.string.download_save_bookmark);
+ setControlsVisible(true);
+ }
+ }.execute();
+ }
private class SongListAdapter extends ArrayAdapter<DownloadFile> {
public SongListAdapter(List<DownloadFile> entries) {
@@ -1120,10 +1247,6 @@ public class DownloadFragment extends SubsonicFragment implements OnGestureListe
return false;
}
- public GestureDetector getGestureDetector() {
- return gestureScanner;
- }
-
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
DownloadService downloadService = getDownloadService();
diff --git a/src/github/daneren2005/dsub/fragments/EqualizerFragment.java b/src/github/daneren2005/dsub/fragments/EqualizerFragment.java
new file mode 100644
index 00000000..8b2c5313
--- /dev/null
+++ b/src/github/daneren2005/dsub/fragments/EqualizerFragment.java
@@ -0,0 +1,286 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2010 (C) Sindre Mehus
+ */
+package github.daneren2005.dsub.fragments;
+
+import android.content.SharedPreferences;
+import android.media.audiofx.Equalizer;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+import android.widget.SeekBar;
+import android.widget.TextView;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.audiofx.EqualizerController;
+import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.Util;
+
+/**
+ * Created by Scott on 10/27/13.
+ */
+public class EqualizerFragment extends SubsonicFragment {
+ private static final String TAG = EqualizerFragment.class.getSimpleName();
+
+ private static final int MENU_GROUP_PRESET = 100;
+
+ private final Map<Short, SeekBar> bars = new HashMap<Short, SeekBar>();
+ private EqualizerController equalizerController;
+ private Equalizer equalizer;
+ private short masterLevel = 0;
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.equalizer, container, false);
+
+ equalizerController = DownloadServiceImpl.getInstance().getEqualizerController();
+ equalizer = equalizerController.getEqualizer();
+
+ initEqualizer();
+
+ final View presetButton = rootView.findViewById(R.id.equalizer_preset);
+ registerForContextMenu(presetButton);
+ presetButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ presetButton.showContextMenu();
+ }
+ });
+
+ CheckBox enabledCheckBox = (CheckBox) rootView.findViewById(R.id.equalizer_enabled);
+ enabledCheckBox.setChecked(equalizer.getEnabled());
+ enabledCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
+ setEqualizerEnabled(b);
+ }
+ });
+
+ setTitle(R.string.equalizer_label);
+
+ return rootView;
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ equalizerController.saveSettings();
+
+ if(!equalizer.getEnabled()) {
+ equalizerController.release();
+ }
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ equalizerController = DownloadServiceImpl.getInstance().getEqualizerController();
+ equalizer = equalizerController.getEqualizer();
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
+
+ short currentPreset;
+ try {
+ currentPreset = equalizer.getCurrentPreset();
+ } catch (Exception x) {
+ currentPreset = -1;
+ }
+
+ for (short preset = 0; preset < equalizer.getNumberOfPresets(); preset++) {
+ MenuItem menuItem = menu.add(MENU_GROUP_PRESET, preset, preset, equalizer.getPresetName(preset));
+ if (preset == currentPreset) {
+ menuItem.setChecked(true);
+ }
+ }
+ menu.setGroupCheckable(MENU_GROUP_PRESET, true, true);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ short preset = (short) menuItem.getItemId();
+ equalizer.usePreset(preset);
+ updateBars(false);
+ return true;
+ }
+
+ private void setEqualizerEnabled(boolean enabled) {
+ SharedPreferences prefs = Util.getPreferences(context);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putBoolean(Constants.PREFERENCES_EQUALIZER_ON, enabled);
+ editor.commit();
+ equalizer.setEnabled(enabled);
+ updateBars(true);
+ }
+
+ private void updateBars(boolean changedEnabled) {
+ boolean isEnabled = equalizer.getEnabled();
+ short minEQLevel = equalizer.getBandLevelRange()[0];
+ short maxEQLevel = equalizer.getBandLevelRange()[1];
+ for (Map.Entry<Short, SeekBar> entry : bars.entrySet()) {
+ short band = entry.getKey();
+ SeekBar bar = entry.getValue();
+ bar.setEnabled(isEnabled);
+ if(band >= (short)0) {
+ short setLevel;
+ if(changedEnabled) {
+ setLevel = (short)(equalizer.getBandLevel(band) - masterLevel);
+ if(isEnabled) {
+ bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
+ } else {
+ bar.setProgress(-minEQLevel);
+ }
+ } else {
+ bar.setProgress(equalizer.getBandLevel(band) - minEQLevel);
+ setLevel = (short)(equalizer.getBandLevel(band) + masterLevel);
+ }
+ if(setLevel < minEQLevel) {
+ setLevel = minEQLevel;
+ } else if(setLevel > maxEQLevel) {
+ setLevel = maxEQLevel;
+ }
+ equalizer.setBandLevel(band, setLevel);
+ } else if(!isEnabled) {
+ bar.setProgress(-minEQLevel);
+ }
+ }
+
+ if(!isEnabled) {
+ masterLevel = 0;
+ SharedPreferences prefs = Util.getPreferences(context);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel);
+ editor.commit();
+ }
+ }
+
+ private void initEqualizer() {
+ LinearLayout layout = (LinearLayout) rootView.findViewById(R.id.equalizer_layout);
+
+ final short minEQLevel = equalizer.getBandLevelRange()[0];
+ final short maxEQLevel = equalizer.getBandLevelRange()[1];
+
+ // Setup Pregain
+ SharedPreferences prefs = Util.getPreferences(context);
+ masterLevel = (short)prefs.getInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, 0);
+ initPregain(layout, minEQLevel, maxEQLevel);
+
+ for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
+ final short band = i;
+
+ View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null);
+ TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
+ final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
+ SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
+
+ freqTextView.setText((equalizer.getCenterFreq(band) / 1000) + " Hz");
+
+ bars.put(band, bar);
+ bar.setMax(maxEQLevel - minEQLevel);
+ short level = equalizer.getBandLevel(band);
+ if(equalizer.getEnabled()) {
+ level = (short) (level - masterLevel);
+ }
+ bar.setProgress(level - minEQLevel);
+ bar.setEnabled(equalizer.getEnabled());
+ updateLevelText(levelTextView, level);
+
+ bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ short level = (short) (progress + minEQLevel);
+ if (fromUser) {
+ equalizer.setBandLevel(band, (short)(level + masterLevel));
+ }
+ updateLevelText(levelTextView, level);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ layout.addView(bandBar);
+ }
+ }
+
+ private void initPregain(LinearLayout layout, final short minEQLevel, final short maxEQLevel) {
+ View bandBar = LayoutInflater.from(context).inflate(R.layout.equalizer_bar, null);
+ TextView freqTextView = (TextView) bandBar.findViewById(R.id.equalizer_frequency);
+ final TextView levelTextView = (TextView) bandBar.findViewById(R.id.equalizer_level);
+ SeekBar bar = (SeekBar) bandBar.findViewById(R.id.equalizer_bar);
+
+ freqTextView.setText("Master");
+
+ bars.put((short)-1, bar);
+ bar.setMax(maxEQLevel - minEQLevel);
+ bar.setProgress(masterLevel - minEQLevel);
+ bar.setEnabled(equalizer.getEnabled());
+ updateLevelText(levelTextView, masterLevel);
+
+ bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
+ @Override
+ public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
+ masterLevel = (short) (progress + minEQLevel);
+ if (fromUser) {
+ SharedPreferences prefs = Util.getPreferences(context);
+ SharedPreferences.Editor editor = prefs.edit();
+ editor.putInt(Constants.PREFERENCES_EQUALIZER_SETTINGS, masterLevel);
+ editor.commit();
+ for (short i = 0; i < equalizer.getNumberOfBands(); i++) {
+ short level = (short) ((bars.get(i).getProgress() + minEQLevel) + masterLevel);
+ equalizer.setBandLevel(i, level);
+ }
+ }
+ updateLevelText(levelTextView, masterLevel);
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ }
+ });
+ layout.addView(bandBar);
+ }
+
+ private void updateLevelText(TextView levelTextView, short level) {
+ levelTextView.setText((level > 0 ? "+" : "") + level / 100 + " dB");
+ }
+}
diff --git a/src/github/daneren2005/dsub/fragments/MainFragment.java b/src/github/daneren2005/dsub/fragments/MainFragment.java
index 05726483..0d865fe8 100644
--- a/src/github/daneren2005/dsub/fragments/MainFragment.java
+++ b/src/github/daneren2005/dsub/fragments/MainFragment.java
@@ -95,6 +95,9 @@ public class MainFragment extends SubsonicFragment {
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
int serverCount = Util.getServerCount(context);
int activeServer = Util.getActiveServer(context);
@@ -116,7 +119,6 @@ public class MainFragment extends SubsonicFragment {
int activeServer = menuItem.getItemId() - MENU_ITEM_SERVER_BASE;
setActiveServer(activeServer);
- context.getPagerAdapter().invalidate();
return true;
}
@@ -186,6 +188,7 @@ public class MainFragment extends SubsonicFragment {
}
}
});
+ setTitle(R.string.common_appname);
}
private void setActiveServer(int instance) {
@@ -195,13 +198,14 @@ public class MainFragment extends SubsonicFragment {
service.clearIncomplete();
}
Util.setActiveServer(context, instance);
+ context.invalidate();
}
}
private void toggleOffline() {
boolean isOffline = Util.isOffline(context);
Util.setOffline(context, !isOffline);
- context.getPagerAdapter().invalidate();
+ context.invalidate();
if(isOffline) {
int scrobblesCount = Util.offlineScrobblesCount(context);
diff --git a/src/github/daneren2005/dsub/fragments/SearchFragment.java b/src/github/daneren2005/dsub/fragments/SearchFragment.java
index 6fa86737..900872da 100644
--- a/src/github/daneren2005/dsub/fragments/SearchFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SearchFragment.java
@@ -18,11 +18,9 @@ import android.view.MenuItem;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
-import android.widget.TextView;
import android.net.Uri;
import android.view.ViewGroup;
import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.activity.SearchActivity;
import github.daneren2005.dsub.domain.Artist;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.SearchCritera;
@@ -53,7 +51,6 @@ public class SearchFragment extends SubsonicFragment {
private View artistsHeading;
private View albumsHeading;
private View songsHeading;
- private TextView searchButton;
private View moreArtistsButton;
private View moreAlbumsButton;
private View moreSongsButton;
@@ -84,7 +81,7 @@ public class SearchFragment extends SubsonicFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.search, container, false);
+ rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false);
setTitle(R.string.search_title);
View buttons = inflater.inflate(R.layout.search_buttons, null);
@@ -93,19 +90,16 @@ public class SearchFragment extends SubsonicFragment {
albumsHeading = buttons.findViewById(R.id.search_albums);
songsHeading = buttons.findViewById(R.id.search_songs);
- searchButton = (TextView) buttons.findViewById(R.id.search_search);
moreArtistsButton = buttons.findViewById(R.id.search_more_artists);
moreAlbumsButton = buttons.findViewById(R.id.search_more_albums);
moreSongsButton = buttons.findViewById(R.id.search_more_songs);
- list = (ListView) rootView.findViewById(R.id.search_list);
+ list = (ListView) rootView.findViewById(R.id.fragment_list);
list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- if (view == searchButton) {
- context.onSearchRequested();
- } else if (view == moreArtistsButton) {
+ if (view == moreArtistsButton) {
expandArtists();
} else if (view == moreAlbumsButton) {
expandAlbums();
@@ -130,7 +124,7 @@ public class SearchFragment extends SubsonicFragment {
}
});
registerForContextMenu(list);
- ((SearchActivity)context).onSupportNewIntent(context.getIntent());
+ context.onNewIntent(context.getIntent());
if(searchResult != null) {
skipSearch = true;
@@ -157,6 +151,9 @@ public class SearchFragment extends SubsonicFragment {
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
Object selectedItem = list.getItemAtPosition(info.position);
@@ -186,7 +183,7 @@ public class SearchFragment extends SubsonicFragment {
public void setPrimaryFragment(boolean primary) {
super.setPrimaryFragment(primary);
if(rootView != null && primary) {
- ((SearchActivity)context).onSupportNewIntent(context.getIntent());
+ context.onNewIntent(context.getIntent());
}
}
@@ -221,7 +218,6 @@ public class SearchFragment extends SubsonicFragment {
public void populateList() {
mergeAdapter = new MergeAdapter();
- mergeAdapter.addView(searchButton, true);
if (searchResult != null) {
List<Artist> artists = searchResult.getArtists();
@@ -258,7 +254,6 @@ public class SearchFragment extends SubsonicFragment {
}
boolean empty = searchResult.getArtists().isEmpty() && searchResult.getAlbums().isEmpty() && searchResult.getSongs().isEmpty();
- searchButton.setText(empty ? R.string.search_no_match : R.string.search_search);
}
list.setAdapter(mergeAdapter);
@@ -301,11 +296,11 @@ public class SearchFragment extends SubsonicFragment {
args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
fragment.setArguments(args);
- replaceFragment(fragment, R.id.search_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
}
private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) {
- int id = R.id.search_layout;
+ int id = R.id.fragment_list_layout;
Bundle args;
if(album.getParent() != null) {
SubsonicFragment parentFragment = new SelectDirectoryFragment();
@@ -314,7 +309,7 @@ public class SearchFragment extends SubsonicFragment {
args.putString(Constants.INTENT_EXTRA_NAME_NAME, album.getArtist());
parentFragment.setArguments(args);
- replaceFragment(parentFragment, R.id.search_layout);
+ replaceFragment(parentFragment, R.id.fragment_list_layout);
id = parentFragment.getRootId();
}
diff --git a/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java b/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java
index b11f6fe7..ed629a15 100644
--- a/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SelectArtistFragment.java
@@ -17,6 +17,7 @@ import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.Artist;
import github.daneren2005.dsub.domain.Indexes;
+import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.MusicFolder;
import github.daneren2005.dsub.service.MusicService;
import github.daneren2005.dsub.service.MusicServiceFactory;
@@ -40,6 +41,7 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
private View folderButton;
private TextView folderName;
private List<MusicFolder> musicFolders = null;
+ private List<MusicDirectory.Entry> entries;
private List<Artist> artists;
@Override
@@ -61,9 +63,9 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_artist, container, false);
+ rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false);
- artistList = (ListView) rootView.findViewById(R.id.select_artist_list);
+ artistList = (ListView) rootView.findViewById(R.id.fragment_list);
artistList.setOnItemClickListener(this);
folderButtonParent = inflater.inflate(R.layout.select_artist_header, artistList, false);
@@ -103,6 +105,9 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
Object entry = artistList.getItemAtPosition(info.position);
@@ -146,7 +151,7 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
: selectedFolder.getName();
Util.setSelectedMusicFolderId(context, musicFolderId);
folderName.setText(musicFolderName);
- refresh();
+ context.invalidate();
}
return true;
@@ -162,9 +167,13 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, artist.getId());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, artist.getName());
+ if("root".equals(artist.getId())) {
+ Log.d(TAG, "root");
+ args.putSerializable(Constants.FRAGMENT_LIST, (Serializable) entries);
+ }
fragment.setArguments(args);
- replaceFragment(fragment, R.id.select_artist_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
}
}
@@ -174,7 +183,7 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
}
private void load(final boolean refresh) {
- setTitle(R.string.search_artists);
+ setTitle(R.string.button_bar_browse);
if (Util.isOffline(context)) {
folderButton.setVisibility(View.GONE);
@@ -199,7 +208,10 @@ public class SelectArtistFragment extends SubsonicFragment implements AdapterVie
artists = new ArrayList<Artist>(result.getShortcuts().size() + result.getArtists().size());
artists.addAll(result.getShortcuts());
artists.addAll(result.getArtists());
+ artistList.setFastScrollEnabled(false);
artistList.setAdapter(new ArtistAdapter(context, artists));
+ artistList.setFastScrollEnabled(true);
+ entries = result.getEntries();
setMusicFolders();
artistList.setVisibility(View.VISIBLE);
diff --git a/src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java b/src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java
new file mode 100644
index 00000000..dc892634
--- /dev/null
+++ b/src/github/daneren2005/dsub/fragments/SelectBookmarkFragment.java
@@ -0,0 +1,238 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2010 (C) Sindre Mehus
+*/
+package github.daneren2005.dsub.fragments;
+
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ListView;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.activity.DownloadActivity;
+import github.daneren2005.dsub.domain.Bookmark;
+import github.daneren2005.dsub.domain.MusicDirectory;
+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.BackgroundTask;
+import github.daneren2005.dsub.util.Constants;
+import github.daneren2005.dsub.util.LoadingTask;
+import github.daneren2005.dsub.util.TabBackgroundTask;
+import github.daneren2005.dsub.util.Util;
+import github.daneren2005.dsub.view.BookmarkAdapter;
+import java.io.Serializable;
+import java.text.Format;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SelectBookmarkFragment extends SubsonicFragment implements AdapterView.OnItemClickListener {
+ private static final String TAG = SelectBookmarkFragment.class.getSimpleName();
+ private ListView bookmarkListView;
+ private View emptyView;
+ private List<Bookmark> bookmarks;
+ private BookmarkAdapter bookmarkAdapter;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ super.onCreate(bundle);
+
+ if(bundle != null) {
+ bookmarks = (List<Bookmark>) bundle.getSerializable(Constants.FRAGMENT_LIST);
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putSerializable(Constants.FRAGMENT_LIST, (Serializable) bookmarks);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
+ rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false);
+
+ bookmarkListView = (ListView)rootView.findViewById(R.id.fragment_list);
+ bookmarkListView.setOnItemClickListener(this);
+ registerForContextMenu(bookmarkListView);
+ emptyView = rootView.findViewById(R.id.fragment_list_empty);
+
+ if(bookmarks == null) {
+ refresh();
+ } else {
+ bookmarkListView.setAdapter(new BookmarkAdapter(context, bookmarks));
+ }
+
+ return rootView;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ menuInflater.inflate(R.menu.abstract_top_menu, menu);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if(super.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @Override
+ public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
+ super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
+
+ MenuInflater inflater = context.getMenuInflater();
+ inflater.inflate(R.menu.select_bookmark_context, menu);
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem menuItem) {
+ if(!primaryFragment) {
+ return false;
+ }
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo();
+ Bookmark bookmark = bookmarks.get(info.position);
+
+ switch(menuItem.getItemId()) {
+ case R.id.bookmark_menu_info:
+ displayBookmarkInfo(bookmark);
+ break;
+ case R.id.bookmark_menu_delete:
+ deleteBookmark(bookmark);
+ break;
+ }
+
+ if(onContextItemSelected(menuItem, bookmark.getEntry())) {
+ return true;
+ }
+
+ return true;
+ }
+
+ @Override
+ protected void refresh(final boolean refresh) {
+ setTitle(R.string.button_bar_bookmarks);
+ bookmarkListView.setVisibility(View.INVISIBLE);
+
+ BackgroundTask<List<Bookmark>> task = new TabBackgroundTask<List<Bookmark>>(this) {
+ @Override
+ protected List<Bookmark> doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+
+ bookmarks = new ArrayList<Bookmark>();
+
+ try {
+ bookmarks = musicService.getBookmarks(refresh, context, this);
+ } catch (Exception x) {
+ Log.e(TAG, "Failed to load bookmarks", x);
+ }
+
+ return bookmarks;
+ }
+
+ @Override
+ protected void done(List<Bookmark> result) {
+ emptyView.setVisibility(result == null || result.isEmpty() ? View.VISIBLE : View.GONE);
+
+ if (result != null) {
+ bookmarkListView.setAdapter(bookmarkAdapter = new BookmarkAdapter(context, result));
+ bookmarkListView.setVisibility(View.VISIBLE);
+ }
+ }
+ };
+ task.execute();
+ }
+
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ DownloadService downloadService = getDownloadService();
+ if(downloadService == null) {
+ return;
+ }
+
+ Bookmark bookmark = (Bookmark) parent.getItemAtPosition(position);
+ downloadService.download(bookmark);
+ Util.startActivityWithoutTransition(context, DownloadActivity.class);
+ }
+
+ private void displayBookmarkInfo(final Bookmark bookmark) {
+ Format formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+ String comment = bookmark.getComment();
+ if(comment == null) {
+ comment = "";
+ }
+
+ String msg = context.getResources().getString(R.string.bookmark_details,
+ bookmark.getEntry().getTitle(), Util.formatDuration(bookmark.getPosition() / 1000),
+ formatter.format(bookmark.getCreated()), formatter.format(bookmark.getChanged()), comment);
+
+ Util.info(context, R.string.bookmark_details_title, msg, false);
+ }
+ private void deleteBookmark(final Bookmark bookmark) {
+ final MusicDirectory.Entry entry = bookmark.getEntry();
+ Util.confirmDialog(context, R.string.bookmark_delete_title, entry.getTitle(), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ new LoadingTask<Void>(context, false) {
+ @Override
+ protected Void doInBackground() throws Throwable {
+ MusicService musicService = MusicServiceFactory.getMusicService(context);
+ musicService.deleteBookmark(entry.getId(), context, null);
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
+ bookmarkAdapter.remove(bookmark);
+ bookmarkAdapter.notifyDataSetChanged();
+ Util.toast(context, context.getResources().getString(R.string.bookmark_deleted, entry.getTitle()));
+ }
+
+ @Override
+ protected void error(Throwable error) {
+ String msg;
+ if (error instanceof OfflineException || error instanceof ServerTooOldException) {
+ msg = getErrorMessage(error);
+ } else {
+ msg = context.getResources().getString(R.string.bookmark_deleted_error, entry.getTitle()) + " " + 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 c5489c6c..0081f881 100644
--- a/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SelectDirectoryFragment.java
@@ -14,18 +14,17 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
-import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.view.EntryAdapter;
import java.io.Serializable;
import java.util.List;
import com.mobeta.android.dslv.*;
import github.daneren2005.dsub.activity.DownloadActivity;
-import github.daneren2005.dsub.activity.SearchActivity;
import github.daneren2005.dsub.domain.PodcastEpisode;
import github.daneren2005.dsub.service.MusicService;
import github.daneren2005.dsub.service.MusicServiceFactory;
@@ -47,7 +46,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
private DragSortListView entryList;
int rootId;
- private View footer;
private View emptyView;
private boolean hideButtons = false;
private Boolean licenseValid;
@@ -65,6 +63,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
String albumListType;
String albumListExtra;
int albumListSize;
+ boolean refreshListing = false;
public SelectDirectoryFragment() {
@@ -97,7 +96,6 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
rootView.setId(rootId);
entryList = (DragSortListView) rootView.findViewById(R.id.select_album_entries);
- footer = LayoutInflater.from(context).inflate(R.layout.select_album_footer, entryList, false);
entryList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
entryList.setOnItemClickListener(this);
entryList.setDropListener(new DragSortListView.DropListener() {
@@ -131,10 +129,14 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
albumListType = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE);
albumListExtra = args.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA);
albumListSize = args.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0);
+ refreshListing = args.getBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS);
+ if(entries == null) {
+ entries = (List<MusicDirectory.Entry>) args.getSerializable(Constants.FRAGMENT_LIST);
+ }
}
if(entries == null) {
- if(primaryFragment) {
+ if(primaryFragment || secondaryFragment) {
load(false);
} else {
invalidated = true;
@@ -233,6 +235,10 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
+
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
MusicDirectory.Entry entry = (MusicDirectory.Entry) entryList.getItemAtPosition(info.position);
@@ -287,6 +293,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
Bundle args = new Bundle();
args.putString(Constants.INTENT_EXTRA_NAME_ID, entry.getParent());
args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getArtist());
+ if("recent".equals(albumListType)) {
+ args.putBoolean(Constants.INTENT_EXTRA_REFRESH_LISTINGS, true);
+ }
parentFragment.setArguments(args);
replaceFragment(parentFragment, fragId);
@@ -299,7 +308,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
args.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.getTitle());
fragment.setArguments(args);
- replaceFragment(fragment, fragId);
+ replaceFragment(fragment, fragId, fragId == rootId);
} else if (entry.isVideo()) {
playVideo(entry);
} else if(entry instanceof PodcastEpisode) {
@@ -323,7 +332,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
@Override
protected void refresh(boolean refresh) {
- load(refresh);
+ if(!"root".equals(id)) {
+ load(refresh);
+ }
}
@Override
@@ -332,12 +343,16 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
private void load(boolean refresh) {
+ if(refreshListing) {
+ refresh = true;
+ }
+
entryList.setVisibility(View.INVISIBLE);
emptyView.setVisibility(View.INVISIBLE);
if (playlistId != null) {
- getPlaylist(playlistId, playlistName);
+ getPlaylist(playlistId, playlistName, refresh);
} else if(podcastId != null) {
- getPodcast(podcastId, podcastName);
+ getPodcast(podcastId, podcastName, refresh);
} else if (albumListType != null) {
getAlbumList(albumListType, albumListSize);
} else {
@@ -356,24 +371,24 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}.execute();
}
- private void getPlaylist(final String playlistId, final String playlistName) {
+ private void getPlaylist(final String playlistId, final String playlistName, final boolean refresh) {
setTitle(playlistName);
new LoadTask() {
@Override
protected MusicDirectory load(MusicService service) throws Exception {
- return service.getPlaylist(playlistId, playlistName, context, this);
+ return service.getPlaylist(refresh, playlistId, playlistName, context, this);
}
}.execute();
}
- private void getPodcast(final String podcastId, final String podcastName) {
+ private void getPodcast(final String podcastId, final String podcastName, final boolean refresh) {
setTitle(podcastName);
new LoadTask() {
@Override
protected MusicDirectory load(MusicService service) throws Exception {
- return service.getPodcastEpisodes(podcastId, context, this);
+ return service.getPodcastEpisodes(refresh, podcastId, context, this);
}
}.execute();
}
@@ -445,7 +460,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
}
- if (songCount > 0) {
+ if (songCount > 0 && !"root".equals(id)) {
if(showHeader) {
View header = createHeader(entries);
if(header != null) {
@@ -454,7 +469,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
} else {
showHeader = false;
- hideButtons = true;
+ if(!"root".equals(id)) {
+ hideButtons = true;
+ }
}
emptyView.setVisibility(entries.isEmpty() ? View.VISIBLE : View.GONE);
@@ -563,31 +580,33 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
}
final List<MusicDirectory.Entry> songs = getSelectedSongs();
- Runnable onValid = new Runnable() {
+ warnIfNetworkOrStorageUnavailable();
+ LoadingTask<Void> onValid = new LoadingTask<Void>(context) {
@Override
- public void run() {
+ protected Void doInBackground() throws Throwable {
if (!append) {
getDownloadService().clear();
}
- warnIfNetworkOrStorageUnavailable();
getDownloadService().download(songs, save, autoplay, playNext, shuffle);
if (playlistName != null) {
getDownloadService().setSuggestedPlaylistName(playlistName, playlistId);
} else {
getDownloadService().setSuggestedPlaylistName(null, null);
}
+ return null;
+ }
+
+ @Override
+ protected void done(Void result) {
if (autoplay) {
Util.startActivityWithoutTransition(context, DownloadActivity.class);
- if(context instanceof SearchActivity) {
- context.finish();
- }
} else if (save) {
Util.toast(context,
- context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
+ context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
} else if (append) {
Util.toast(context,
- context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
+ context.getResources().getQuantityString(R.plurals.select_album_n_songs_added, songs.size(), songs.size()));
}
}
};
@@ -607,14 +626,17 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
return;
}
- Runnable onValid = new Runnable() {
+ warnIfNetworkOrStorageUnavailable();
+ LoadingTask<Void> onValid = new LoadingTask<Void>(context) {
@Override
- public void run() {
- warnIfNetworkOrStorageUnavailable();
+ protected Void doInBackground() throws Throwable {
getDownloadService().downloadBackground(songs, save);
+ return null;
+ }
- Util.toast(context,
- context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
+ @Override
+ protected void done(Void result) {
+ Util.toast(context, context.getResources().getQuantityString(R.plurals.select_album_n_songs_downloading, songs.size(), songs.size()));
}
};
@@ -722,6 +744,11 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.deletePodcastEpisode(episode.getEpisodeId(), context, null);
+ if (getDownloadService() != null) {
+ List<MusicDirectory.Entry> episodeList = new ArrayList<MusicDirectory.Entry>(1);
+ episodeList.add(episode);
+ getDownloadService().delete(episodeList);
+ }
return null;
}
@@ -740,9 +767,9 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
});
}
- private void checkLicenseAndTrialPeriod(Runnable onValid) {
+ private void checkLicenseAndTrialPeriod(LoadingTask onValid) {
if (licenseValid) {
- onValid.run();
+ onValid.execute();
return;
}
@@ -755,11 +782,11 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
showDonationDialog(trialDaysLeft, onValid);
} else {
Util.toast(context, context.getResources().getString(R.string.select_album_not_licensed, trialDaysLeft));
- onValid.run();
+ onValid.execute();
}
}
- private void showDonationDialog(int trialDaysLeft, final Runnable onValid) {
+ private void showDonationDialog(int trialDaysLeft, final LoadingTask onValid) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setIcon(android.R.drawable.ic_dialog_info);
@@ -786,7 +813,7 @@ public class SelectDirectoryFragment extends SubsonicFragment implements Adapter
public void onClick(DialogInterface dialogInterface, int i) {
dialogInterface.dismiss();
if (onValid != null) {
- onValid.run();
+ onValid.execute();
}
}
});
diff --git a/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java b/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java
index 2a6693ca..4f0b8a03 100644
--- a/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SelectGenreFragment.java
@@ -64,11 +64,11 @@ public class SelectGenreFragment extends SubsonicFragment implements AdapterView
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_genres, container, false);
+ rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false);
- genreListView = (ListView)rootView.findViewById(R.id.select_genre_list);
+ genreListView = (ListView)rootView.findViewById(R.id.fragment_list);
genreListView.setOnItemClickListener(this);
- emptyView = rootView.findViewById(R.id.select_genre_empty);
+ emptyView = rootView.findViewById(R.id.fragment_list_empty);
if(genres == null) {
refresh();
@@ -81,6 +81,10 @@ public class SelectGenreFragment extends SubsonicFragment implements AdapterView
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
+ if(!primaryFragment) {
+ return;
+ }
+
menuInflater.inflate(R.menu.select_genres, menu);
}
@@ -92,18 +96,6 @@ public class SelectGenreFragment extends SubsonicFragment implements AdapterView
return false;
}
-
- @Override
- public void setPrimaryFragment(boolean primary) {
- super.setPrimaryFragment(primary);
- if(rootView != null) {
- if(primary) {
- ((ViewGroup)rootView).getChildAt(0).setVisibility(View.VISIBLE);
- } else {
- ((ViewGroup)rootView).getChildAt(0).setVisibility(View.GONE);
- }
- }
- }
@Override
protected void refresh(boolean refresh) {
@@ -155,6 +147,6 @@ public class SelectGenreFragment extends SubsonicFragment implements AdapterView
args.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_EXTRA, genre.getName());
fragment.setArguments(args);
- replaceFragment(fragment, R.id.select_genre_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
}
}
diff --git a/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java b/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
index 48338b3d..01c9d938 100644
--- a/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SelectPlaylistFragment.java
@@ -59,10 +59,10 @@ public class SelectPlaylistFragment extends SubsonicFragment implements AdapterV
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_playlist, container, false);
+ rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false);
- list = (ListView) rootView.findViewById(R.id.select_playlist_list);
- emptyTextView = rootView.findViewById(R.id.select_playlist_empty);
+ list = (ListView) rootView.findViewById(R.id.fragment_list);
+ emptyTextView = rootView.findViewById(R.id.fragment_list_empty);
list.setOnItemClickListener(this);
registerForContextMenu(list);
@@ -81,7 +81,7 @@ public class SelectPlaylistFragment extends SubsonicFragment implements AdapterV
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) {
- menuInflater.inflate(R.menu.select_playlist, menu);
+ menuInflater.inflate(R.menu.abstract_top_menu, menu);
}
@Override
@@ -96,6 +96,9 @@ public class SelectPlaylistFragment extends SubsonicFragment implements AdapterV
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
MenuInflater inflater = context.getMenuInflater();
if (Util.isOffline(context)) {
@@ -133,7 +136,7 @@ public class SelectPlaylistFragment extends SubsonicFragment implements AdapterV
args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
fragment.setArguments(args);
- replaceFragment(fragment, R.id.select_playlist_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
break;
case R.id.playlist_menu_play_shuffled:
fragment = new SelectDirectoryFragment();
@@ -144,7 +147,7 @@ public class SelectPlaylistFragment extends SubsonicFragment implements AdapterV
args.putBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true);
fragment.setArguments(args);
- replaceFragment(fragment, R.id.select_playlist_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
break;
case R.id.playlist_menu_delete:
deletePlaylist(playlist);
@@ -171,7 +174,7 @@ public class SelectPlaylistFragment extends SubsonicFragment implements AdapterV
args.putString(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName());
fragment.setArguments(args);
- replaceFragment(fragment, R.id.select_playlist_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
}
@Override
diff --git a/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java b/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
index e9a06076..143ff229 100644
--- a/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SelectPodcastsFragment.java
@@ -81,12 +81,12 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
- rootView = inflater.inflate(R.layout.select_podcasts, container, false);
+ rootView = inflater.inflate(R.layout.abstract_list_fragment, container, false);
- podcastListView = (ListView)rootView.findViewById(R.id.select_podcasts_list);
+ podcastListView = (ListView)rootView.findViewById(R.id.fragment_list);
podcastListView.setOnItemClickListener(this);
registerForContextMenu(podcastListView);
- emptyView = rootView.findViewById(R.id.select_podcasts_empty);
+ emptyView = rootView.findViewById(R.id.fragment_list_empty);
if(channels == null) {
if(!primaryFragment) {
@@ -127,6 +127,10 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
@Override
public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) {
super.onCreateContextMenu(menu, view, menuInfo);
+ if(!primaryFragment) {
+ return;
+ }
+
if(!Util.isOffline(context)) {
android.view.MenuInflater inflater = context.getMenuInflater();
inflater.inflate(R.menu.select_podcasts_context, menu);
@@ -205,7 +209,7 @@ public class SelectPodcastsFragment extends SubsonicFragment implements AdapterV
args.putString(Constants.INTENT_EXTRA_NAME_PODCAST_DESCRIPTION, channel.getDescription());
fragment.setArguments(args);
- replaceFragment(fragment, R.id.select_podcasts_layout);
+ replaceFragment(fragment, R.id.fragment_list_layout);
}
}
diff --git a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
index 0d79ceda..d33c1b96 100644
--- a/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
+++ b/src/github/daneren2005/dsub/fragments/SubsonicFragment.java
@@ -32,6 +32,7 @@ import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.ContextMenu;
+import android.view.GestureDetector;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
@@ -41,11 +42,9 @@ import android.widget.EditText;
import android.widget.TextView;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.activity.DownloadActivity;
-import github.daneren2005.dsub.activity.HelpActivity;
-import github.daneren2005.dsub.activity.MainActivity;
-import github.daneren2005.dsub.activity.SearchActivity;
import github.daneren2005.dsub.activity.SettingsActivity;
import github.daneren2005.dsub.activity.SubsonicActivity;
+import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.domain.Artist;
import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.MusicDirectory;
@@ -65,6 +64,7 @@ import github.daneren2005.dsub.util.SilentBackgroundTask;
import github.daneren2005.dsub.util.LoadingTask;
import github.daneren2005.dsub.util.Util;
import java.io.File;
+import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -85,8 +85,10 @@ public class SubsonicFragment extends Fragment {
protected CharSequence subtitle = null;
protected View rootView;
protected boolean primaryFragment = false;
+ protected boolean secondaryFragment = false;
protected boolean invalidated = false;
protected static Random random = new Random();
+ protected GestureDetector gestureScanner;
public SubsonicFragment() {
super();
@@ -96,6 +98,19 @@ public class SubsonicFragment extends Fragment {
@Override
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
+
+ if(bundle != null) {
+ String name = bundle.getString(Constants.FRAGMENT_NAME);
+ if(name != null) {
+ title = name;
+ }
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putString(Constants.FRAGMENT_NAME, title.toString());
}
@Override
@@ -129,12 +144,6 @@ public class SubsonicFragment extends Fragment {
case R.id.menu_exit:
exit();
return true;
- case R.id.menu_settings:
- startActivity(new Intent(context, SettingsActivity.class));
- return true;
- case R.id.menu_help:
- startActivity(new Intent(context, HelpActivity.class));
- return true;
}
return false;
@@ -237,9 +246,6 @@ public class SubsonicFragment extends Fragment {
getDownloadService().clear();
getDownloadService().download(songs, false, true, true, false);
Util.startActivityWithoutTransition(context, DownloadActivity.class);
- if(context instanceof SearchActivity) {
- context.finish();
- }
break;
case R.id.song_menu_play_next:
getDownloadService().download(songs, false, false, true, false);
@@ -279,7 +285,10 @@ public class SubsonicFragment extends Fragment {
}
public void replaceFragment(SubsonicFragment fragment, int id) {
- context.replaceFragment(fragment, id, fragment.getSupportTag());
+ replaceFragment(fragment, id, true);
+ }
+ public void replaceFragment(SubsonicFragment fragment, int id, boolean replaceCurrent) {
+ context.replaceFragment(fragment, id, fragment.getSupportTag(), secondaryFragment && replaceCurrent);
}
protected int getNewId() {
@@ -296,7 +305,9 @@ public class SubsonicFragment extends Fragment {
public int getRootId() {
return rootView.getId();
}
-
+
+ public void setSupportTag(int tag) { this.tag = tag; }
+ public void setSupportTag(String tag) { this.tag = Integer.parseInt(tag); }
public int getSupportTag() {
return tag;
}
@@ -314,10 +325,14 @@ public class SubsonicFragment extends Fragment {
}
}
}
-
+ public void setPrimaryFragment(boolean primary, boolean secondary) {
+ setPrimaryFragment(primary);
+ secondaryFragment = secondary;
+ }
+
public void invalidate() {
if(primaryFragment) {
- refresh(false);
+ refresh(true);
} else {
invalidated = true;
}
@@ -335,8 +350,8 @@ public class SubsonicFragment extends Fragment {
}
protected void exit() {
- if(context.getClass() != MainActivity.class) {
- Intent intent = new Intent(context, MainActivity.class);
+ if(context.getClass() != SubsonicFragmentActivity.class) {
+ Intent intent = new Intent(context, SubsonicFragmentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true);
Util.startActivityWithoutTransition(context, intent);
@@ -512,6 +527,12 @@ public class SubsonicFragment extends Fragment {
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
musicService.setStarred(entry.getId(), starred, context, null);
+
+ // Make sure to clear parent cache
+ String s = Util.getRestUrl(context, null) + entry.getParent();
+ String parentCache = "directory-" + s.hashCode() + ".ser";
+ File file = new File(context.getCacheDir(), parentCache);
+ file.delete();
return null;
}
@@ -587,7 +608,7 @@ public class SubsonicFragment extends Fragment {
if(isDirectory)
root = musicService.getMusicDirectory(id, name, false, context, this);
else
- root = musicService.getPlaylist(id, name, context, this);
+ root = musicService.getPlaylist(true, id, name, context, this);
List<MusicDirectory.Entry> songs = new LinkedList<MusicDirectory.Entry>();
getSongsRecursively(root, songs);
return songs;
@@ -621,9 +642,6 @@ public class SubsonicFragment extends Fragment {
downloadService.download(songs, save, autoplay, false, shuffle);
if(!append) {
Util.startActivityWithoutTransition(context, DownloadActivity.class);
- if(context instanceof SearchActivity) {
- context.finish();
- }
}
}
else {
@@ -792,7 +810,7 @@ public class SubsonicFragment extends Fragment {
@Override
protected Void doInBackground() throws Throwable {
MusicService musicService = MusicServiceFactory.getMusicService(context);
- MusicDirectory playlist = musicService.getPlaylist(id, name, context, null);
+ MusicDirectory playlist = musicService.getPlaylist(true, id, name, context, null);
List<MusicDirectory.Entry> toDelete = playlist.getChildren();
musicService.overwritePlaylist(id, name, toDelete.size(), songs, context, null);
return null;
@@ -960,6 +978,8 @@ public class SubsonicFragment extends Fragment {
public void deleteRecursively(Artist artist) {
File dir = FileUtil.getArtistDirectory(context, artist);
+ if(dir == null) return;
+
Util.recursiveDelete(dir);
if(Util.isOffline(context)) {
refresh();
@@ -968,9 +988,15 @@ public class SubsonicFragment extends Fragment {
public void deleteRecursively(MusicDirectory.Entry album) {
File dir = FileUtil.getAlbumDirectory(context, album);
+ if(dir == null) return;
+
Util.recursiveDelete(dir);
if(Util.isOffline(context)) {
refresh();
}
}
+
+ public GestureDetector getGestureDetector() {
+ return gestureScanner;
+ }
}
diff --git a/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java b/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java
index 7215040c..3b4e545f 100644
--- a/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java
+++ b/src/github/daneren2005/dsub/provider/DSubWidgetProvider.java
@@ -25,6 +25,7 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
+import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
@@ -36,16 +37,17 @@ import android.graphics.RectF;
import android.os.Environment;
import android.util.Log;
import android.view.KeyEvent;
+import android.view.View;
import android.widget.RemoteViews;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.activity.DownloadActivity;
-import github.daneren2005.dsub.activity.MainActivity;
+import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.service.DownloadService;
import github.daneren2005.dsub.service.DownloadServiceImpl;
import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.FileUtil;
-import java.util.HashMap;
+import github.daneren2005.dsub.util.Util;
/**
* Simple widget to show currently playing album art along
@@ -143,6 +145,16 @@ public class DSubWidgetProvider extends AppWidgetProvider {
final Resources res = context.getResources();
final RemoteViews views = new RemoteViews(context.getPackageName(), getLayout());
+ if(playing) {
+ views.setViewVisibility(R.id.widget_root, View.VISIBLE);
+ } else {
+ // Hide widget
+ SharedPreferences prefs = Util.getPreferences(context);
+ if(prefs.getBoolean(Constants.PREFERENCES_KEY_HIDE_WIDGET, false)) {
+ views.setViewVisibility(R.id.widget_root, View.GONE);
+ }
+ }
+
MusicDirectory.Entry currentPlaying = service.getCurrentPlaying() == null ? null : service.getCurrentPlaying().getSong();
String title = currentPlaying == null ? null : currentPlaying.getTitle();
CharSequence artist = currentPlaying == null ? null : currentPlaying.getArtist();
@@ -243,10 +255,10 @@ public class DSubWidgetProvider extends AppWidgetProvider {
*
* @param playerActive True if player is active in background, which means
* widget click will launch {@link DownloadActivity},
- * otherwise we launch {@link MainActivity}.
+ * otherwise we launch {@link github.daneren2005.dsub.activity.SubsonicFragmentActivity}.
*/
private void linkButtons(Context context, RemoteViews views, boolean playerActive) {
- Intent intent = new Intent(context, MainActivity.class);
+ Intent intent = new Intent(context, SubsonicFragmentActivity.class);
if(playerActive) {
intent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
diff --git a/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java b/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java
index 567cf8f4..ab46c784 100644
--- a/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java
+++ b/src/github/daneren2005/dsub/receiver/BluetoothIntentReceiver.java
@@ -22,8 +22,10 @@ import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
+import android.content.SharedPreferences;
import android.util.Log;
import github.daneren2005.dsub.service.DownloadServiceImpl;
+import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.Util;
/**
@@ -44,7 +46,11 @@ public class BluetoothIntentReceiver extends BroadcastReceiver {
Util.registerMediaButtonEventReceiver(context);
} else if (isDisconnected(intent)) {
Log.i(TAG, "Disconnected from Bluetooth A2DP, requesting pause.");
- context.sendBroadcast(new Intent(DownloadServiceImpl.CMD_PAUSE));
+ SharedPreferences prefs = Util.getPreferences(context);
+ int pausePref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT, "0"));
+ if(pausePref == 0 || pausePref == 2) {
+ context.sendBroadcast(new Intent(DownloadServiceImpl.CMD_PAUSE));
+ }
}
}
private boolean isConnected(Intent intent) {
@@ -75,4 +81,4 @@ public class BluetoothIntentReceiver extends BroadcastReceiver {
}
return false;
}
-} \ No newline at end of file
+}
diff --git a/src/github/daneren2005/dsub/service/CachedMusicService.java b/src/github/daneren2005/dsub/service/CachedMusicService.java
index cc8d2dbd..5a7737de 100644
--- a/src/github/daneren2005/dsub/service/CachedMusicService.java
+++ b/src/github/daneren2005/dsub/service/CachedMusicService.java
@@ -18,6 +18,8 @@
*/
package github.daneren2005.dsub.service;
+import java.io.File;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -26,6 +28,8 @@ import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;
+
+import github.daneren2005.dsub.domain.Bookmark;
import github.daneren2005.dsub.domain.ChatMessage;
import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
@@ -42,6 +46,7 @@ import github.daneren2005.dsub.domain.Version;
import github.daneren2005.dsub.util.CancellableTask;
import github.daneren2005.dsub.util.ProgressListener;
import github.daneren2005.dsub.util.TimeLimitedCache;
+import github.daneren2005.dsub.util.FileUtil;
import github.daneren2005.dsub.util.Util;
/**
@@ -92,7 +97,14 @@ public class CachedMusicService implements MusicService {
}
List<MusicFolder> result = cachedMusicFolders.get();
if (result == null) {
- result = musicService.getMusicFolders(refresh, context, progressListener);
+ if(!refresh) {
+ result = FileUtil.deserialize(context, getCacheName(context, "musicFolders"), ArrayList.class);
+ }
+
+ if(result == null) {
+ result = musicService.getMusicFolders(refresh, context, progressListener);
+ FileUtil.serialize(context, new ArrayList<MusicFolder>(result), getCacheName(context, "musicFolders"));
+ }
cachedMusicFolders.set(result);
}
return result;
@@ -120,7 +132,14 @@ public class CachedMusicService implements MusicService {
TimeLimitedCache<MusicDirectory> cache = refresh ? null : cachedMusicDirectories.get(id);
MusicDirectory dir = cache == null ? null : cache.get();
if (dir == null) {
- dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener);
+ if(!refresh) {
+ dir = FileUtil.deserialize(context, getCacheName(context, "directory", id), MusicDirectory.class);
+ }
+
+ if(dir == null) {
+ dir = musicService.getMusicDirectory(id, name, refresh, context, progressListener);
+ FileUtil.serialize(context, dir, getCacheName(context, "directory", id));
+ }
cache = new TimeLimitedCache<MusicDirectory>(TTL_MUSIC_DIR, TimeUnit.SECONDS);
cache.set(dir);
cachedMusicDirectories.put(id, cache);
@@ -134,8 +153,16 @@ public class CachedMusicService implements MusicService {
}
@Override
- public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception {
- return musicService.getPlaylist(id, name, context, progressListener);
+ public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception {
+ MusicDirectory dir = null;
+ if(!refresh) {
+ dir = FileUtil.deserialize(context, getCacheName(context, "playlist", id), MusicDirectory.class);
+ }
+ if(dir == null) {
+ dir = musicService.getPlaylist(refresh, id, name, context, progressListener);
+ FileUtil.serialize(context, dir, getCacheName(context, "playlist", id));
+ }
+ return dir;
}
@Override
@@ -143,7 +170,14 @@ public class CachedMusicService implements MusicService {
checkSettingsChanged(context);
List<Playlist> result = refresh ? null : cachedPlaylists.get();
if (result == null) {
- result = musicService.getPlaylists(refresh, context, progressListener);
+ if(!refresh) {
+ result = FileUtil.deserialize(context, getCacheName(context, "playlist"), ArrayList.class);
+ }
+
+ if(result == null) {
+ result = musicService.getPlaylists(refresh, context, progressListener);
+ FileUtil.serialize(context, new ArrayList<Playlist>(result), getCacheName(context, "playlist"));
+ }
cachedPlaylists.set(result);
}
return result;
@@ -152,11 +186,13 @@ public class CachedMusicService implements MusicService {
@Override
public void createPlaylist(String id, String name, List<MusicDirectory.Entry> entries, Context context, ProgressListener progressListener) throws Exception {
cachedPlaylists.clear();
+ Util.delete(new File(context.getCacheDir(), getCacheName(context, "playlist")));
musicService.createPlaylist(id, name, entries, context, progressListener);
}
@Override
public void deletePlaylist(String id, Context context, ProgressListener progressListener) throws Exception {
+ Util.delete(new File(context.getCacheDir(), getCacheName(context, "playlist")));
musicService.deletePlaylist(id, context, progressListener);
}
@@ -296,7 +332,14 @@ public class CachedMusicService implements MusicService {
List<Genre> result = refresh ? null : cachedGenres.get();
if (result == null) {
- result = musicService.getGenres(refresh, context, progressListener);
+ if(!refresh) {
+ result = FileUtil.deserialize(context, getCacheName(context, "genre"), ArrayList.class);
+ }
+
+ if(result == null) {
+ result = musicService.getGenres(refresh, context, progressListener);
+ FileUtil.serialize(context, new ArrayList<Genre>(result), getCacheName(context, "genre"));
+ }
cachedGenres.set(result);
}
@@ -314,7 +357,14 @@ public class CachedMusicService implements MusicService {
List<PodcastChannel> result = refresh ? null : cachedPodcastChannels.get();
if (result == null) {
- result = musicService.getPodcastChannels(refresh, context, progressListener);
+ if(!refresh) {
+ result = FileUtil.deserialize(context, getCacheName(context, "podcast"), ArrayList.class);
+ }
+
+ if(result == null) {
+ result = musicService.getPodcastChannels(refresh, context, progressListener);
+ FileUtil.serialize(context, new ArrayList<PodcastChannel>(result), getCacheName(context, "podcast"));
+ }
cachedPodcastChannels.set(result);
}
@@ -322,8 +372,8 @@ public class CachedMusicService implements MusicService {
}
@Override
- public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception {
- return musicService.getPodcastEpisodes(id, context, progressListener);
+ public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception {
+ return musicService.getPodcastEpisodes(refresh, id, context, progressListener);
}
@Override
@@ -333,11 +383,15 @@ public class CachedMusicService implements MusicService {
@Override
public void createPodcastChannel(String url, Context context, ProgressListener progressListener) throws Exception{
+ Util.delete(new File(context.getCacheDir(), getCacheName(context, "podcast")));
+ cachedPodcastChannels.clear();
musicService.createPodcastChannel(url, context, progressListener);
}
@Override
public void deletePodcastChannel(String id, Context context, ProgressListener progressListener) throws Exception{
+ Util.delete(new File(context.getCacheDir(), getCacheName(context, "podcast")));
+ cachedPodcastChannels.clear();
musicService.deletePodcastChannel(id, context, progressListener);
}
@@ -350,13 +404,40 @@ public class CachedMusicService implements MusicService {
public void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{
musicService.deletePodcastEpisode(id, context, progressListener);
}
-
+
+ @Override
+ public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception {
+ musicService.setRating(id, rating, context, progressListener);
+ }
+
+ @Override
+ public List<Bookmark> getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
+ return musicService.getBookmarks(refresh, context, progressListener);
+ }
+
+ @Override
+ public void createBookmark(String id, int position, String comment, Context context, ProgressListener progressListener) throws Exception {
+ musicService.createBookmark(id, position, comment, context, progressListener);
+ }
+
+ @Override
+ public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception {
+ musicService.deleteBookmark(id, context, progressListener);
+ }
+
@Override
public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{
return musicService.processOfflineSyncs(context, progressListener);
}
-
+ private String getCacheName(Context context, String name, String id) {
+ String s = Util.getRestUrl(context, null) + id;
+ return name + "-" + s.hashCode() + ".ser";
+ }
+ private String getCacheName(Context context, String name) {
+ String s = Util.getRestUrl(context, null);
+ return name + "-" + s.hashCode() + ".ser";
+ }
private void checkSettingsChanged(Context context) {
String newUrl = Util.getRestUrl(context, null);
diff --git a/src/github/daneren2005/dsub/service/DownloadFile.java b/src/github/daneren2005/dsub/service/DownloadFile.java
index 5ab7ad70..c2cffdef 100644
--- a/src/github/daneren2005/dsub/service/DownloadFile.java
+++ b/src/github/daneren2005/dsub/service/DownloadFile.java
@@ -30,6 +30,7 @@ import android.os.PowerManager;
import android.util.DisplayMetrics;
import android.util.Log;
import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.service.parser.SubsonicRESTException;
import github.daneren2005.dsub.util.CancellableTask;
import github.daneren2005.dsub.util.FileUtil;
import github.daneren2005.dsub.util.Util;
@@ -44,8 +45,8 @@ import org.apache.http.HttpStatus;
* @version $Id$
*/
public class DownloadFile {
-
private static final String TAG = DownloadFile.class.getSimpleName();
+ private static final int MAX_FAILURES = 5;
private final Context context;
private final MusicDirectory.Entry song;
private final File partialFile;
@@ -55,7 +56,8 @@ public class DownloadFile {
private final MediaStoreService mediaStoreService;
private CancellableTask downloadTask;
private boolean save;
- private boolean failed;
+ private boolean failedDownload = false;
+ private int failed = 0;
private int bitRate;
private boolean isPlaying = false;
private boolean saveWhenDone = false;
@@ -98,7 +100,7 @@ public class DownloadFile {
public synchronized void download() {
FileUtil.createDirectoryForParent(saveFile);
- failed = false;
+ failedDownload = false;
if(!partialFile.exists()) {
bitRate = Util.getMaxBitrate(context);
}
@@ -153,7 +155,10 @@ public class DownloadFile {
}
public boolean isFailed() {
- return failed;
+ return failedDownload;
+ }
+ public boolean isFailedMax() {
+ return failed > MAX_FAILURES;
}
public void delete() {
@@ -212,11 +217,18 @@ public class DownloadFile {
completeWhenDone = false;
}
} catch(IOException ex) {
- Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile);
+ Log.w(TAG, "Failed to rename file " + completeFile + " to " + saveFile, ex);
}
this.isPlaying = isPlaying;
}
+ public void renamePartial() {
+ try {
+ Util.renameFile(partialFile, completeFile);
+ } catch(IOException ex) {
+ Log.w(TAG, "Failed to rename file " + partialFile + " to " + completeFile, ex);
+ }
+ }
public boolean getPlaying() {
return isPlaying;
}
@@ -314,12 +326,21 @@ public class DownloadFile {
}
}
+ } catch(SubsonicRESTException x) {
+ Util.close(out);
+ Util.delete(completeFile);
+ Util.delete(saveFile);
+ if (!isCancelled()) {
+ failed++;
+ failedDownload = true;
+ Log.w(TAG, "Failed to download '" + song + "'.", x);
+ }
} catch (Exception x) {
Util.close(out);
Util.delete(completeFile);
Util.delete(saveFile);
if (!isCancelled()) {
- failed = true;
+ failedDownload = true;
Log.w(TAG, "Failed to download '" + song + "'.", x);
}
diff --git a/src/github/daneren2005/dsub/service/DownloadService.java b/src/github/daneren2005/dsub/service/DownloadService.java
index 7e8c8c81..1a254c73 100644
--- a/src/github/daneren2005/dsub/service/DownloadService.java
+++ b/src/github/daneren2005/dsub/service/DownloadService.java
@@ -22,6 +22,7 @@ import java.util.List;
import github.daneren2005.dsub.audiofx.EqualizerController;
import github.daneren2005.dsub.audiofx.VisualizerController;
+import github.daneren2005.dsub.domain.Bookmark;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.domain.RemoteControlState;
@@ -33,6 +34,7 @@ import github.daneren2005.dsub.domain.RepeatMode;
*/
public interface DownloadService {
+ void download(Bookmark bookmark);
void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle);
void downloadBackground(List<MusicDirectory.Entry> songs, boolean save);
diff --git a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
index 66d31a0f..e379291f 100644
--- a/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
+++ b/src/github/daneren2005/dsub/service/DownloadServiceImpl.java
@@ -28,6 +28,7 @@ import static github.daneren2005.dsub.domain.PlayerState.STARTED;
import static github.daneren2005.dsub.domain.PlayerState.STOPPED;
import github.daneren2005.dsub.audiofx.EqualizerController;
import github.daneren2005.dsub.audiofx.VisualizerController;
+import github.daneren2005.dsub.domain.Bookmark;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.domain.RemoteControlState;
@@ -115,6 +116,8 @@ public class DownloadServiceImpl extends Service implements DownloadService {
private PowerManager.WakeLock wakeLock;
private boolean keepScreenOn;
private int cachedPosition = 0;
+ private long downloadRevision;
+ private boolean downloadOngoing = false;
private static boolean equalizerAvailable;
private static boolean visualizerAvailable;
@@ -268,6 +271,17 @@ public class DownloadServiceImpl extends Service implements DownloadService {
return binder;
}
+ @Override
+ public synchronized void download(Bookmark bookmark) {
+ clear();
+ DownloadFile downloadFile = new DownloadFile(this, bookmark.getEntry(), false);
+ downloadList.add(downloadFile);
+ revision++;
+ updateJukeboxPlaylist();
+ play(0, true, bookmark.getPosition());
+ lifecycleSupport.serializeDownloadQueue();
+ }
+
@Override
public synchronized void download(List<MusicDirectory.Entry> songs, boolean save, boolean autoplay, boolean playNext, boolean shuffle) {
setShufflePlayEnabled(false);
@@ -318,7 +332,10 @@ public class DownloadServiceImpl extends Service implements DownloadService {
public synchronized void downloadBackground(List<MusicDirectory.Entry> songs, boolean save) {
for (MusicDirectory.Entry song : songs) {
DownloadFile downloadFile = new DownloadFile(this, song, save);
- backgroundDownloadList.add(downloadFile);
+ if(!downloadFile.isWorkDone() || (downloadFile.shouldSave() && !downloadFile.isSaved())) {
+ // Only add to list if there is work to be done
+ backgroundDownloadList.add(downloadFile);
+ }
}
revision++;
@@ -578,21 +595,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
return;
}
- int index = getCurrentPlayingIndex();
- if (index != -1) {
- switch (getRepeatMode()) {
- case OFF:
- index = index + 1;
- break;
- case ALL:
- index = (index + 1) % size();
- break;
- case SINGLE:
- break;
- default:
- break;
- }
- }
+ int index = getNextPlayingIndex();
nextSetup = false;
if(nextPlayingTask != null) {
@@ -613,6 +616,24 @@ public class DownloadServiceImpl extends Service implements DownloadService {
public synchronized int getCurrentPlayingIndex() {
return downloadList.indexOf(currentPlaying);
}
+ private int getNextPlayingIndex() {
+ int index = getCurrentPlayingIndex();
+ if (index != -1) {
+ switch (getRepeatMode()) {
+ case OFF:
+ index = index + 1;
+ break;
+ case ALL:
+ index = (index + 1) % size();
+ break;
+ case SINGLE:
+ break;
+ default:
+ break;
+ }
+ }
+ return index;
+ }
@Override
public DownloadFile getCurrentPlaying() {
@@ -657,8 +678,10 @@ public class DownloadServiceImpl extends Service implements DownloadService {
public synchronized void play(int index) {
play(index, true);
}
-
- private synchronized void play(int index, boolean start) {
+ private synchronized void play(int index, boolean start) {
+ play(index, start, 0);
+ }
+ private synchronized void play(int index, boolean start, int position) {
if (index < 0 || index >= size()) {
reset();
setCurrentPlaying(null, false);
@@ -674,7 +697,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
remoteController.changeTrack(index, downloadList.get(index));
setPlayerState(STARTED);
} else {
- bufferAndPlay();
+ bufferAndPlay(position);
}
}
if (remoteState == RemoteControlState.LOCAL) {
@@ -761,28 +784,18 @@ public class DownloadServiceImpl extends Service implements DownloadService {
@Override
public synchronized void next() {
int index = getCurrentPlayingIndex();
- if (index != -1) {
- play(index + 1);
+ int nextPlayingIndex = getNextPlayingIndex();
+ // Make sure to actually go to next when repeat song is on
+ if(index == nextPlayingIndex) {
+ nextPlayingIndex++;
+ }
+ if (index != -1 && nextPlayingIndex < size()) {
+ play(nextPlayingIndex);
}
}
private void onSongCompleted() {
- int index = getCurrentPlayingIndex();
- if (index != -1) {
- switch (getRepeatMode()) {
- case OFF:
- play(index + 1);
- break;
- case ALL:
- play((index + 1) % size());
- break;
- case SINGLE:
- play(index);
- break;
- default:
- break;
- }
- }
+ play(getNextPlayingIndex());
}
@Override
@@ -1072,14 +1085,17 @@ public class DownloadServiceImpl extends Service implements DownloadService {
remoteController.setVolume(up);
}
- private synchronized void bufferAndPlay() {
+ private synchronized void bufferAndPlay() {
+ bufferAndPlay(0);
+ }
+ private synchronized void bufferAndPlay(int position) {
if(playerState != PREPARED) {
reset();
- bufferTask = new BufferTask(currentPlaying, 0);
+ bufferTask = new BufferTask(currentPlaying, position);
bufferTask.start();
} else {
- doPlay(currentPlaying, 0, true);
+ doPlay(currentPlaying, position, true);
}
}
@@ -1138,7 +1154,10 @@ public class DownloadServiceImpl extends Service implements DownloadService {
}
}
- lifecycleSupport.serializeDownloadQueue();
+ // Only call when starting, setPlayerState(PAUSED) already calls this
+ if(start) {
+ lifecycleSupport.serializeDownloadQueue();
+ }
} catch (Exception x) {
handleError(x);
}
@@ -1158,6 +1177,8 @@ public class DownloadServiceImpl extends Service implements DownloadService {
final File file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
if(nextMediaPlayer != null) {
nextMediaPlayer.setOnCompletionListener(null);
+ nextMediaPlayer.setOnErrorListener(null);
+ nextMediaPlayer.reset();
nextMediaPlayer.release();
nextMediaPlayer = null;
}
@@ -1345,7 +1366,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
checkShufflePlay();
}
- if (remoteState != RemoteControlState.LOCAL || !Util.isNetworkConnected(this)) {
+ if (remoteState != RemoteControlState.LOCAL || !Util.isNetworkConnected(this) || Util.isOffline(this)) {
return;
}
@@ -1380,7 +1401,7 @@ public class DownloadServiceImpl extends Service implements DownloadService {
int i = start;
do {
DownloadFile downloadFile = downloadList.get(i);
- if (!downloadFile.isWorkDone()) {
+ if (!downloadFile.isWorkDone() && !downloadFile.isFailedMax()) {
if (downloadFile.shouldSave() || preloaded < Util.getPreloadCount(this)) {
currentDownloading = downloadFile;
currentDownloading.download();
@@ -1407,15 +1428,26 @@ public class DownloadServiceImpl extends Service implements DownloadService {
revision++;
i--;
} else {
- currentDownloading = downloadFile;
- currentDownloading.download();
- cleanupCandidates.add(currentDownloading);
- break;
+ if(!downloadFile.isFailedMax()) {
+ currentDownloading = downloadFile;
+ currentDownloading.download();
+ cleanupCandidates.add(currentDownloading);
+ break;
+ }
}
}
}
}
+ if(!backgroundDownloadList.isEmpty() && downloadRevision != revision) {
+ Util.showDownloadingNotification(this, currentDownloading, backgroundDownloadList.size());
+ downloadRevision = revision;
+ downloadOngoing = true;
+ } else if(backgroundDownloadList.isEmpty() && downloadOngoing) {
+ Util.hideDownloadingNotification(this);
+ downloadOngoing = false;
+ }
+
// Delete obsolete .partial and .complete files.
cleanup();
}
diff --git a/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java b/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java
index 4e3ec29c..563565b2 100644
--- a/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java
+++ b/src/github/daneren2005/dsub/service/DownloadServiceLifecycleSupport.java
@@ -31,6 +31,7 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.media.RemoteControlClient;
import android.os.AsyncTask;
import android.os.Build;
@@ -43,6 +44,7 @@ import android.view.KeyEvent;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.util.CacheCleaner;
+import github.daneren2005.dsub.util.Constants;
import github.daneren2005.dsub.util.FileUtil;
import github.daneren2005.dsub.util.Util;
@@ -52,7 +54,7 @@ import github.daneren2005.dsub.util.Util;
public class DownloadServiceLifecycleSupport {
private static final String TAG = DownloadServiceLifecycleSupport.class.getSimpleName();
- private static final String FILENAME_DOWNLOADS_SER = "downloadstate.ser";
+ private static final String FILENAME_DOWNLOADS_SER = "downloadstate2.ser";
private final DownloadServiceImpl downloadService;
private Looper eventLooper;
@@ -141,7 +143,11 @@ public class DownloadServiceLifecycleSupport {
@Override
public void run() {
if(!downloadService.isRemoteEnabled()) {
- downloadService.pause();
+ SharedPreferences prefs = Util.getPreferences(downloadService);
+ int pausePref = Integer.parseInt(prefs.getString(Constants.PREFERENCES_KEY_PAUSE_DISCONNECT, "0"));
+ if(pausePref == 0 || pausePref == 1) {
+ downloadService.pause();
+ }
}
}
});
@@ -252,20 +258,29 @@ public class DownloadServiceLifecycleSupport {
state.currentPlayingIndex = downloadService.getCurrentPlayingIndex();
state.currentPlayingPosition = downloadService.getPlayerPosition();
+ DownloadFile currentPlaying = downloadService.getCurrentPlaying();
+ if(currentPlaying != null) {
+ state.renameCurrent = currentPlaying.isWorkDone() && !currentPlaying.isCompleteFileAvailable();
+ }
+
Log.i(TAG, "Serialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
FileUtil.serialize(downloadService, state, FILENAME_DOWNLOADS_SER);
}
private void deserializeDownloadQueueNow() {
- State state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER);
+ State state = FileUtil.deserialize(downloadService, FILENAME_DOWNLOADS_SER, State.class);
if (state == null) {
return;
}
Log.i(TAG, "Deserialized currentPlayingIndex: " + state.currentPlayingIndex + ", currentPlayingPosition: " + state.currentPlayingPosition);
- downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition);
- // Work-around: Serialize again, as the restore() method creates a serialization without current playing info.
- serializeDownloadQueue();
+ // Rename first thing before anything else starts
+ if(state.renameCurrent && state.currentPlayingIndex != -1 && state.currentPlayingIndex < state.songs.size()) {
+ DownloadFile currentPlaying = new DownloadFile(downloadService, state.songs.get(state.currentPlayingIndex), false);
+ currentPlaying.renamePartial();
+ }
+
+ downloadService.restore(state.songs, state.currentPlayingIndex, state.currentPlayingPosition);
}
private void handleKeyEvent(KeyEvent event) {
@@ -363,5 +378,6 @@ public class DownloadServiceLifecycleSupport {
private List<MusicDirectory.Entry> songs = new ArrayList<MusicDirectory.Entry>();
private int currentPlayingIndex;
private int currentPlayingPosition;
+ private boolean renameCurrent = false;
}
}
diff --git a/src/github/daneren2005/dsub/service/JukeboxController.java b/src/github/daneren2005/dsub/service/JukeboxController.java
index fcd58e01..faace3ae 100644
--- a/src/github/daneren2005/dsub/service/JukeboxController.java
+++ b/src/github/daneren2005/dsub/service/JukeboxController.java
@@ -104,7 +104,7 @@ public class JukeboxController extends RemoteController {
if (jukeboxStatus != null) {
jukeboxStatus.setPositionSeconds(seconds);
}
- tasks.add(new Skip(-1, seconds));
+ tasks.add(new Skip(downloadService.getCurrentPlayingIndex(), seconds));
downloadService.setPlayerState(PlayerState.STARTED);
}
@Override
diff --git a/src/github/daneren2005/dsub/service/MusicService.java b/src/github/daneren2005/dsub/service/MusicService.java
index cae307cb..8d204530 100644
--- a/src/github/daneren2005/dsub/service/MusicService.java
+++ b/src/github/daneren2005/dsub/service/MusicService.java
@@ -24,6 +24,8 @@ import org.apache.http.HttpResponse;
import android.content.Context;
import android.graphics.Bitmap;
+
+import github.daneren2005.dsub.domain.Bookmark;
import github.daneren2005.dsub.domain.ChatMessage;
import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
@@ -59,7 +61,7 @@ public interface MusicService {
MusicDirectory getStarredList(Context context, ProgressListener progressListener) throws Exception;
- MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception;
+ MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception;
List<Playlist> getPlaylists(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
@@ -123,7 +125,7 @@ public interface MusicService {
List<PodcastChannel> getPodcastChannels(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
- MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception;
+ MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception;
void refreshPodcasts(Context context, ProgressListener progressListener) throws Exception;
@@ -134,6 +136,14 @@ public interface MusicService {
void downloadPodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception;
void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception;
+
+ void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception;
+
+ List<Bookmark> getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception;
+
+ void createBookmark(String id, int position, String comment, Context context, ProgressListener progressListener) throws Exception;
+
+ void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception;
int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception;
} \ No newline at end of file
diff --git a/src/github/daneren2005/dsub/service/OfflineMusicService.java b/src/github/daneren2005/dsub/service/OfflineMusicService.java
index 1221df5c..ba798c09 100644
--- a/src/github/daneren2005/dsub/service/OfflineMusicService.java
+++ b/src/github/daneren2005/dsub/service/OfflineMusicService.java
@@ -32,9 +32,9 @@ import java.util.Set;
import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
-import android.media.MediaMetadataRetriever;
import android.util.Log;
import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.Bookmark;
import github.daneren2005.dsub.domain.Genre;
import github.daneren2005.dsub.domain.Indexes;
import github.daneren2005.dsub.domain.RemoteStatus;
@@ -147,7 +147,10 @@ public class OfflineMusicService extends RESTMusicService {
return FileUtil.getBaseName(name);
}
- private MusicDirectory.Entry createEntry(Context context, File file, String name) {
+ private MusicDirectory.Entry createEntry(Context context, File file, String name) {
+ return createEntry(context, file, name, true);
+ }
+ private MusicDirectory.Entry createEntry(Context context, File file, String name, boolean load) {
MusicDirectory.Entry entry = new MusicDirectory.Entry();
entry.setDirectory(file.isDirectory());
entry.setId(file.getPath());
@@ -179,33 +182,8 @@ public class OfflineMusicService extends RESTMusicService {
}
}
- try {
- MediaMetadataRetriever metadata = new MediaMetadataRetriever();
- metadata.setDataSource(file.getAbsolutePath());
- String discNumber = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER);
- if(discNumber == null) {
- discNumber = "1/1";
- }
- int slashIndex = discNumber.indexOf("/");
- if(slashIndex > 0) {
- discNumber = discNumber.substring(0, slashIndex);
- }
- entry.setDiscNumber(Integer.parseInt(discNumber));
- String bitrate = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE);
- entry.setBitRate(Integer.parseInt((bitrate != null) ? bitrate : "0") / 1000);
- String length = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
- entry.setDuration(Integer.parseInt(length) / 1000);
- String artist = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
- if(artist != null) {
- entry.setArtist(artist);
- }
- String album = metadata.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- if(album != null) {
- entry.setAlbum(album);
- }
- metadata.release();
- } catch(Exception e) {
- Log.i(TAG, "Device doesn't properly support MediaMetadataRetreiver");
+ if(load) {
+ entry.loadMetadata(file);
}
}
@@ -401,7 +379,7 @@ public class OfflineMusicService extends RESTMusicService {
}
@Override
- public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception {
+ public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception {
DownloadService downloadService = DownloadServiceImpl.getInstance();
if (downloadService == null) {
return new MusicDirectory();
@@ -427,7 +405,7 @@ public class OfflineMusicService extends RESTMusicService {
File entryFile = new File(line);
String entryName = getName(entryFile);
if(entryFile.exists() && entryName != null){
- playlist.addChild(createEntry(context, entryFile, entryName));
+ playlist.addChild(createEntry(context, entryFile, entryName, false));
}
}
@@ -629,7 +607,7 @@ public class OfflineMusicService extends RESTMusicService {
}
@Override
- public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception {
+ public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception {
return getMusicDirectory(FileUtil.getPodcastDirectory(context, id).getPath(), null, false, context, progressListener);
}
@@ -657,6 +635,26 @@ public class OfflineMusicService extends RESTMusicService {
public void deletePodcastEpisode(String id, Context context, ProgressListener progressListener) throws Exception{
throw new OfflineException("Getting Podcasts not available in offline mode");
}
+
+ @Override
+ public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception {
+ throw new OfflineException("Setting ratings not available in offline mode");
+ }
+
+ @Override
+ public List<Bookmark> getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
+ throw new OfflineException("Getting bookmarks not available in offline mode");
+ }
+
+ @Override
+ public void createBookmark(String id, int position, String comment, Context context, ProgressListener progressListener) throws Exception {
+ throw new OfflineException("Creating bookmarks not available in offline mode");
+ }
+
+ @Override
+ public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception {
+ throw new OfflineException("Deleting bookmarks not available in offline mode");
+ }
@Override
public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{
diff --git a/src/github/daneren2005/dsub/service/RESTMusicService.java b/src/github/daneren2005/dsub/service/RESTMusicService.java
index 82148dc0..22abacb1 100644
--- a/src/github/daneren2005/dsub/service/RESTMusicService.java
+++ b/src/github/daneren2005/dsub/service/RESTMusicService.java
@@ -70,6 +70,7 @@ import android.util.Log;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.*;
import github.daneren2005.dsub.service.parser.AlbumListParser;
+import github.daneren2005.dsub.service.parser.BookmarkParser;
import github.daneren2005.dsub.service.parser.ChatMessageParser;
import github.daneren2005.dsub.service.parser.ErrorParser;
import github.daneren2005.dsub.service.parser.GenreParser;
@@ -186,17 +187,9 @@ public class RESTMusicService implements MusicService {
}
public List<MusicFolder> getMusicFolders(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
-
- List<MusicFolder> cachedMusicFolders = readCachedMusicFolders(context);
- if (cachedMusicFolders != null && !refresh) {
- return cachedMusicFolders;
- }
-
Reader reader = getReader(context, progressListener, "getMusicFolders", null);
try {
- List<MusicFolder> musicFolders = new MusicFoldersParser(context).parse(reader, progressListener);
- writeCachedMusicFolders(context, musicFolders);
- return musicFolders;
+ return new MusicFoldersParser(context).parse(reader, progressListener);
} finally {
Util.close(reader);
}
@@ -243,7 +236,7 @@ public class RESTMusicService implements MusicService {
private Indexes readCachedIndexes(Context context, String musicFolderId) {
String filename = getCachedIndexesFilename(context, musicFolderId);
- return FileUtil.deserialize(context, filename);
+ return FileUtil.deserialize(context, filename, Indexes.class);
}
private void writeCachedIndexes(Context context, Indexes indexes, String musicFolderId) {
@@ -256,21 +249,6 @@ public class RESTMusicService implements MusicService {
return "indexes-" + Math.abs(s.hashCode()) + ".ser";
}
- private ArrayList<MusicFolder> readCachedMusicFolders(Context context) {
- String filename = getCachedMusicFoldersFilename(context);
- return FileUtil.deserialize(context, filename);
- }
-
- private void writeCachedMusicFolders(Context context, List<MusicFolder> musicFolders) {
- String filename = getCachedMusicFoldersFilename(context);
- FileUtil.serialize(context, new ArrayList<MusicFolder>(musicFolders), filename);
- }
-
- private String getCachedMusicFoldersFilename(Context context) {
- String s = Util.getRestUrl(context, null);
- return "musicFolders-" + Math.abs(s.hashCode()) + ".ser";
- }
-
@Override
public MusicDirectory getMusicDirectory(String id, String name, boolean refresh, Context context, ProgressListener progressListener) throws Exception {
SharedPreferences prefs = Util.getPreferences(context);
@@ -336,7 +314,7 @@ public class RESTMusicService implements MusicService {
}
@Override
- public MusicDirectory getPlaylist(String id, String name, Context context, ProgressListener progressListener) throws Exception {
+ public MusicDirectory getPlaylist(boolean refresh, String id, String name, Context context, ProgressListener progressListener) throws Exception {
HttpParams params = new BasicHttpParams();
HttpConnectionParams.setSoTimeout(params, SOCKET_READ_TIMEOUT_GET_PLAYLIST);
@@ -755,10 +733,6 @@ public class RESTMusicService implements MusicService {
public RemoteStatus skipJukebox(int index, int offsetSeconds, Context context, ProgressListener progressListener) throws Exception {
List<String> parameterNames = Arrays.asList("action", "index", "offset");
List<Object> parameterValues = Arrays.<Object>asList("skip", index, offsetSeconds);
- if(index < 0) {
- parameterNames.remove(1);
- parameterValues.remove(1);
- }
return executeJukeboxCommand(context, progressListener, parameterNames, parameterValues);
}
@@ -927,7 +901,7 @@ public class RESTMusicService implements MusicService {
}
@Override
- public MusicDirectory getPodcastEpisodes(String id, Context context, ProgressListener progressListener) throws Exception {
+ public MusicDirectory getPodcastEpisodes(boolean refresh, String id, Context context, ProgressListener progressListener) throws Exception {
Reader reader = getReader(context, progressListener, "getPodcasts", null, Arrays.asList("id"), Arrays.<Object>asList(id));
try {
return new PodcastEntryParser(context).parse(id, reader, progressListener);
@@ -995,7 +969,55 @@ public class RESTMusicService implements MusicService {
Util.close(reader);
}
}
-
+
+ @Override
+ public void setRating(String id, int rating, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.6", "Setting ratings not supported.");
+
+ Reader reader = getReader(context, progressListener, "setRating", null, Arrays.asList("id", "rating"), Arrays.<Object>asList(id, rating));
+ try {
+ new ErrorParser(context).parse(reader);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
+ @Override
+ public List<Bookmark> getBookmarks(boolean refresh, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.9", "Bookmarks not supported.");
+
+ Reader reader = getReader(context, progressListener, "getBookmarks", null);
+ try {
+ return new BookmarkParser(context).parse(reader, progressListener);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
+ @Override
+ public void createBookmark(String id, int position, String comment, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.9", "Creating bookmarks not supported.");
+
+ Reader reader = getReader(context, progressListener, "createBookmark", null, Arrays.asList("id", "position", "comment"), Arrays.<Object>asList(id, position, comment));
+ try {
+ new ErrorParser(context).parse(reader);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
+ @Override
+ public void deleteBookmark(String id, Context context, ProgressListener progressListener) throws Exception {
+ checkServerVersion(context, "1.9", "Deleting bookmarks not supported.");
+
+ Reader reader = getReader(context, progressListener, "deleteBookmark", null, Arrays.asList("id"), Arrays.<Object>asList(id));
+ try {
+ new ErrorParser(context).parse(reader);
+ } finally {
+ Util.close(reader);
+ }
+ }
+
@Override
public int processOfflineSyncs(final Context context, final ProgressListener progressListener) throws Exception{
return processOfflineScrobbles(context, progressListener) + processOfflineStars(context, progressListener);
diff --git a/src/github/daneren2005/dsub/service/StreamProxy.java b/src/github/daneren2005/dsub/service/StreamProxy.java
index 24c1b201..900a0c92 100644
--- a/src/github/daneren2005/dsub/service/StreamProxy.java
+++ b/src/github/daneren2005/dsub/service/StreamProxy.java
@@ -18,6 +18,7 @@ import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
+import org.apache.http.Header;
import org.apache.http.HttpRequest;
import org.apache.http.message.BasicHttpRequest;
@@ -90,10 +91,10 @@ public class StreamProxy implements Runnable {
}
private class StreamToMediaPlayerTask implements Runnable {
-
- String localPath;
+ DownloadFile downloadFile;
+ File file;
Socket client;
- int cbSkip;
+ int cbSkip = 0;
public StreamToMediaPlayerTask(Socket client) {
this.client = client;
@@ -103,9 +104,10 @@ public class StreamProxy implements Runnable {
HttpRequest request = null;
InputStream is;
String firstLine;
+ BufferedReader reader = null;
try {
is = client.getInputStream();
- BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8192);
+ reader = new BufferedReader(new InputStreamReader(is), 8192);
firstLine = reader.readLine();
} catch (IOException e) {
Log.e(TAG, "Error parsing request", e);
@@ -123,6 +125,19 @@ public class StreamProxy implements Runnable {
String realUri = uri.substring(1);
Log.i(TAG, realUri);
request = new BasicHttpRequest(method, realUri);
+
+ // Get all of the headers
+ try {
+ String line;
+ while((line = reader.readLine()) != null && !"".equals(line)) {
+ String headerName = line.substring(0, line.indexOf(':'));
+ String headerValue = line.substring(line.indexOf(": ") + 2);
+ request.addHeader(headerName, headerValue);
+ }
+ } catch(IOException e) {
+ // Don't really care once past first line
+ }
+
return request;
}
@@ -135,6 +150,7 @@ public class StreamProxy implements Runnable {
// Read HTTP headers
Log.i(TAG, "Processing request");
+ String localPath;
try {
localPath = URLDecoder.decode(request.getRequestLine().getUri(), Constants.UTF_8);
} catch (UnsupportedEncodingException e) {
@@ -143,11 +159,38 @@ public class StreamProxy implements Runnable {
}
Log.i(TAG, "Processing request for file " + localPath);
- File file = new File(localPath);
- if (!file.exists()) {
+ downloadFile = downloadService.getCurrentPlaying();
+ File partialFile = new File(localPath);
+ if (!partialFile.equals(downloadFile.getPartialFile())) {
Log.e(TAG, "File " + localPath + " does not exist");
return false;
}
+
+ // Use either partial or complete if downloading finished while StreamProxy was idle
+ file = downloadFile.isCompleteFileAvailable() ? downloadFile.getCompleteFile() : downloadFile.getPartialFile();
+
+ // Try to get range requested
+ Header rangeHeader = request.getFirstHeader("Range");
+
+ if(rangeHeader != null) {
+ String range = rangeHeader.getValue();
+ int index = range.indexOf("=");
+ if(index >= 0) {
+ range = range.substring(index + 1);
+
+ index = range.indexOf("-");
+ if(index > 0) {
+ range = range.substring(0, index);
+ }
+
+ cbSkip = Integer.parseInt(range);
+
+ // Make sure to not try to read past where the file is downloaded
+ if(cbSkip >= file.length()) {
+ return false;
+ }
+ }
+ }
return true;
}
@@ -155,14 +198,30 @@ public class StreamProxy implements Runnable {
@Override
public void run() {
Log.i(TAG, "Streaming song in background");
- DownloadFile downloadFile = downloadService.getCurrentPlaying();
MusicDirectory.Entry song = downloadFile.getSong();
+
+ Integer contentLength = downloadFile.getContentLength();
+ if(contentLength == null && downloadFile.isWorkDone()) {
+ contentLength = (int)file.length();
+ }
// Create HTTP header
- String headers = "HTTP/1.0 200 OK\r\n";
+ String headers;
+ if(cbSkip == 0) {
+ headers = "HTTP/1.0 200 OK\r\n";
+ } else {
+ headers = "HTTP/1.0 206 OK\r\n;";
+ headers += "Content-Range: bytes " + cbSkip + "-" + (file.length() - 1) + "/";
+ if(contentLength == null) {
+ headers += "*";
+ } else {
+ headers += contentLength;
+ }
+
+ Log.i(TAG, "Streaming starts from: " + cbSkip);
+ }
headers += "Content-Type: " + "application/octet-stream" + "\r\n";
- Integer contentLength = downloadFile.getContentLength();
long fileSize;
if(contentLength == null) {
fileSize = downloadFile.getBitRate() * ((song.getDuration() != null) ? song.getDuration() : 0) * 1000 / 8;
@@ -182,50 +241,54 @@ public class StreamProxy implements Runnable {
output = new BufferedOutputStream(client.getOutputStream(), 32*1024);
output.write(headers.getBytes());
- if(!downloadFile.isWorkDone()) {
- // Loop as long as there's stuff to send
- while (isRunning && !client.isClosed()) {
-
- // See if there's more to send
- File file = new File(localPath);
- int cbSentThisBatch = 0;
- if (file.exists()) {
- FileInputStream input = new FileInputStream(file);
- input.skip(cbSkip);
- int cbToSendThisBatch = input.available();
- while (cbToSendThisBatch > 0) {
- int cbToRead = Math.min(cbToSendThisBatch, buff.length);
- int cbRead = input.read(buff, 0, cbToRead);
- if (cbRead == -1) {
- break;
- }
- cbToSendThisBatch -= cbRead;
- cbToSend -= cbRead;
- output.write(buff, 0, cbRead);
- output.flush();
- cbSkip += cbRead;
- cbSentThisBatch += cbRead;
+ // Make sure to have file lock
+ downloadFile.setPlaying(true);
+
+ // Loop as long as there's stuff to send
+ while (isRunning && !client.isClosed()) {
+
+ // See if there's more to send
+ int cbSentThisBatch = 0;
+ if (file.exists()) {
+ FileInputStream input = new FileInputStream(file);
+ input.skip(cbSkip);
+ int cbToSendThisBatch = input.available();
+ while (cbToSendThisBatch > 0) {
+ int cbToRead = Math.min(cbToSendThisBatch, buff.length);
+ int cbRead = input.read(buff, 0, cbToRead);
+ if (cbRead == -1) {
+ break;
}
- input.close();
+ cbToSendThisBatch -= cbRead;
+ cbToSend -= cbRead;
+ output.write(buff, 0, cbRead);
+ output.flush();
+ cbSkip += cbRead;
+ cbSentThisBatch += cbRead;
}
+ input.close();
+ }
- // Done regardless of whether or not it thinks it is
- if(downloadFile.isWorkDone() && cbSkip >= file.length()) {
- break;
- }
+ // Done regardless of whether or not it thinks it is
+ if(downloadFile.isWorkDone() && cbSkip >= file.length()) {
+ break;
+ }
- // If we did nothing this batch, block for a second
- if (cbSentThisBatch == 0) {
- Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")");
- Thread.sleep(1000);
- }
+ // If we did nothing this batch, block for a second
+ if (cbSentThisBatch == 0) {
+ Log.d(TAG, "Blocking until more data appears (" + cbToSend + ")");
+ Thread.sleep(1000);
}
- } else {
- Log.w(TAG, "Requesting data for completely downloaded file");
}
+
+ // Release file lock, use of stream proxy means nothing else is using it
+ downloadFile.setPlaying(false);
}
catch (SocketException socketException) {
Log.e(TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
+
+ // Release file lock, use of stream proxy means nothing else is using it
+ downloadFile.setPlaying(false);
}
catch (Exception e) {
Log.e(TAG, "Exception thrown from streaming task:");
diff --git a/src/github/daneren2005/dsub/service/parser/BookmarkParser.java b/src/github/daneren2005/dsub/service/parser/BookmarkParser.java
new file mode 100644
index 00000000..8af509f0
--- /dev/null
+++ b/src/github/daneren2005/dsub/service/parser/BookmarkParser.java
@@ -0,0 +1,73 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2013 (C) Scott Jackson
+*/
+package github.daneren2005.dsub.service.parser;
+
+import android.content.Context;
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Bookmark;
+import github.daneren2005.dsub.util.ProgressListener;
+import org.xmlpull.v1.XmlPullParser;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Scott Jackson
+ */
+public class BookmarkParser extends MusicDirectoryEntryParser {
+ public BookmarkParser(Context context) {
+ super(context);
+ }
+
+ public List<Bookmark> parse(Reader reader, ProgressListener progressListener) throws Exception {
+ updateProgress(progressListener, R.string.parser_reading);
+ init(reader);
+
+ List<Bookmark> bookmarks = new ArrayList<Bookmark>();
+ Bookmark bookmark = null;
+ int eventType;
+
+ do {
+ eventType = nextParseEvent();
+
+ if (eventType == XmlPullParser.START_TAG) {
+ String name = getElementName();
+
+ if ("bookmark".equals(name)) {
+ bookmark = new Bookmark();
+ bookmark.setChanged(get("changed"));
+ bookmark.setCreated(get("created"));
+ bookmark.setComment(get("comment"));
+ bookmark.setPosition(getInteger("position"));
+ bookmark.setUsername(get("username"));
+ } else if ("entry".equals(name)) {
+ bookmark.setEntry(parseEntry(null));
+ bookmarks.add(bookmark);
+ } else if ("error".equals(name)) {
+ handleError();
+ }
+ }
+ } while (eventType != XmlPullParser.END_DOCUMENT);
+
+ validate();
+ updateProgress(progressListener, R.string.parser_reading_done);
+
+ return bookmarks;
+ }
+}
diff --git a/src/github/daneren2005/dsub/service/parser/IndexesParser.java b/src/github/daneren2005/dsub/service/parser/IndexesParser.java
index 6196411d..bf5bd8b1 100644
--- a/src/github/daneren2005/dsub/service/parser/IndexesParser.java
+++ b/src/github/daneren2005/dsub/service/parser/IndexesParser.java
@@ -29,6 +29,7 @@ import android.content.SharedPreferences;
import github.daneren2005.dsub.R;
import github.daneren2005.dsub.domain.Artist;
import github.daneren2005.dsub.domain.Indexes;
+import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.util.ProgressListener;
import android.util.Log;
import github.daneren2005.dsub.util.Constants;
@@ -37,7 +38,7 @@ import github.daneren2005.dsub.util.Util;
/**
* @author Sindre Mehus
*/
-public class IndexesParser extends AbstractParser {
+public class IndexesParser extends MusicDirectoryEntryParser {
private static final String TAG = IndexesParser.class.getSimpleName();
private Context context;
@@ -55,6 +56,7 @@ public class IndexesParser extends AbstractParser {
List<Artist> artists = new ArrayList<Artist>();
List<Artist> shortcuts = new ArrayList<Artist>();
+ List<MusicDirectory.Entry> entries = new ArrayList<MusicDirectory.Entry>();
Long lastModified = null;
int eventType;
String index = "#";
@@ -91,7 +93,10 @@ public class IndexesParser extends AbstractParser {
shortcut.setIndex("*");
shortcut.setStarred(get("starred") != null);
shortcuts.add(shortcut);
- } else if ("error".equals(name)) {
+ } else if("child".equals(name)) {
+ MusicDirectory.Entry entry = parseEntry("");
+ entries.add(entry);
+ } else if ("error".equals(name)) {
handleError();
}
}
@@ -115,6 +120,6 @@ public class IndexesParser extends AbstractParser {
String msg = getContext().getResources().getString(R.string.parser_artist_count, artists.size());
updateProgress(progressListener, msg);
- return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists);
+ return new Indexes(lastModified == null ? 0L : lastModified, shortcuts, artists, entries);
}
} \ No newline at end of file
diff --git a/src/github/daneren2005/dsub/util/Constants.java b/src/github/daneren2005/dsub/util/Constants.java
index fccd03cd..9940c3be 100644
--- a/src/github/daneren2005/dsub/util/Constants.java
+++ b/src/github/daneren2005/dsub/util/Constants.java
@@ -54,14 +54,18 @@ public final class Constants {
public static final String INTENT_EXTRA_REQUEST_SEARCH = "subsonic.requestsearch";
public static final String INTENT_EXTRA_NAME_EXIT = "subsonic.exit" ;
public static final String INTENT_EXTRA_NAME_DOWNLOAD = "subsonic.download";
+ public static final String INTENT_EXTRA_NAME_DOWNLOAD_VIEW = "subsonic.download_view";
public static final String INTENT_EXTRA_VIEW_ALBUM = "subsonic.view_album";
public static final String INTENT_EXTRA_NAME_PODCAST_ID = "subsonic.podcast.id";
public static final String INTENT_EXTRA_NAME_PODCAST_NAME = "subsonic.podcast.name";
public static final String INTENT_EXTRA_NAME_PODCAST_DESCRIPTION = "subsonic.podcast.description";
+ public static final String INTENT_EXTRA_FRAGMENT_TYPE = "fragmentType";
+ public static final String INTENT_EXTRA_REFRESH_LISTINGS = "refreshListings";
// Notification IDs.
public static final int NOTIFICATION_ID_PLAYING = 100;
public static final int NOTIFICATION_ID_ERROR = 101;
+ public static final int NOTIFICATION_ID_DOWNLOADING = 102;
// Preferences keys.
public static final String PREFERENCES_KEY_SERVER_KEY = "server";
@@ -117,6 +121,10 @@ public final class Constants {
public static final String PREFERENCES_KEY_SYNC_ENABLED = "syncEnabled";
public static final String PREFERENCES_KEY_SYNC_INTERVAL = "syncInterval";
public static final String PREFERENCES_KEY_SYNC_WIFI = "syncWifi";
+ public static final String PREFERENCES_KEY_PAUSE_DISCONNECT = "pauseOnDisconnect";
+ public static final String PREFERENCES_KEY_HIDE_WIDGET = "hideWidget";
+ public static final String PREFERENCES_KEY_PODCASTS_ENABLED = "podcastsEnabled";
+ public static final String PREFERENCES_KEY_BOOKMARKS_ENABLED = "bookmarksEnabled";
public static final String OFFLINE_SCROBBLE_COUNT = "scrobbleCount";
public static final String OFFLINE_SCROBBLE_ID = "scrobbleID";
@@ -137,6 +145,8 @@ public final class Constants {
public static final String FRAGMENT_LIST = "fragmentList";
public static final String FRAGMENT_LIST2 = "fragmentList2";
public static final String FRAGMENT_DOWNLOAD_FLIPPER = "fragmentDownloadFlipper";
+ public static final String FRAGMENT_NAME = "fragmentName";
+ public static final String FRAGMENT_POSITION = "fragmentPosition";
// Name of the preferences file.
public static final String PREFERENCES_FILE_NAME = "github.daneren2005.dsub_preferences";
diff --git a/src/github/daneren2005/dsub/util/FileUtil.java b/src/github/daneren2005/dsub/util/FileUtil.java
index 34bc82bd..d18bddb8 100644
--- a/src/github/daneren2005/dsub/util/FileUtil.java
+++ b/src/github/daneren2005/dsub/util/FileUtil.java
@@ -20,9 +20,9 @@ package github.daneren2005.dsub.util;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
+import java.io.RandomAccessFile;
import java.io.Serializable;
import java.util.Arrays;
import java.util.SortedSet;
@@ -36,10 +36,19 @@ import android.graphics.BitmapFactory;
import android.os.Environment;
import android.util.Log;
import github.daneren2005.dsub.domain.Artist;
+import github.daneren2005.dsub.domain.Genre;
+import github.daneren2005.dsub.domain.Indexes;
+import github.daneren2005.dsub.domain.Playlist;
+import github.daneren2005.dsub.domain.PodcastChannel;
import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.domain.MusicFolder;
import github.daneren2005.dsub.domain.PodcastChannel;
import github.daneren2005.dsub.domain.PodcastEpisode;
+import com.esotericsoftware.kryo.Kryo;
+import com.esotericsoftware.kryo.io.Input;
+import com.esotericsoftware.kryo.io.Output;
+
/**
* @author Sindre Mehus
*/
@@ -52,6 +61,17 @@ public class FileUtil {
private static final List<String> VIDEO_FILE_EXTENSIONS = Arrays.asList("flv", "mp4", "m4v", "wmv", "avi", "mov", "mpg", "mkv");
private static final List<String> PLAYLIST_FILE_EXTENSIONS = Arrays.asList("m3u");
private static final File DEFAULT_MUSIC_DIR = createDirectory("music");
+ private static final Kryo kryo = new Kryo();
+
+ static {
+ kryo.register(MusicDirectory.Entry.class);
+ kryo.register(Indexes.class);
+ kryo.register(Artist.class);
+ kryo.register(MusicFolder.class);
+ kryo.register(PodcastChannel.class);
+ kryo.register(Playlist.class);
+ kryo.register(Genre.class);
+ }
public static File getAnySong(Context context) {
File dir = getMusicDirectory(context);
@@ -359,35 +379,36 @@ public class FileUtil {
}
public static <T extends Serializable> boolean serialize(Context context, T obj, String fileName) {
- File file = new File(context.getCacheDir(), fileName);
- ObjectOutputStream out = null;
+ Output out = null;
try {
- out = new ObjectOutputStream(new FileOutputStream(file));
- out.writeObject(obj);
- Log.i(TAG, "Serialized object to " + file);
+ RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "rw");
+ out = new Output(new FileOutputStream(file.getFD()));
+ kryo.writeObject(out, obj);
+ Log.i(TAG, "Serialized object to " + fileName);
return true;
} catch (Throwable x) {
- Log.w(TAG, "Failed to serialize object to " + file);
+ Log.w(TAG, "Failed to serialize object to " + fileName);
return false;
} finally {
Util.close(out);
}
}
- public static <T extends Serializable> T deserialize(Context context, String fileName) {
- File file = new File(context.getCacheDir(), fileName);
- if (!file.exists() || !file.isFile()) {
- return null;
- }
-
- ObjectInputStream in = null;
+ public static <T extends Serializable> T deserialize(Context context, String fileName, Class<T> tClass) {
+ Input in = null;
try {
- in = new ObjectInputStream(new FileInputStream(file));
- T result = (T) in.readObject();
- Log.i(TAG, "Deserialized object from " + file);
+ RandomAccessFile file = new RandomAccessFile(context.getCacheDir() + "/" + fileName, "r");
+
+ in = new Input(new FileInputStream(file.getFD()));
+ T result = (T) kryo.readObject(in, tClass);
+ Log.i(TAG, "Deserialized object from " + fileName);
return result;
- } catch (Throwable x) {
- Log.w(TAG, "Failed to deserialize object from " + file, x);
+ } catch(FileNotFoundException e) {
+ // Different error message
+ Log.w(TAG, "No serialization for object from " + fileName);
+ return null;
+ } catch (Throwable x) {
+ Log.w(TAG, "Failed to deserialize object from " + fileName, x);
return null;
} finally {
Util.close(in);
diff --git a/src/github/daneren2005/dsub/util/Util.java b/src/github/daneren2005/dsub/util/Util.java
index ae575e89..ce6ba914 100644
--- a/src/github/daneren2005/dsub/util/Util.java
+++ b/src/github/daneren2005/dsub/util/Util.java
@@ -22,6 +22,7 @@ import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
+import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -40,6 +41,7 @@ import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
+import android.support.v4.app.NotificationCompat;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
@@ -52,13 +54,14 @@ import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;
import github.daneren2005.dsub.R;
-import github.daneren2005.dsub.activity.MainActivity;
+import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.domain.MusicDirectory;
import github.daneren2005.dsub.domain.PlayerState;
import github.daneren2005.dsub.domain.RepeatMode;
import github.daneren2005.dsub.domain.Version;
import github.daneren2005.dsub.provider.DSubWidgetProvider;
import github.daneren2005.dsub.receiver.MediaButtonIntentReceiver;
+import github.daneren2005.dsub.service.DownloadFile;
import github.daneren2005.dsub.service.DownloadService;
import github.daneren2005.dsub.service.DownloadServiceImpl;
import org.apache.http.HttpEntity;
@@ -161,7 +164,7 @@ public final class Util {
public static int getActiveServer(Context context) {
SharedPreferences prefs = getPreferences(context);
- return prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
+ return prefs.getBoolean(Constants.PREFERENCES_KEY_OFFLINE, false) ? 0 : prefs.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, 1);
}
public static boolean checkServerVersion(Context context, String requiredVersion) {
@@ -758,8 +761,8 @@ public final class Util {
}
}
- public static boolean isNullOrWhiteSpace(String string) {
- return string == null || string.isEmpty() || string.trim().isEmpty();
+ public static boolean isNullOrWhiteSpace(String string) {
+ return string == null || "".equals(string) || "".equals(string.trim());
}
public static boolean isNetworkConnected(Context context) {
@@ -783,24 +786,44 @@ public final class Util {
}
public static void info(Context context, int titleId, int messageId) {
- showDialog(context, android.R.drawable.ic_dialog_info, titleId, messageId);
+ info(context, titleId, messageId, true);
}
public static void info(Context context, int titleId, String message) {
- showDialog(context, android.R.drawable.ic_dialog_info, titleId, message);
+ info(context, titleId, message, true);
}
public static void info(Context context, String title, String message) {
- showDialog(context, android.R.drawable.ic_dialog_info, title, message);
+ info(context, title, message, true);
+ }
+ public static void info(Context context, int titleId, int messageId, boolean linkify) {
+ showDialog(context, android.R.drawable.ic_dialog_info, titleId, messageId, linkify);
+ }
+ public static void info(Context context, int titleId, String message, boolean linkify) {
+ showDialog(context, android.R.drawable.ic_dialog_info, titleId, message, linkify);
+ }
+ public static void info(Context context, String title, String message, boolean linkify) {
+ showDialog(context, android.R.drawable.ic_dialog_info, title, message, linkify);
}
private static void showDialog(Context context, int icon, int titleId, int messageId) {
- showDialog(context, icon, context.getResources().getString(titleId), context.getResources().getString(messageId));
+ showDialog(context, icon, titleId, messageId, true);
}
private static void showDialog(Context context, int icon, int titleId, String message) {
- showDialog(context, icon, context.getResources().getString(titleId), message);
+ showDialog(context, icon, titleId, message, true);
}
private static void showDialog(Context context, int icon, String title, String message) {
+ showDialog(context, icon, title, message, true);
+ }
+ private static void showDialog(Context context, int icon, int titleId, int messageId, boolean linkify) {
+ showDialog(context, icon, context.getResources().getString(titleId), context.getResources().getString(messageId), linkify);
+ }
+ private static void showDialog(Context context, int icon, int titleId, String message, boolean linkify) {
+ showDialog(context, icon, context.getResources().getString(titleId), message, linkify);
+ }
+ private static void showDialog(Context context, int icon, String title, String message, boolean linkify) {
SpannableString ss = new SpannableString(message);
- Linkify.addLinks(ss, Linkify.ALL);
+ if(linkify) {
+ Linkify.addLinks(ss, Linkify.ALL);
+ }
AlertDialog dialog = new AlertDialog.Builder(context)
.setIcon(icon)
@@ -833,10 +856,10 @@ public final class Util {
setupViews(smallContentView, context, song, playing);
notification.contentView = smallContentView;
- Intent notificationIntent = new Intent(context, MainActivity.class);
+ Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class);
notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
- notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
+ notification.contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
handler.post(new Runnable() {
@Override
@@ -846,7 +869,7 @@ public final class Util {
});
// Update widget
- DSubWidgetProvider.notifyInstances(context, downloadService, true);
+ DSubWidgetProvider.notifyInstances(context, downloadService, playing);
}
private static void setupViews(RemoteViews rv, Context context, MusicDirectory.Entry song, boolean playing){
@@ -883,39 +906,62 @@ public final class Util {
if (colors.getSecond() != null) {
rv.setTextColor(R.id.notification_artist, colors.getSecond());
}
-
- if(!playing) {
- rv.setImageViewResource(R.id.control_pause, R.drawable.notification_play);
- rv.setImageViewResource(R.id.control_previous, R.drawable.notification_stop);
+
+ if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) {
+ rv.setImageViewResource(R.id.control_previous, playing ? R.drawable.notification_pause : R.drawable.notification_play);
+ rv.setImageViewResource(R.id.control_pause, R.drawable.notification_next);
+ rv.setImageViewResource(R.id.control_next, R.drawable.notification_close);
}
// Create actions for media buttons
PendingIntent pendingIntent;
- if(playing) {
+ int previous = 0, pause = 0, next = 0, close = 0;
+ if(Util.getPreferences(context).getBoolean(Constants.PREFERENCES_KEY_PERSISTENT_NOTIFICATION, false)) {
+ pause = R.id.control_previous;
+ next = R.id.control_pause;
+ close = R.id.control_next;
+ } else {
+ previous = R.id.control_previous;
+ pause = R.id.control_pause;
+ next = R.id.control_next;
+ }
+
+ if(previous > 0) {
Intent prevIntent = new Intent("KEYCODE_MEDIA_PREVIOUS");
prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PREVIOUS));
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
- rv.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
- } else {
+ rv.setOnClickPendingIntent(previous, pendingIntent);
+ }
+ if(pause > 0) {
+ if(playing) {
+ Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE");
+ pauseIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
+ pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
+ pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0);
+ rv.setOnClickPendingIntent(pause, pendingIntent);
+ } else {
+ Intent prevIntent = new Intent("KEYCODE_MEDIA_START");
+ prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
+ prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY));
+ pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
+ rv.setOnClickPendingIntent(pause, pendingIntent);
+ }
+ }
+ if(next > 0) {
+ Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT");
+ nextIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
+ nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
+ pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0);
+ rv.setOnClickPendingIntent(next, pendingIntent);
+ }
+ if(close > 0) {
Intent prevIntent = new Intent("KEYCODE_MEDIA_STOP");
prevIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
prevIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_STOP));
pendingIntent = PendingIntent.getService(context, 0, prevIntent, 0);
- rv.setOnClickPendingIntent(R.id.control_previous, pendingIntent);
+ rv.setOnClickPendingIntent(close, pendingIntent);
}
-
- Intent pauseIntent = new Intent("KEYCODE_MEDIA_PLAY_PAUSE");
- pauseIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
- pauseIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE));
- pendingIntent = PendingIntent.getService(context, 0, pauseIntent, 0);
- rv.setOnClickPendingIntent(R.id.control_pause, pendingIntent);
-
- Intent nextIntent = new Intent("KEYCODE_MEDIA_NEXT");
- nextIntent.setComponent(new ComponentName(context, DownloadServiceImpl.class));
- nextIntent.putExtra(Intent.EXTRA_KEY_EVENT, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MEDIA_NEXT));
- pendingIntent = PendingIntent.getService(context, 0, nextIntent, 0);
- rv.setOnClickPendingIntent(R.id.control_next, pendingIntent);
}
public static void hidePlayingNotification(final Context context, final DownloadServiceImpl downloadService, Handler handler) {
@@ -930,6 +976,30 @@ public final class Util {
// Update widget
DSubWidgetProvider.notifyInstances(context, downloadService, false);
}
+
+ public static void showDownloadingNotification(final Context context, DownloadFile file, int size) {
+ NotificationCompat.Builder builder;
+ builder = new NotificationCompat.Builder(context)
+ .setSmallIcon(R.drawable.stat_notify_download)
+ .setContentTitle("Downloading " + size + " songs")
+ .setContentText("Current: " + (file != null ? file.getSong().getTitle() : "none"))
+ .setProgress(10, 5, true)
+ .setOngoing(true);
+
+ Intent notificationIntent = new Intent(context, SubsonicFragmentActivity.class);
+ notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD, true);
+ notificationIntent.putExtra(Constants.INTENT_EXTRA_NAME_DOWNLOAD_VIEW, true);
+ notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+ builder.setContentIntent(PendingIntent.getActivity(context, 0, notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP));
+
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.notify(Constants.NOTIFICATION_ID_DOWNLOADING, builder.build());
+
+ }
+ public static void hideDownloadingNotification(final Context context) {
+ NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+ notificationManager.cancel(Constants.NOTIFICATION_ID_DOWNLOADING);
+ }
public static void sleepQuietly(long millis) {
try {
diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java
index ddaa9f43..9826851d 100644
--- a/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java
+++ b/src/github/daneren2005/dsub/util/compat/RemoteControlClientHelper.java
@@ -10,6 +10,8 @@ public abstract class RemoteControlClientHelper {
public static RemoteControlClientHelper createInstance() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
return new RemoteControlClientBase();
+ } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
+ return new RemoteControlClientJB();
} else {
return new RemoteControlClientICS();
}
diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java
index 8707ecb5..a47ecab5 100644
--- a/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java
+++ b/src/github/daneren2005/dsub/util/compat/RemoteControlClientICS.java
@@ -10,16 +10,14 @@ import android.content.Intent;
import android.media.AudioManager;
import android.media.MediaMetadataRetriever;
import android.media.RemoteControlClient;
-import android.os.Build;
import github.daneren2005.dsub.activity.SubsonicActivity;
import github.daneren2005.dsub.service.DownloadService;
@TargetApi(14)
public class RemoteControlClientICS extends RemoteControlClientHelper {
-
- private RemoteControlClient mRemoteControl;
- private ImageLoader imageLoader;
- private DownloadService downloadService;
+ protected RemoteControlClient mRemoteControl;
+ protected ImageLoader imageLoader;
+ protected DownloadService downloadService;
public void register(final Context context, final ComponentName mediaButtonReceiverComponent) {
downloadService = (DownloadService) context;
@@ -37,21 +35,6 @@ public class RemoteControlClientICS extends RemoteControlClientHelper {
mRemoteControl.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED);
mRemoteControl.setTransportControlFlags(getTransportFlags());
imageLoader = SubsonicActivity.getStaticImageLoader(context);
-
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- mRemoteControl.setOnGetPlaybackPositionListener(new RemoteControlClient.OnGetPlaybackPositionListener() {
- @Override
- public long onGetPlaybackPosition() {
- return downloadService.getPlayerPosition();
- }
- });
- mRemoteControl.setPlaybackPositionUpdateListener(new RemoteControlClient.OnPlaybackPositionUpdateListener() {
- @Override
- public void onPlaybackPositionUpdate(long newPosition) {
- downloadService.seekTo((int) newPosition);
- }
- });
- }
}
public void unregister(final Context context) {
@@ -62,15 +45,7 @@ public class RemoteControlClientICS extends RemoteControlClientHelper {
}
public void setPlaybackState(final int state) {
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- long position = -1;
- if(state == RemoteControlClient.PLAYSTATE_PLAYING || state == RemoteControlClient.PLAYSTATE_PAUSED) {
- position = downloadService.getPlayerPosition();
- }
- mRemoteControl.setPlaybackState(state, position, 1.0f);
- } else {
- mRemoteControl.setPlaybackState(state);
- }
+ mRemoteControl.setPlaybackState(state);
}
public void updateMetadata(final Context context, final MusicDirectory.Entry currentSong) {
@@ -99,19 +74,13 @@ public class RemoteControlClientICS extends RemoteControlClientHelper {
}
}
- private int getTransportFlags() {
- int flags = RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
+ protected int getTransportFlags() {
+ return RemoteControlClient.FLAG_KEY_MEDIA_PLAY |
RemoteControlClient.FLAG_KEY_MEDIA_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_PLAY_PAUSE |
RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS |
RemoteControlClient.FLAG_KEY_MEDIA_NEXT |
RemoteControlClient.FLAG_KEY_MEDIA_STOP;
-
- if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
- flags = flags | RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
- }
-
- return flags;
}
}
diff --git a/src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java b/src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java
new file mode 100644
index 00000000..c499f6c0
--- /dev/null
+++ b/src/github/daneren2005/dsub/util/compat/RemoteControlClientJB.java
@@ -0,0 +1,50 @@
+package github.daneren2005.dsub.util.compat;
+
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.util.ImageLoader;
+import android.annotation.TargetApi;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.media.AudioManager;
+import android.media.MediaMetadataRetriever;
+import android.media.RemoteControlClient;
+import github.daneren2005.dsub.activity.SubsonicActivity;
+import github.daneren2005.dsub.service.DownloadService;
+
+@TargetApi(18)
+public class RemoteControlClientJB extends RemoteControlClientICS {
+ @Override
+ public void register(final Context context, final ComponentName mediaButtonReceiverComponent) {
+ super.register(context, mediaButtonReceiverComponent);
+
+ mRemoteControl.setOnGetPlaybackPositionListener(new RemoteControlClient.OnGetPlaybackPositionListener() {
+ @Override
+ public long onGetPlaybackPosition() {
+ return downloadService.getPlayerPosition();
+ }
+ });
+ mRemoteControl.setPlaybackPositionUpdateListener(new RemoteControlClient.OnPlaybackPositionUpdateListener() {
+ @Override
+ public void onPlaybackPositionUpdate(long newPosition) {
+ downloadService.seekTo((int) newPosition);
+ }
+ });
+ }
+
+ @Override
+ public void setPlaybackState(final int state) {
+ long position = -1;
+ if(state == RemoteControlClient.PLAYSTATE_PLAYING || state == RemoteControlClient.PLAYSTATE_PAUSED) {
+ position = downloadService.getPlayerPosition();
+ }
+ mRemoteControl.setPlaybackState(state, position, 1.0f);
+ }
+
+ @Override
+ protected int getTransportFlags() {
+ return super.getTransportFlags() | RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE;
+ }
+
+}
diff --git a/src/github/daneren2005/dsub/view/ArtistAdapter.java b/src/github/daneren2005/dsub/view/ArtistAdapter.java
index ff66f396..1998eaed 100644
--- a/src/github/daneren2005/dsub/view/ArtistAdapter.java
+++ b/src/github/daneren2005/dsub/view/ArtistAdapter.java
@@ -42,7 +42,7 @@ public class ArtistAdapter extends ArrayAdapter<Artist> implements SectionIndexe
private final Integer[] positions;
public ArtistAdapter(Context activity, List<Artist> artists) {
- super(activity, R.layout.artist_list_item, artists);
+ super(activity, R.layout.basic_list_item, artists);
this.activity = activity;
Set<String> sectionSet = new LinkedHashSet<String>(30);
diff --git a/src/github/daneren2005/dsub/view/ArtistEntryView.java b/src/github/daneren2005/dsub/view/ArtistEntryView.java
index 1d3993a0..958b4b87 100644
--- a/src/github/daneren2005/dsub/view/ArtistEntryView.java
+++ b/src/github/daneren2005/dsub/view/ArtistEntryView.java
@@ -48,12 +48,12 @@ public class ArtistEntryView extends UpdateView {
public ArtistEntryView(Context context) {
super(context);
this.context = context;
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
+ LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true);
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
+ titleView = (TextView) findViewById(R.id.item_name);
+ starButton = (ImageButton) findViewById(R.id.item_star);
starButton.setFocusable(false);
- moreButton = (ImageView) findViewById(R.id.artist_more);
+ moreButton = (ImageView) findViewById(R.id.item_more);
moreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.showContextMenu();
diff --git a/src/github/daneren2005/dsub/view/ArtistView.java b/src/github/daneren2005/dsub/view/ArtistView.java
index 2a284905..6f54e800 100644
--- a/src/github/daneren2005/dsub/view/ArtistView.java
+++ b/src/github/daneren2005/dsub/view/ArtistView.java
@@ -47,12 +47,12 @@ public class ArtistView extends UpdateView {
public ArtistView(Context context) {
super(context);
this.context = context;
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
+ LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true);
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
- starButton.setFocusable(false);
- moreButton = (ImageView) findViewById(R.id.artist_more);
+ titleView = (TextView) findViewById(R.id.item_name);
+ starButton = (ImageButton) findViewById(R.id.item_star);
+ starButton.setFocusable(false);
+ moreButton = (ImageView) findViewById(R.id.item_more);
moreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.showContextMenu();
diff --git a/src/github/daneren2005/dsub/view/BookmarkAdapter.java b/src/github/daneren2005/dsub/view/BookmarkAdapter.java
new file mode 100644
index 00000000..bcddc574
--- /dev/null
+++ b/src/github/daneren2005/dsub/view/BookmarkAdapter.java
@@ -0,0 +1,62 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2010 (C) Sindre Mehus
+*/
+
+package github.daneren2005.dsub.view;
+
+import android.content.Context;
+import android.util.Log;
+import java.util.List;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.domain.Bookmark;
+import github.daneren2005.dsub.domain.MusicDirectory;
+import github.daneren2005.dsub.util.Util;
+
+public class BookmarkAdapter extends ArrayAdapter<Bookmark> {
+ private final static String TAG = BookmarkAdapter.class.getSimpleName();
+ private Context activity;
+
+ public BookmarkAdapter(Context activity, List<Bookmark> bookmarks) {
+ super(activity, android.R.layout.simple_list_item_1, bookmarks);
+ this.activity = activity;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ Bookmark bookmark = getItem(position);
+ MusicDirectory.Entry entry = bookmark.getEntry();
+ SongView view;
+ if (convertView != null) {
+ view = (SongView) convertView;
+ } else {
+ view = new SongView(activity);
+ }
+ view.setObject(entry, false);
+
+ // Add current position to duration
+ TextView durationTextView = (TextView) view.findViewById(R.id.song_duration);
+ String duration = durationTextView.getText().toString();
+ durationTextView.setText(Util.formatDuration(bookmark.getPosition() / 1000) + " / " + duration);
+
+ return view;
+ }
+}
diff --git a/src/github/daneren2005/dsub/view/DrawerAdapter.java b/src/github/daneren2005/dsub/view/DrawerAdapter.java
new file mode 100644
index 00000000..d3639373
--- /dev/null
+++ b/src/github/daneren2005/dsub/view/DrawerAdapter.java
@@ -0,0 +1,68 @@
+/*
+ This file is part of Subsonic.
+
+ Subsonic is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Subsonic is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Subsonic. If not, see <http://www.gnu.org/licenses/>.
+
+ Copyright 2009 (C) Sindre Mehus
+*/
+package github.daneren2005.dsub.view;
+
+import android.content.Context;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import java.util.List;
+
+import github.daneren2005.dsub.R;
+
+/**
+ * Created by Scott on 11/8/13.
+ */
+public class DrawerAdapter extends ArrayAdapter<String> {
+ private static String TAG = DrawerAdapter.class.getSimpleName();
+ private Context context;
+ private List<String> items;
+ private List<Integer> icons;
+
+ public DrawerAdapter(Context context, List<String> items, List<Integer> icons) {
+ super(context, R.layout.drawer_list_item, items);
+
+ this.context = context;
+ this.items = items;
+ this.icons = icons;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ String item = items.get(position);
+ Integer icon = icons.get(position);
+
+ if(convertView == null) {
+ convertView = LayoutInflater.from(context).inflate(R.layout.drawer_list_item, null);
+ }
+
+ TextView textView = (TextView) convertView.findViewById(R.id.drawer_name);
+ textView.setText(item);
+ ImageView iconView = (ImageView) convertView.findViewById(R.id.drawer_icon);
+ Log.d(TAG, "icon: " + icon);
+ iconView.setImageResource(icon);
+
+ return convertView;
+ }
+}
diff --git a/src/github/daneren2005/dsub/view/ErrorDialog.java b/src/github/daneren2005/dsub/view/ErrorDialog.java
index e9f25a2d..246b3756 100644
--- a/src/github/daneren2005/dsub/view/ErrorDialog.java
+++ b/src/github/daneren2005/dsub/view/ErrorDialog.java
@@ -22,8 +22,9 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
-import github.daneren2005.dsub.activity.MainActivity;
+
import github.daneren2005.dsub.R;
+import github.daneren2005.dsub.activity.SubsonicFragmentActivity;
import github.daneren2005.dsub.util.Util;
/**
@@ -59,11 +60,15 @@ public class ErrorDialog {
}
});
- builder.create().show();
+ try {
+ builder.create().show();
+ } catch(Exception e) {
+ // Don't care, just means no activity to attach to
+ }
}
private void restart(Activity context) {
- Intent intent = new Intent(context, MainActivity.class);
+ Intent intent = new Intent(context, SubsonicFragmentActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Util.startActivityWithoutTransition(context, intent);
}
diff --git a/src/github/daneren2005/dsub/view/GenreView.java b/src/github/daneren2005/dsub/view/GenreView.java
index 69456c28..6a8e04ef 100644
--- a/src/github/daneren2005/dsub/view/GenreView.java
+++ b/src/github/daneren2005/dsub/view/GenreView.java
@@ -34,12 +34,13 @@ public class GenreView extends UpdateView {
public GenreView(Context context) {
super(context);
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
+ LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true);
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
+ titleView = (TextView) findViewById(R.id.item_name);
+ starButton = (ImageButton) findViewById(R.id.item_star);
starButton.setFocusable(false);
- moreButton = (ImageView) findViewById(R.id.artist_more);
+ moreButton = (ImageView) findViewById(R.id.item_more);
+ moreButton.setVisibility(View.GONE);
moreButton.setClickable(false);
}
diff --git a/src/github/daneren2005/dsub/view/PlaylistAdapter.java b/src/github/daneren2005/dsub/view/PlaylistAdapter.java
index f25996dd..ff0294b7 100644
--- a/src/github/daneren2005/dsub/view/PlaylistAdapter.java
+++ b/src/github/daneren2005/dsub/view/PlaylistAdapter.java
@@ -36,7 +36,7 @@ public class PlaylistAdapter extends ArrayAdapter<Playlist> {
private final Context activity;
public PlaylistAdapter(Context activity, List<Playlist> Playlists) {
- super(activity, R.layout.playlist_list_item, Playlists);
+ super(activity, R.layout.basic_list_item, Playlists);
this.activity = activity;
}
diff --git a/src/github/daneren2005/dsub/view/PlaylistView.java b/src/github/daneren2005/dsub/view/PlaylistView.java
index 31332b22..c75f8ad7 100644
--- a/src/github/daneren2005/dsub/view/PlaylistView.java
+++ b/src/github/daneren2005/dsub/view/PlaylistView.java
@@ -21,6 +21,7 @@ package github.daneren2005.dsub.view;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import github.daneren2005.dsub.R;
@@ -39,17 +40,18 @@ public class PlaylistView extends UpdateView {
private Context context;
private Playlist playlist;
- private File file;
private TextView titleView;
public PlaylistView(Context context) {
super(context);
this.context = context;
- LayoutInflater.from(context).inflate(R.layout.playlist_list_item, this, true);
+ LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true);
- titleView = (TextView) findViewById(R.id.playlist_name);
- moreButton = (ImageView) findViewById(R.id.playlist_more);
+ titleView = (TextView) findViewById(R.id.item_name);
+ starButton = (ImageButton) findViewById(R.id.item_star);
+ starButton.setFocusable(false);
+ moreButton = (ImageView) findViewById(R.id.item_more);
moreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.showContextMenu();
@@ -60,11 +62,5 @@ public class PlaylistView extends UpdateView {
protected void setObjectImpl(Object obj) {
this.playlist = (Playlist) obj;
titleView.setText(playlist.getName());
- file = FileUtil.getPlaylistFile(Util.getServerName(context), playlist.getName());
- }
-
- @Override
- protected void updateBackground() {
- exists = file.exists();
}
}
diff --git a/src/github/daneren2005/dsub/view/PodcastChannelView.java b/src/github/daneren2005/dsub/view/PodcastChannelView.java
index 5b9225d7..9ad78d1c 100644
--- a/src/github/daneren2005/dsub/view/PodcastChannelView.java
+++ b/src/github/daneren2005/dsub/view/PodcastChannelView.java
@@ -41,12 +41,12 @@ public class PodcastChannelView extends UpdateView {
public PodcastChannelView(Context context) {
super(context);
this.context = context;
- LayoutInflater.from(context).inflate(R.layout.artist_list_item, this, true);
+ LayoutInflater.from(context).inflate(R.layout.basic_list_item, this, true);
- titleView = (TextView) findViewById(R.id.artist_name);
- starButton = (ImageButton) findViewById(R.id.artist_star);
+ titleView = (TextView) findViewById(R.id.item_name);
+ starButton = (ImageButton) findViewById(R.id.item_star);
starButton.setFocusable(false);
- moreButton = (ImageView) findViewById(R.id.artist_more);
+ moreButton = (ImageView) findViewById(R.id.item_more);
moreButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.showContextMenu();
diff --git a/src/github/daneren2005/dsub/view/SongView.java b/src/github/daneren2005/dsub/view/SongView.java
index 3106d38c..c256495b 100644
--- a/src/github/daneren2005/dsub/view/SongView.java
+++ b/src/github/daneren2005/dsub/view/SongView.java
@@ -19,6 +19,7 @@
package github.daneren2005.dsub.view;
import android.content.Context;
+import android.content.res.TypedArray;
import android.media.MediaMetadataRetriever;
import android.util.Log;
import android.view.LayoutInflater;
@@ -42,8 +43,7 @@ import java.text.DateFormat;
*/
public class SongView extends UpdateView implements Checkable {
private static final String TAG = SongView.class.getSimpleName();
-
- private Context context;
+
private MusicDirectory.Entry song;
private CheckedTextView checkedTextView;
@@ -51,22 +51,23 @@ public class SongView extends UpdateView implements Checkable {
private TextView artistTextView;
private TextView durationTextView;
private TextView statusTextView;
+ private ImageView statusImageView;
private DownloadService downloadService;
private long revision = -1;
private DownloadFile downloadFile;
private boolean playing = false;
- private int rightImage = 0;
+ private boolean rightImage = false;
private int moreImage = 0;
private boolean isWorkDone = false;
private boolean isSaved = false;
private File partialFile;
private boolean partialFileExists = false;
+ private boolean loaded = false;
public SongView(Context context) {
super(context);
- this.context = context;
LayoutInflater.from(context).inflate(R.layout.song_list_item, this, true);
checkedTextView = (CheckedTextView) findViewById(R.id.song_check);
@@ -74,6 +75,7 @@ public class SongView extends UpdateView implements Checkable {
artistTextView = (TextView) findViewById(R.id.song_artist);
durationTextView = (TextView) findViewById(R.id.song_duration);
statusTextView = (TextView) findViewById(R.id.song_status);
+ statusImageView = (ImageView) findViewById(R.id.song_status_icon);
starButton = (ImageButton) findViewById(R.id.song_star);
starButton.setFocusable(false);
moreButton = (ImageView) findViewById(R.id.artist_more);
@@ -142,6 +144,7 @@ public class SongView extends UpdateView implements Checkable {
checkedTextView.setVisibility(checkable && !song.isVideo() ? View.VISIBLE : View.GONE);
revision = -1;
+ loaded = false;
}
@Override
@@ -164,10 +167,19 @@ public class SongView extends UpdateView implements Checkable {
partialFile = downloadFile.getPartialFile();
partialFileExists = partialFile.exists();
isStarred = song.isStarred();
+
+ // Check if needs to load metadata: check against all fields that we know are null in offline mode
+ if(song.getBitRate() == null && song.getDuration() == null && song.getDiscNumber() == null && isWorkDone) {
+ song.loadMetadata(downloadFile.getCompleteFile());
+ loaded = true;
+ }
}
@Override
protected void update() {
+ if(loaded) {
+ setObjectImpl(song, checkedTextView.getVisibility() == View.VISIBLE);
+ }
if (downloadService == null) {
return;
}
@@ -184,34 +196,39 @@ public class SongView extends UpdateView implements Checkable {
}
}
- int rightImage = 0;
if (isWorkDone) {
- int moreImage = isSaved ? R.drawable.list_item_more_saved : R.drawable.list_item_more_shaded;
+ int moreImage = isSaved ? R.drawable.download_pinned : R.drawable.download_cached;
if(moreImage != this.moreImage) {
moreButton.setImageResource(moreImage);
this.moreImage = moreImage;
}
- } else if(this.moreImage != R.drawable.list_item_more) {
- moreButton.setImageResource(R.drawable.list_item_more);
- this.moreImage = R.drawable.list_item_more;
+ } else if(true) {
+ int[] attrs = new int[] {R.attr.download_none};
+ TypedArray typedArray = context.obtainStyledAttributes(attrs);
+ moreButton.setImageResource(typedArray.getResourceId(0, 0));
+ typedArray.recycle();
+ this.moreImage = R.drawable.download_none_light;
}
if (downloadFile.isDownloading() && !downloadFile.isDownloadCancelled() && partialFileExists) {
statusTextView.setText(Util.formatLocalizedBytes(partialFile.length(), getContext()));
- rightImage = R.drawable.downloading;
- } else if(this.rightImage != 0) {
+ if(!rightImage) {
+ statusImageView.setVisibility(View.VISIBLE);
+ rightImage = true;
+ }
+ } else if(rightImage) {
statusTextView.setText(null);
+ statusImageView.setVisibility(View.GONE);
+ rightImage = false;
}
- if(this.rightImage != rightImage) {
- statusTextView.setCompoundDrawablesWithIntrinsicBounds(0, 0, rightImage, 0);
- this.rightImage = rightImage;
- }
boolean playing = downloadService.getCurrentPlaying() == downloadFile;
if (playing) {
if(!this.playing) {
this.playing = playing;
- titleTextView.setCompoundDrawablesWithIntrinsicBounds(R.drawable.stat_notify_playing, 0, 0, 0);
+ int[] attrs = new int[] {R.attr.media_button_start};
+ TypedArray typedArray = context.obtainStyledAttributes(attrs);
+ titleTextView.setCompoundDrawablesWithIntrinsicBounds(typedArray.getResourceId(0, 0), 0, 0, 0);
}
} else {
if(this.playing) {
diff --git a/src/github/daneren2005/dsub/view/UpdateView.java b/src/github/daneren2005/dsub/view/UpdateView.java
index 48d9cf94..05b17417 100644
--- a/src/github/daneren2005/dsub/view/UpdateView.java
+++ b/src/github/daneren2005/dsub/view/UpdateView.java
@@ -19,6 +19,7 @@
package github.daneren2005.dsub.view;
import android.content.Context;
+import android.content.res.TypedArray;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
@@ -41,7 +42,8 @@ public class UpdateView extends LinearLayout {
private static Handler backgroundHandler;
private static Handler uiHandler;
private static Runnable updateRunnable;
-
+
+ protected Context context;
protected ImageButton starButton;
protected ImageView moreButton;
@@ -52,6 +54,7 @@ public class UpdateView extends LinearLayout {
public UpdateView(Context context) {
super(context);
+ this.context = context;
setLayoutParams(new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT,
@@ -99,6 +102,8 @@ public class UpdateView extends LinearLayout {
}
uiHandler = new Handler();
+ // Needed so handler is never null until thread creates it
+ backgroundHandler = uiHandler;
updateRunnable = new Runnable() {
@Override
public void run() {
@@ -166,12 +171,14 @@ public class UpdateView extends LinearLayout {
if(moreButton != null) {
if(exists) {
if(!shaded) {
- moreButton.setImageResource(R.drawable.list_item_more_shaded);
+ moreButton.setImageResource(R.drawable.download_cached);
shaded = true;
}
} else {
if(shaded) {
- moreButton.setImageResource(R.drawable.list_item_more);
+ int[] attrs = new int[] {R.attr.download_none};
+ TypedArray typedArray = context.obtainStyledAttributes(attrs);
+ moreButton.setImageResource(typedArray.getResourceId(0, 0));
shaded = false;
}
}