From feca33c9ac8fd22e1e856e977d76efc98f556a51 Mon Sep 17 00:00:00 2001 From: Joshua Bahnsen Date: Wed, 23 May 2012 15:45:11 -0700 Subject: [PATCH] Removed Option Menu on post 3.x devices, added Settings and Help buttons instead of option menu, changed icon for server selection --- res/layout/action_bar.xml | 44 +- res/layout/main_buttons.xml | 10 +- .../androidapp/activity/MainActivity.java | 545 ++++++------ .../androidapp/activity/SearchActivity.java | 754 ++++++++--------- .../activity/SelectAlbumActivity.java | 20 + .../activity/SelectArtistActivity.java | 474 ++++++----- .../activity/SelectPlaylistActivity.java | 310 +++---- .../activity/SubsonicTabActivity.java | 776 +++++++++--------- 8 files changed, 1519 insertions(+), 1414 deletions(-) diff --git a/res/layout/action_bar.xml b/res/layout/action_bar.xml index c2f0343c..ea3b302a 100644 --- a/res/layout/action_bar.xml +++ b/res/layout/action_bar.xml @@ -19,7 +19,7 @@ a:paddingTop="2dip" a:scaleType="centerInside" a:src="@drawable/main_header_icon" /> - /> + /> + + + a:src="@drawable/ic_menu_settings" /> + + + a:src="@drawable/ic_menu_shuffle" /> - - - + \ No newline at end of file diff --git a/res/layout/main_buttons.xml b/res/layout/main_buttons.xml index fa28cd72..de2cc574 100644 --- a/res/layout/main_buttons.xml +++ b/res/layout/main_buttons.xml @@ -13,12 +13,12 @@ a:layout_width="fill_parent" a:layout_height="wrap_content" a:minHeight="?android:attr/listPreferredItemHeight"> - + + a:layout_width="wrap_content" + a:layout_height="wrap_content" + a:layout_gravity="center_vertical" + a:src="@drawable/ic_menu_select_artist_folder" /> . - - Copyright 2009 (C) Sindre Mehus - */ - -package net.sourceforge.subsonic.androidapp.activity; - -import java.util.Arrays; - -import net.sourceforge.subsonic.androidapp.R; -import net.sourceforge.subsonic.androidapp.service.DownloadService; -import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl; -import net.sourceforge.subsonic.androidapp.util.Constants; -import net.sourceforge.subsonic.androidapp.util.MergeAdapter; -import net.sourceforge.subsonic.androidapp.util.Util; -import net.sourceforge.subsonic.androidapp.util.FileUtil; -import android.content.Intent; -import android.content.SharedPreferences; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; - -public class MainActivity extends SubsonicTabActivity { - - private static final int MENU_GROUP_SERVER = 10; - private static final int MENU_ITEM_SERVER_1 = 101; - private static final int MENU_ITEM_SERVER_2 = 102; - private static final int MENU_ITEM_SERVER_3 = 103; - private static final int MENU_ITEM_OFFLINE = 104; - - private String theme; - - private static boolean infoDialogDisplayed; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) { - exit(); - } - setContentView(R.layout.main); - - loadSettings(); - - View buttons = LayoutInflater.from(this).inflate(R.layout.main_buttons, null); - - final View serverButton = buttons.findViewById(R.id.main_select_server); - final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2); - - final View albumsTitle = buttons.findViewById(R.id.main_albums); - final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest); - final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random); - final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest); - final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent); - final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent); - - final View dummyView = findViewById(R.id.main_dummy); - - int instance = Util.getActiveServer(this); - String name = Util.getServerName(this, instance); - serverTextView.setText(name); - - ListView list = (ListView) findViewById(R.id.main_list); - - MergeAdapter adapter = new MergeAdapter(); - adapter.addViews(Arrays.asList(serverButton), true); - if (!Util.isOffline(this)) { - adapter.addView(albumsTitle, false); - adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsRecentButton, albumsFrequentButton), true); - } - list.setAdapter(adapter); - registerForContextMenu(dummyView); - - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view == serverButton) { - dummyView.showContextMenu(); - } else if (view == albumsNewestButton) { - showAlbumList("newest"); - } else if (view == albumsRandomButton) { - showAlbumList("random"); - } else if (view == albumsHighestButton) { - showAlbumList("highest"); - } else if (view == albumsRecentButton) { - showAlbumList("recent"); - } else if (view == albumsFrequentButton) { - showAlbumList("frequent"); - } - } - }); - - // Title: Subsonic - setTitle(R.string.common_appname); - - // Button 1: shuffle - ImageButton actionShuffleButton = (ImageButton)findViewById(R.id.action_button_1); - actionShuffleButton.setImageResource(R.drawable.ic_menu_shuffle); - actionShuffleButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(MainActivity.this, DownloadActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - Util.startActivityWithoutTransition(MainActivity.this, intent); - } - }); - - // Button 2: search - ImageButton actionSearchButton = (ImageButton)findViewById(R.id.action_button_2); - actionSearchButton.setImageResource(R.drawable.ic_menu_search); - actionSearchButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(MainActivity.this, SearchActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true); - Util.startActivityWithoutTransition(MainActivity.this, intent); - } - }); - - // Button 3: menu - ImageButton actionMenuButton = (ImageButton)findViewById(R.id.action_button_3); - actionMenuButton.setImageResource(R.drawable.ic_menu_moreoverflow); - actionMenuButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - openOptionsMenu(); - } - }); - - // Remember the current theme. - theme = Util.getTheme(this); - - showInfoDialog(); - } - - 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(); - } - } - - @Override - protected void onResume() { - super.onResume(); - - // Restart activity if theme has changed. - if (theme != null && !theme.equals(Util.getTheme(this))) { - restart(); - } - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - MenuItem menuItem1 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_1, MENU_ITEM_SERVER_1, Util.getServerName(this, 1)); - MenuItem menuItem2 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_2, MENU_ITEM_SERVER_2, Util.getServerName(this, 2)); - MenuItem menuItem3 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_3, MENU_ITEM_SERVER_3, Util.getServerName(this, 3)); - MenuItem menuItem4 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_OFFLINE, MENU_ITEM_OFFLINE, Util.getServerName(this, 0)); - menu.setGroupCheckable(MENU_GROUP_SERVER, true, true); - menu.setHeaderTitle(R.string.main_select_server); - - switch (Util.getActiveServer(this)) { - case 0: - menuItem4.setChecked(true); - break; - case 1: - menuItem1.setChecked(true); - break; - case 2: - menuItem2.setChecked(true); - break; - case 3: - menuItem3.setChecked(true); - break; - } - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - switch (menuItem.getItemId()) { - case MENU_ITEM_OFFLINE: - setActiveServer(0); - break; - case MENU_ITEM_SERVER_1: - setActiveServer(1); - break; - case MENU_ITEM_SERVER_2: - setActiveServer(2); - break; - case MENU_ITEM_SERVER_3: - setActiveServer(3); - break; - default: - return super.onContextItemSelected(menuItem); - } - - // Restart activity - restart(); - return true; - } - - private void setActiveServer(int instance) { - if (Util.getActiveServer(this) != instance) { - DownloadService service = getDownloadService(); - if (service != null) { - service.clearIncomplete(); - } - Util.setActiveServer(this, instance); - } - } - - private void restart() { - Intent intent = new Intent(this, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(this, intent); - } - - private void exit() { - stopService(new Intent(this, DownloadServiceImpl.class)); - finish(); - } - - private void showInfoDialog() { - if (!infoDialogDisplayed) { - infoDialogDisplayed = true; - if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) { - Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text); - } - } - } - - private void showAlbumList(String type) { - Intent intent = new Intent(this, SelectAlbumActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); - Util.startActivityWithoutTransition(this, intent); - } +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ + +package net.sourceforge.subsonic.androidapp.activity; + +import java.util.Arrays; + +import net.sourceforge.subsonic.androidapp.R; +import net.sourceforge.subsonic.androidapp.service.DownloadService; +import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl; +import net.sourceforge.subsonic.androidapp.util.Constants; +import net.sourceforge.subsonic.androidapp.util.MergeAdapter; +import net.sourceforge.subsonic.androidapp.util.Util; +import net.sourceforge.subsonic.androidapp.util.FileUtil; +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.AdapterView; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; + +public class MainActivity extends SubsonicTabActivity { + + private static final int MENU_GROUP_SERVER = 10; + private static final int MENU_ITEM_SERVER_1 = 101; + private static final int MENU_ITEM_SERVER_2 = 102; + private static final int MENU_ITEM_SERVER_3 = 103; + private static final int MENU_ITEM_OFFLINE = 104; + + private String theme; + + private static boolean infoDialogDisplayed; + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (getIntent().hasExtra(Constants.INTENT_EXTRA_NAME_EXIT)) { + exit(); + } + setContentView(R.layout.main); + + loadSettings(); + + View buttons = LayoutInflater.from(this).inflate(R.layout.main_buttons, null); + + final View serverButton = buttons.findViewById(R.id.main_select_server); + final TextView serverTextView = (TextView) serverButton.findViewById(R.id.main_select_server_2); + + final View albumsTitle = buttons.findViewById(R.id.main_albums); + final View albumsNewestButton = buttons.findViewById(R.id.main_albums_newest); + final View albumsRandomButton = buttons.findViewById(R.id.main_albums_random); + final View albumsHighestButton = buttons.findViewById(R.id.main_albums_highest); + final View albumsRecentButton = buttons.findViewById(R.id.main_albums_recent); + final View albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent); + + final View dummyView = findViewById(R.id.main_dummy); + + int instance = Util.getActiveServer(this); + String name = Util.getServerName(this, instance); + serverTextView.setText(name); + + ListView list = (ListView) findViewById(R.id.main_list); + + MergeAdapter adapter = new MergeAdapter(); + adapter.addViews(Arrays.asList(serverButton), true); + if (!Util.isOffline(this)) { + adapter.addView(albumsTitle, false); + adapter.addViews(Arrays.asList(albumsNewestButton, albumsRandomButton, albumsHighestButton, albumsRecentButton, albumsFrequentButton), true); + } + list.setAdapter(adapter); + registerForContextMenu(dummyView); + + list.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (view == serverButton) { + dummyView.showContextMenu(); + } else if (view == albumsNewestButton) { + showAlbumList("newest"); + } else if (view == albumsRandomButton) { + showAlbumList("random"); + } else if (view == albumsHighestButton) { + showAlbumList("highest"); + } else if (view == albumsRecentButton) { + showAlbumList("recent"); + } else if (view == albumsFrequentButton) { + showAlbumList("frequent"); + } + } + }); + + // Title: Subsonic + setTitle(R.string.common_appname); + + // Button 1: search + ImageButton actionSearchButton = (ImageButton)findViewById(R.id.action_button_1); + actionSearchButton.setImageResource(R.drawable.ic_menu_search); + actionSearchButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(MainActivity.this, SearchActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true); + Util.startActivityWithoutTransition(MainActivity.this, intent); + } + }); + + // Button 2: shuffle + ImageButton actionShuffleButton = (ImageButton)findViewById(R.id.action_button_2); + actionShuffleButton.setImageResource(R.drawable.ic_menu_shuffle); + actionShuffleButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(MainActivity.this, DownloadActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); + Util.startActivityWithoutTransition(MainActivity.this, intent); + } + }); + + // Button 3: help + ImageButton actionHelpButton = (ImageButton)findViewById(R.id.action_button_3); + actionHelpButton.setImageResource(R.drawable.ic_menu_help); + actionHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(MainActivity.this, HelpActivity.class)); + } + }); + + // Button 4: settings + ImageButton actionSettingsButton = (ImageButton)findViewById(R.id.action_button_4); + actionSettingsButton.setImageResource(R.drawable.ic_menu_settings); + actionSettingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(MainActivity.this, SettingsActivity.class)); + } + }); + + // Remember the current theme. + theme = Util.getTheme(this); + + showInfoDialog(); + } + + 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(); + } + } + + @Override + protected void onResume() { + super.onResume(); + + // Restart activity if theme has changed. + if (theme != null && !theme.equals(Util.getTheme(this))) { + restart(); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, view, menuInfo); + + MenuItem menuItem1 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_1, MENU_ITEM_SERVER_1, Util.getServerName(this, 1)); + MenuItem menuItem2 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_2, MENU_ITEM_SERVER_2, Util.getServerName(this, 2)); + MenuItem menuItem3 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_SERVER_3, MENU_ITEM_SERVER_3, Util.getServerName(this, 3)); + MenuItem menuItem4 = menu.add(MENU_GROUP_SERVER, MENU_ITEM_OFFLINE, MENU_ITEM_OFFLINE, Util.getServerName(this, 0)); + menu.setGroupCheckable(MENU_GROUP_SERVER, true, true); + menu.setHeaderTitle(R.string.main_select_server); + + switch (Util.getActiveServer(this)) { + case 0: + menuItem4.setChecked(true); + break; + case 1: + menuItem1.setChecked(true); + break; + case 2: + menuItem2.setChecked(true); + break; + case 3: + menuItem3.setChecked(true); + break; + } + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) { + switch (menuItem.getItemId()) { + case MENU_ITEM_OFFLINE: + setActiveServer(0); + break; + case MENU_ITEM_SERVER_1: + setActiveServer(1); + break; + case MENU_ITEM_SERVER_2: + setActiveServer(2); + break; + case MENU_ITEM_SERVER_3: + setActiveServer(3); + break; + default: + return super.onContextItemSelected(menuItem); + } + + // Restart activity + restart(); + return true; + } + + private void setActiveServer(int instance) { + if (Util.getActiveServer(this) != instance) { + DownloadService service = getDownloadService(); + if (service != null) { + service.clearIncomplete(); + } + Util.setActiveServer(this, instance); + } + } + + private void restart() { + Intent intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + Util.startActivityWithoutTransition(this, intent); + } + + private void exit() { + stopService(new Intent(this, DownloadServiceImpl.class)); + finish(); + } + + private void showInfoDialog() { + if (!infoDialogDisplayed) { + infoDialogDisplayed = true; + if (Util.getRestUrl(this, null).contains("demo.subsonic.org")) { + Util.info(this, R.string.main_welcome_title, R.string.main_welcome_text); + } + } + } + + private void showAlbumList(String type) { + Intent intent = new Intent(this, SelectAlbumActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 20); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0); + Util.startActivityWithoutTransition(this, intent); + } } \ No newline at end of file diff --git a/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java b/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java index 31f70678..9ea95ad6 100644 --- a/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java +++ b/src/net/sourceforge/subsonic/androidapp/activity/SearchActivity.java @@ -1,368 +1,388 @@ -/* - 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 . - - Copyright 2009 (C) Sindre Mehus - */ - -package net.sourceforge.subsonic.androidapp.activity; - -import java.util.ArrayList; -import java.util.List; -import java.util.Arrays; - -import android.content.Intent; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.View; -import android.view.MenuItem; -import android.widget.AdapterView; -import android.widget.ImageButton; -import android.widget.ListAdapter; -import android.widget.ListView; -import android.widget.TextView; -import android.net.Uri; -import net.sourceforge.subsonic.androidapp.R; -import net.sourceforge.subsonic.androidapp.domain.Artist; -import net.sourceforge.subsonic.androidapp.domain.MusicDirectory; -import net.sourceforge.subsonic.androidapp.domain.SearchCritera; -import net.sourceforge.subsonic.androidapp.domain.SearchResult; -import net.sourceforge.subsonic.androidapp.service.MusicService; -import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; -import net.sourceforge.subsonic.androidapp.service.DownloadService; -import net.sourceforge.subsonic.androidapp.util.ArtistAdapter; -import net.sourceforge.subsonic.androidapp.util.BackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Constants; -import net.sourceforge.subsonic.androidapp.util.EntryAdapter; -import net.sourceforge.subsonic.androidapp.util.MergeAdapter; -import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Util; - -/** - * Performs searches and displays the matching artists, albums and songs. - * - * @author Sindre Mehus - */ -public class SearchActivity extends SubsonicTabActivity { - - private static final int DEFAULT_ARTISTS = 3; - private static final int DEFAULT_ALBUMS = 5; - private static final int DEFAULT_SONGS = 10; - - private static final int MAX_ARTISTS = 10; - private static final int MAX_ALBUMS = 20; - private static final int MAX_SONGS = 25; - private ListView list; - - private View artistsHeading; - private View albumsHeading; - private View songsHeading; - private TextView searchButton; - private View moreArtistsButton; - private View moreAlbumsButton; - private View moreSongsButton; - private SearchResult searchResult; - private MergeAdapter mergeAdapter; - private ArtistAdapter artistAdapter; - private ListAdapter moreArtistsAdapter; - private EntryAdapter albumAdapter; - private ListAdapter moreAlbumsAdapter; - private ListAdapter moreSongsAdapter; - private EntryAdapter songAdapter; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.search); - - setTitle(R.string.search_title); - - View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null); - - artistsHeading = buttons.findViewById(R.id.search_artists); - 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) findViewById(R.id.search_list); - - list.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view == searchButton) { - onSearchRequested(); - } else if (view == moreArtistsButton) { - expandArtists(); - } else if (view == moreAlbumsButton) { - expandAlbums(); - } else if (view == moreSongsButton) { - expandSongs(); - } else { - Object item = parent.getItemAtPosition(position); - if (item instanceof Artist) { - onArtistSelected((Artist) item); - } else if (item instanceof MusicDirectory.Entry) { - MusicDirectory.Entry entry = (MusicDirectory.Entry) item; - if (entry.isDirectory()) { - onAlbumSelected(entry, false); - } else if (entry.isVideo()) { - onVideoSelected(entry); - } else { - onSongSelected(entry, false, true, true, false); - } - - } - } - } - }); - registerForContextMenu(list); - - // Button 1: gone - findViewById(R.id.action_button_1).setVisibility(View.GONE); - - // Button 2: search - final ImageButton actionSearchButton = (ImageButton)findViewById(R.id.action_button_2); - actionSearchButton.setImageResource(R.drawable.ic_menu_search); - actionSearchButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - onSearchRequested(); - } - }); - - onNewIntent(getIntent()); - } - - @Override - protected void onNewIntent(Intent intent) { - super.onNewIntent(intent); - 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) { - mergeAdapter = new MergeAdapter(); - list.setAdapter(mergeAdapter); - search(query, autoplay); - } else { - populateList(); - if (requestsearch) - onSearchRequested(); - } - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - Object selectedItem = list.getItemAtPosition(info.position); - - boolean isArtist = selectedItem instanceof Artist; - boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory(); - boolean isSong = selectedItem instanceof MusicDirectory.Entry && (!((MusicDirectory.Entry) selectedItem).isDirectory()) - && (!((MusicDirectory.Entry) selectedItem).isVideo()); - - if (isArtist || isAlbum) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.select_album_context, menu); - } else if (isSong) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.select_song_context, menu); - } - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Object selectedItem = list.getItemAtPosition(info.position); - - Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null; - MusicDirectory.Entry entry = selectedItem instanceof MusicDirectory.Entry ? (MusicDirectory.Entry) selectedItem : null; - String id = artist != null ? artist.getId() : entry.getId(); - - switch (menuItem.getItemId()) { - case R.id.album_menu_play_now: - downloadRecursively(id, false, false, true); - break; - case R.id.album_menu_play_last: - downloadRecursively(id, false, true, false); - break; - case R.id.album_menu_pin: - downloadRecursively(id, true, true, false); - break; - case R.id.song_menu_play_now: - onSongSelected(entry, false, false, true, false); - break; - case R.id.song_menu_play_next: - onSongSelected(entry, false, true, false, true); - break; - case R.id.song_menu_play_last: - onSongSelected(entry, false, true, false, false); - break; - default: - return super.onContextItemSelected(menuItem); - } - - return true; - } - - private void search(final String query, final boolean autoplay) { - BackgroundTask task = new TabActivityBackgroundTask(this) { - @Override - protected SearchResult doInBackground() throws Throwable { - SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS); - MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this); - return service.search(criteria, SearchActivity.this, this); - } - - @Override - protected void done(SearchResult result) { - searchResult = result; - populateList(); - if (autoplay) { - autoplay(); - } - - } - }; - task.execute(); - } - - private void populateList() { - mergeAdapter = new MergeAdapter(); - mergeAdapter.addView(searchButton, true); - - if (searchResult != null) { - List artists = searchResult.getArtists(); - if (!artists.isEmpty()) { - mergeAdapter.addView(artistsHeading); - List displayedArtists = new ArrayList(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size()))); - artistAdapter = new ArtistAdapter(this, displayedArtists); - mergeAdapter.addAdapter(artistAdapter); - if (artists.size() > DEFAULT_ARTISTS) { - moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true); - } - } - - List albums = searchResult.getAlbums(); - if (!albums.isEmpty()) { - mergeAdapter.addView(albumsHeading); - List displayedAlbums = new ArrayList(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size()))); - albumAdapter = new EntryAdapter(this, getImageLoader(), displayedAlbums, false); - mergeAdapter.addAdapter(albumAdapter); - if (albums.size() > DEFAULT_ALBUMS) { - moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true); - } - } - - List songs = searchResult.getSongs(); - if (!songs.isEmpty()) { - mergeAdapter.addView(songsHeading); - List displayedSongs = new ArrayList(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size()))); - songAdapter = new EntryAdapter(this, getImageLoader(), displayedSongs, false); - mergeAdapter.addAdapter(songAdapter); - if (songs.size() > DEFAULT_SONGS) { - moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true); - } - } - - 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); - } - - private void expandArtists() { - artistAdapter.clear(); - for (Artist artist : searchResult.getArtists()) { - artistAdapter.add(artist); - } - artistAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreArtistsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void expandAlbums() { - albumAdapter.clear(); - for (MusicDirectory.Entry album : searchResult.getAlbums()) { - albumAdapter.add(album); - } - albumAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreAlbumsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void expandSongs() { - songAdapter.clear(); - for (MusicDirectory.Entry song : searchResult.getSongs()) { - songAdapter.add(song); - } - songAdapter.notifyDataSetChanged(); - mergeAdapter.removeAdapter(moreSongsAdapter); - mergeAdapter.notifyDataSetChanged(); - } - - private void onArtistSelected(Artist artist) { - Intent intent = new Intent(this, SelectAlbumActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - Util.startActivityWithoutTransition(this, intent); - } - - private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) { - Intent intent = new Intent(SearchActivity.this, SelectAlbumActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, album.getId()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay); - Util.startActivityWithoutTransition(SearchActivity.this, intent); - } - - private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) { - DownloadService downloadService = getDownloadService(); - if (downloadService != null) { - if (!append) { - downloadService.clear(); - } - downloadService.download(Arrays.asList(song), save, false, playNext); - if (autoplay) { - downloadService.play(downloadService.size() - 1); - } - - Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1)); - } - } - - private void onVideoSelected(MusicDirectory.Entry entry) { - Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(this, entry.getId()))); - startActivity(intent); - } - - private void autoplay() { - if (!searchResult.getSongs().isEmpty()) { - onSongSelected(searchResult.getSongs().get(0), false, false, true, false); - } else if (!searchResult.getAlbums().isEmpty()) { - onAlbumSelected(searchResult.getAlbums().get(0), true); - } - } +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ + +package net.sourceforge.subsonic.androidapp.activity; + +import java.util.ArrayList; +import java.util.List; +import java.util.Arrays; + +import android.content.Intent; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.MenuInflater; +import android.view.View; +import android.view.MenuItem; +import android.widget.AdapterView; +import android.widget.ImageButton; +import android.widget.ListAdapter; +import android.widget.ListView; +import android.widget.TextView; +import android.net.Uri; +import net.sourceforge.subsonic.androidapp.R; +import net.sourceforge.subsonic.androidapp.domain.Artist; +import net.sourceforge.subsonic.androidapp.domain.MusicDirectory; +import net.sourceforge.subsonic.androidapp.domain.SearchCritera; +import net.sourceforge.subsonic.androidapp.domain.SearchResult; +import net.sourceforge.subsonic.androidapp.service.MusicService; +import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; +import net.sourceforge.subsonic.androidapp.service.DownloadService; +import net.sourceforge.subsonic.androidapp.util.ArtistAdapter; +import net.sourceforge.subsonic.androidapp.util.BackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Constants; +import net.sourceforge.subsonic.androidapp.util.EntryAdapter; +import net.sourceforge.subsonic.androidapp.util.MergeAdapter; +import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Util; + +/** + * Performs searches and displays the matching artists, albums and songs. + * + * @author Sindre Mehus + */ +public class SearchActivity extends SubsonicTabActivity { + + private static final int DEFAULT_ARTISTS = 3; + private static final int DEFAULT_ALBUMS = 5; + private static final int DEFAULT_SONGS = 10; + + private static final int MAX_ARTISTS = 10; + private static final int MAX_ALBUMS = 20; + private static final int MAX_SONGS = 25; + private ListView list; + + private View artistsHeading; + private View albumsHeading; + private View songsHeading; + private TextView searchButton; + private View moreArtistsButton; + private View moreAlbumsButton; + private View moreSongsButton; + private SearchResult searchResult; + private MergeAdapter mergeAdapter; + private ArtistAdapter artistAdapter; + private ListAdapter moreArtistsAdapter; + private EntryAdapter albumAdapter; + private ListAdapter moreAlbumsAdapter; + private ListAdapter moreSongsAdapter; + private EntryAdapter songAdapter; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.search); + + setTitle(R.string.search_title); + + View buttons = LayoutInflater.from(this).inflate(R.layout.search_buttons, null); + + artistsHeading = buttons.findViewById(R.id.search_artists); + 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) findViewById(R.id.search_list); + + list.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (view == searchButton) { + onSearchRequested(); + } else if (view == moreArtistsButton) { + expandArtists(); + } else if (view == moreAlbumsButton) { + expandAlbums(); + } else if (view == moreSongsButton) { + expandSongs(); + } else { + Object item = parent.getItemAtPosition(position); + if (item instanceof Artist) { + onArtistSelected((Artist) item); + } else if (item instanceof MusicDirectory.Entry) { + MusicDirectory.Entry entry = (MusicDirectory.Entry) item; + if (entry.isDirectory()) { + onAlbumSelected(entry, false); + } else if (entry.isVideo()) { + onVideoSelected(entry); + } else { + onSongSelected(entry, false, true, true, false); + } + + } + } + } + }); + registerForContextMenu(list); + + // Button 1: gone + findViewById(R.id.action_button_1).setVisibility(View.GONE); + + // Button 2: search + final ImageButton actionSearchButton = (ImageButton)findViewById(R.id.action_button_2); + actionSearchButton.setImageResource(R.drawable.ic_menu_search); + actionSearchButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + onSearchRequested(); + } + }); + + // Button 3: help + ImageButton actionHelpButton = (ImageButton)findViewById(R.id.action_button_3); + actionHelpButton.setImageResource(R.drawable.ic_menu_help); + actionHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SearchActivity.this, HelpActivity.class)); + } + }); + + // Button 4: settings + ImageButton actionSettingsButton = (ImageButton)findViewById(R.id.action_button_4); + actionSettingsButton.setImageResource(R.drawable.ic_menu_settings); + actionSettingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SearchActivity.this, SettingsActivity.class)); + } + }); + + onNewIntent(getIntent()); + } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + 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) { + mergeAdapter = new MergeAdapter(); + list.setAdapter(mergeAdapter); + search(query, autoplay); + } else { + populateList(); + if (requestsearch) + onSearchRequested(); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, view, menuInfo); + + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; + Object selectedItem = list.getItemAtPosition(info.position); + + boolean isArtist = selectedItem instanceof Artist; + boolean isAlbum = selectedItem instanceof MusicDirectory.Entry && ((MusicDirectory.Entry) selectedItem).isDirectory(); + boolean isSong = selectedItem instanceof MusicDirectory.Entry && (!((MusicDirectory.Entry) selectedItem).isDirectory()) + && (!((MusicDirectory.Entry) selectedItem).isVideo()); + + if (isArtist || isAlbum) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.select_album_context, menu); + } else if (isSong) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.select_song_context, menu); + } + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); + Object selectedItem = list.getItemAtPosition(info.position); + + Artist artist = selectedItem instanceof Artist ? (Artist) selectedItem : null; + MusicDirectory.Entry entry = selectedItem instanceof MusicDirectory.Entry ? (MusicDirectory.Entry) selectedItem : null; + String id = artist != null ? artist.getId() : entry.getId(); + + switch (menuItem.getItemId()) { + case R.id.album_menu_play_now: + downloadRecursively(id, false, false, true); + break; + case R.id.album_menu_play_last: + downloadRecursively(id, false, true, false); + break; + case R.id.album_menu_pin: + downloadRecursively(id, true, true, false); + break; + case R.id.song_menu_play_now: + onSongSelected(entry, false, false, true, false); + break; + case R.id.song_menu_play_next: + onSongSelected(entry, false, true, false, true); + break; + case R.id.song_menu_play_last: + onSongSelected(entry, false, true, false, false); + break; + default: + return super.onContextItemSelected(menuItem); + } + + return true; + } + + private void search(final String query, final boolean autoplay) { + BackgroundTask task = new TabActivityBackgroundTask(this) { + @Override + protected SearchResult doInBackground() throws Throwable { + SearchCritera criteria = new SearchCritera(query, MAX_ARTISTS, MAX_ALBUMS, MAX_SONGS); + MusicService service = MusicServiceFactory.getMusicService(SearchActivity.this); + return service.search(criteria, SearchActivity.this, this); + } + + @Override + protected void done(SearchResult result) { + searchResult = result; + populateList(); + if (autoplay) { + autoplay(); + } + + } + }; + task.execute(); + } + + private void populateList() { + mergeAdapter = new MergeAdapter(); + mergeAdapter.addView(searchButton, true); + + if (searchResult != null) { + List artists = searchResult.getArtists(); + if (!artists.isEmpty()) { + mergeAdapter.addView(artistsHeading); + List displayedArtists = new ArrayList(artists.subList(0, Math.min(DEFAULT_ARTISTS, artists.size()))); + artistAdapter = new ArtistAdapter(this, displayedArtists); + mergeAdapter.addAdapter(artistAdapter); + if (artists.size() > DEFAULT_ARTISTS) { + moreArtistsAdapter = mergeAdapter.addView(moreArtistsButton, true); + } + } + + List albums = searchResult.getAlbums(); + if (!albums.isEmpty()) { + mergeAdapter.addView(albumsHeading); + List displayedAlbums = new ArrayList(albums.subList(0, Math.min(DEFAULT_ALBUMS, albums.size()))); + albumAdapter = new EntryAdapter(this, getImageLoader(), displayedAlbums, false); + mergeAdapter.addAdapter(albumAdapter); + if (albums.size() > DEFAULT_ALBUMS) { + moreAlbumsAdapter = mergeAdapter.addView(moreAlbumsButton, true); + } + } + + List songs = searchResult.getSongs(); + if (!songs.isEmpty()) { + mergeAdapter.addView(songsHeading); + List displayedSongs = new ArrayList(songs.subList(0, Math.min(DEFAULT_SONGS, songs.size()))); + songAdapter = new EntryAdapter(this, getImageLoader(), displayedSongs, false); + mergeAdapter.addAdapter(songAdapter); + if (songs.size() > DEFAULT_SONGS) { + moreSongsAdapter = mergeAdapter.addView(moreSongsButton, true); + } + } + + 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); + } + + private void expandArtists() { + artistAdapter.clear(); + for (Artist artist : searchResult.getArtists()) { + artistAdapter.add(artist); + } + artistAdapter.notifyDataSetChanged(); + mergeAdapter.removeAdapter(moreArtistsAdapter); + mergeAdapter.notifyDataSetChanged(); + } + + private void expandAlbums() { + albumAdapter.clear(); + for (MusicDirectory.Entry album : searchResult.getAlbums()) { + albumAdapter.add(album); + } + albumAdapter.notifyDataSetChanged(); + mergeAdapter.removeAdapter(moreAlbumsAdapter); + mergeAdapter.notifyDataSetChanged(); + } + + private void expandSongs() { + songAdapter.clear(); + for (MusicDirectory.Entry song : searchResult.getSongs()) { + songAdapter.add(song); + } + songAdapter.notifyDataSetChanged(); + mergeAdapter.removeAdapter(moreSongsAdapter); + mergeAdapter.notifyDataSetChanged(); + } + + private void onArtistSelected(Artist artist) { + Intent intent = new Intent(this, SelectAlbumActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); + Util.startActivityWithoutTransition(this, intent); + } + + private void onAlbumSelected(MusicDirectory.Entry album, boolean autoplay) { + Intent intent = new Intent(SearchActivity.this, SelectAlbumActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, album.getId()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, album.getTitle()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, autoplay); + Util.startActivityWithoutTransition(SearchActivity.this, intent); + } + + private void onSongSelected(MusicDirectory.Entry song, boolean save, boolean append, boolean autoplay, boolean playNext) { + DownloadService downloadService = getDownloadService(); + if (downloadService != null) { + if (!append) { + downloadService.clear(); + } + downloadService.download(Arrays.asList(song), save, false, playNext); + if (autoplay) { + downloadService.play(downloadService.size() - 1); + } + + Util.toast(SearchActivity.this, getResources().getQuantityString(R.plurals.select_album_n_songs_added, 1, 1)); + } + } + + private void onVideoSelected(MusicDirectory.Entry entry) { + Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(MusicServiceFactory.getMusicService(this).getVideoUrl(this, entry.getId()))); + startActivity(intent); + } + + private void autoplay() { + if (!searchResult.getSongs().isEmpty()) { + onSongSelected(searchResult.getSongs().get(0), false, false, true, false); + } else if (!searchResult.getAlbums().isEmpty()) { + onAlbumSelected(searchResult.getAlbums().get(0), true); + } + } } \ No newline at end of file diff --git a/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java b/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java index 4c7fb4b0..3cec42cd 100644 --- a/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java +++ b/src/net/sourceforge/subsonic/androidapp/activity/SelectAlbumActivity.java @@ -190,6 +190,26 @@ public class SelectAlbumActivity extends SubsonicTabActivity { refresh(); } }); + + // Button 3: help + ImageButton actionHelpButton = (ImageButton)findViewById(R.id.action_button_3); + actionHelpButton.setImageResource(R.drawable.ic_menu_help); + actionHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SelectAlbumActivity.this, HelpActivity.class)); + } + }); + + // Button 4: settings + ImageButton actionSettingsButton = (ImageButton)findViewById(R.id.action_button_4); + actionSettingsButton.setImageResource(R.drawable.ic_menu_settings); + actionSettingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SelectAlbumActivity.this, SettingsActivity.class)); + } + }); } private void playAll() { diff --git a/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java b/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java index 1a444868..4e74404b 100644 --- a/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java +++ b/src/net/sourceforge/subsonic/androidapp/activity/SelectArtistActivity.java @@ -1,228 +1,248 @@ -/* - 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 . - - Copyright 2009 (C) Sindre Mehus - */ - -package net.sourceforge.subsonic.androidapp.activity; - -import android.content.Intent; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.LayoutInflater; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ImageButton; -import android.widget.ListView; -import android.widget.TextView; -import net.sourceforge.subsonic.androidapp.R; -import net.sourceforge.subsonic.androidapp.domain.Artist; -import net.sourceforge.subsonic.androidapp.domain.Indexes; -import net.sourceforge.subsonic.androidapp.domain.MusicFolder; -import net.sourceforge.subsonic.androidapp.service.MusicService; -import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; -import net.sourceforge.subsonic.androidapp.util.ArtistAdapter; -import net.sourceforge.subsonic.androidapp.util.BackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Constants; -import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Util; - -import java.util.ArrayList; -import java.util.List; - -public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener { - - private static final int MENU_GROUP_MUSIC_FOLDER = 10; - - private ListView artistList; - private View folderButton; - private TextView folderName; - private List musicFolders; - - /** - * Called when the activity is first created. - */ - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.select_artist); - - artistList = (ListView) findViewById(R.id.select_artist_list); - artistList.setOnItemClickListener(this); - - folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistList, false); - folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2); - - if (!Util.isOffline(this)) { - artistList.addHeaderView(folderButton); - } - - registerForContextMenu(artistList); - - setTitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label); - - // Button 1: shuffle - ImageButton shuffleButton = (ImageButton) findViewById(R.id.action_button_1); - shuffleButton.setImageResource(R.drawable.ic_menu_shuffle); - shuffleButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(SelectArtistActivity.this, DownloadActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); - Util.startActivityWithoutTransition(SelectArtistActivity.this, intent); - } - }); - - // Button 2: refresh - ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2); - refreshButton.setImageResource(R.drawable.ic_menu_refresh); - refreshButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - refresh(); - } - }); - - musicFolders = null; - load(); - } - - private void refresh() { - finish(); - Intent intent = getIntent(); - intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true); - Util.startActivityWithoutTransition(this, intent); - } - - private void selectFolder() { - folderButton.showContextMenu(); - } - - private void load() { - BackgroundTask task = new TabActivityBackgroundTask(this) { - @Override - protected Indexes doInBackground() throws Throwable { - boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false); - MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this); - if (!Util.isOffline(SelectArtistActivity.this)) { - musicFolders = musicService.getMusicFolders(SelectArtistActivity.this, this); - } - String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this); - return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this); - } - - @Override - protected void done(Indexes result) { - List artists = new ArrayList(result.getShortcuts().size() + result.getArtists().size()); - artists.addAll(result.getShortcuts()); - artists.addAll(result.getArtists()); - artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists)); - - // Display selected music folder - if (musicFolders != null) { - String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this); - if (musicFolderId == null) { - folderName.setText(R.string.select_artist_all_folders); - } else { - for (MusicFolder musicFolder : musicFolders) { - if (musicFolder.getId().equals(musicFolderId)) { - folderName.setText(musicFolder.getName()); - break; - } - } - } - } - } - }; - task.execute(); - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (view == folderButton) { - selectFolder(); - } else { - Artist artist = (Artist) parent.getItemAtPosition(position); - Intent intent = new Intent(this, SelectAlbumActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); - Util.startActivityWithoutTransition(this, intent); - } - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; - - if (artistList.getItemAtPosition(info.position) instanceof Artist) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.select_artist_context, menu); - } else if (info.position == 0) { - String musicFolderId = Util.getSelectedMusicFolderId(this); - MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders); - if (musicFolderId == null) { - menuItem.setChecked(true); - } - if (musicFolders != null) { - for (int i = 0; i < musicFolders.size(); i++) { - MusicFolder musicFolder = musicFolders.get(i); - menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName()); - if (musicFolder.getId().equals(musicFolderId)) { - menuItem.setChecked(true); - } - } - } - menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true); - } - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - - Artist artist = (Artist) artistList.getItemAtPosition(info.position); - - if (artist != null) { - switch (menuItem.getItemId()) { - case R.id.artist_menu_play_now: - downloadRecursively(artist.getId(), false, false, true); - break; - case R.id.artist_menu_play_last: - downloadRecursively(artist.getId(), false, true, false); - break; - case R.id.artist_menu_pin: - downloadRecursively(artist.getId(), true, true, false); - break; - default: - return super.onContextItemSelected(menuItem); - } - } else if (info.position == 0) { - MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId()); - String musicFolderId = selectedFolder == null ? null : selectedFolder.getId(); - String musicFolderName = selectedFolder == null ? getString(R.string.select_artist_all_folders) - : selectedFolder.getName(); - Util.setSelectedMusicFolderId(this, musicFolderId); - folderName.setText(musicFolderName); - refresh(); - } - - return true; - } +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ + +package net.sourceforge.subsonic.androidapp.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.LayoutInflater; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ImageButton; +import android.widget.ListView; +import android.widget.TextView; +import net.sourceforge.subsonic.androidapp.R; +import net.sourceforge.subsonic.androidapp.domain.Artist; +import net.sourceforge.subsonic.androidapp.domain.Indexes; +import net.sourceforge.subsonic.androidapp.domain.MusicFolder; +import net.sourceforge.subsonic.androidapp.service.MusicService; +import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; +import net.sourceforge.subsonic.androidapp.util.ArtistAdapter; +import net.sourceforge.subsonic.androidapp.util.BackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Constants; +import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Util; + +import java.util.ArrayList; +import java.util.List; + +public class SelectArtistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener { + + private static final int MENU_GROUP_MUSIC_FOLDER = 10; + + private ListView artistList; + private View folderButton; + private TextView folderName; + private List musicFolders; + + /** + * Called when the activity is first created. + */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.select_artist); + + artistList = (ListView) findViewById(R.id.select_artist_list); + artistList.setOnItemClickListener(this); + + folderButton = LayoutInflater.from(this).inflate(R.layout.select_artist_header, artistList, false); + folderName = (TextView) folderButton.findViewById(R.id.select_artist_folder_2); + + if (!Util.isOffline(this)) { + artistList.addHeaderView(folderButton); + } + + registerForContextMenu(artistList); + + setTitle(Util.isOffline(this) ? R.string.music_library_label_offline : R.string.music_library_label); + + // Button 1: shuffle + ImageButton shuffleButton = (ImageButton) findViewById(R.id.action_button_1); + shuffleButton.setImageResource(R.drawable.ic_menu_shuffle); + shuffleButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(SelectArtistActivity.this, DownloadActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_SHUFFLE, true); + Util.startActivityWithoutTransition(SelectArtistActivity.this, intent); + } + }); + + // Button 2: refresh + ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2); + refreshButton.setImageResource(R.drawable.ic_menu_refresh); + refreshButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + refresh(); + } + }); + + // Button 3: help + ImageButton actionHelpButton = (ImageButton)findViewById(R.id.action_button_3); + actionHelpButton.setImageResource(R.drawable.ic_menu_help); + actionHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SelectArtistActivity.this, HelpActivity.class)); + } + }); + + // Button 4: settings + ImageButton actionSettingsButton = (ImageButton)findViewById(R.id.action_button_4); + actionSettingsButton.setImageResource(R.drawable.ic_menu_settings); + actionSettingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SelectArtistActivity.this, SettingsActivity.class)); + } + }); + + musicFolders = null; + load(); + } + + private void refresh() { + finish(); + Intent intent = getIntent(); + intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true); + Util.startActivityWithoutTransition(this, intent); + } + + private void selectFolder() { + folderButton.showContextMenu(); + } + + private void load() { + BackgroundTask task = new TabActivityBackgroundTask(this) { + @Override + protected Indexes doInBackground() throws Throwable { + boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false); + MusicService musicService = MusicServiceFactory.getMusicService(SelectArtistActivity.this); + if (!Util.isOffline(SelectArtistActivity.this)) { + musicFolders = musicService.getMusicFolders(SelectArtistActivity.this, this); + } + String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this); + return musicService.getIndexes(musicFolderId, refresh, SelectArtistActivity.this, this); + } + + @Override + protected void done(Indexes result) { + List artists = new ArrayList(result.getShortcuts().size() + result.getArtists().size()); + artists.addAll(result.getShortcuts()); + artists.addAll(result.getArtists()); + artistList.setAdapter(new ArtistAdapter(SelectArtistActivity.this, artists)); + + // Display selected music folder + if (musicFolders != null) { + String musicFolderId = Util.getSelectedMusicFolderId(SelectArtistActivity.this); + if (musicFolderId == null) { + folderName.setText(R.string.select_artist_all_folders); + } else { + for (MusicFolder musicFolder : musicFolders) { + if (musicFolder.getId().equals(musicFolderId)) { + folderName.setText(musicFolder.getName()); + break; + } + } + } + } + } + }; + task.execute(); + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (view == folderButton) { + selectFolder(); + } else { + Artist artist = (Artist) parent.getItemAtPosition(position); + Intent intent = new Intent(this, SelectAlbumActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_ID, artist.getId()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_NAME, artist.getName()); + Util.startActivityWithoutTransition(this, intent); + } + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, view, menuInfo); + + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo; + + if (artistList.getItemAtPosition(info.position) instanceof Artist) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.select_artist_context, menu); + } else if (info.position == 0) { + String musicFolderId = Util.getSelectedMusicFolderId(this); + MenuItem menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders); + if (musicFolderId == null) { + menuItem.setChecked(true); + } + if (musicFolders != null) { + for (int i = 0; i < musicFolders.size(); i++) { + MusicFolder musicFolder = musicFolders.get(i); + menuItem = menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, musicFolder.getName()); + if (musicFolder.getId().equals(musicFolderId)) { + menuItem.setChecked(true); + } + } + } + menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true); + } + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); + + Artist artist = (Artist) artistList.getItemAtPosition(info.position); + + if (artist != null) { + switch (menuItem.getItemId()) { + case R.id.artist_menu_play_now: + downloadRecursively(artist.getId(), false, false, true); + break; + case R.id.artist_menu_play_last: + downloadRecursively(artist.getId(), false, true, false); + break; + case R.id.artist_menu_pin: + downloadRecursively(artist.getId(), true, true, false); + break; + default: + return super.onContextItemSelected(menuItem); + } + } else if (info.position == 0) { + MusicFolder selectedFolder = menuItem.getItemId() == -1 ? null : musicFolders.get(menuItem.getItemId()); + String musicFolderId = selectedFolder == null ? null : selectedFolder.getId(); + String musicFolderName = selectedFolder == null ? getString(R.string.select_artist_all_folders) + : selectedFolder.getName(); + Util.setSelectedMusicFolderId(this, musicFolderId); + folderName.setText(musicFolderName); + refresh(); + } + + return true; + } } \ No newline at end of file diff --git a/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java b/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java index 1706f8c2..fb31a088 100644 --- a/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java +++ b/src/net/sourceforge/subsonic/androidapp/activity/SelectPlaylistActivity.java @@ -1,146 +1,166 @@ -/* - 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 . - - Copyright 2009 (C) Sindre Mehus - */ - -package net.sourceforge.subsonic.androidapp.activity; - -import android.content.Intent; -import android.os.Bundle; -import android.view.ContextMenu; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.ImageButton; -import android.widget.ListView; -import net.sourceforge.subsonic.androidapp.R; -import net.sourceforge.subsonic.androidapp.domain.Playlist; -import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; -import net.sourceforge.subsonic.androidapp.service.MusicService; -import net.sourceforge.subsonic.androidapp.util.BackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Constants; -import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Util; - -import java.util.List; - -public class SelectPlaylistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener { - - private static final int MENU_ITEM_PLAY_ALL = 1; - - private ListView list; - private View emptyTextView; - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.select_playlist); - - list = (ListView) findViewById(R.id.select_playlist_list); - emptyTextView = findViewById(R.id.select_playlist_empty); - list.setOnItemClickListener(this); - registerForContextMenu(list); - - // Title: Playlists - setTitle(R.string.playlist_label); - - // Button 1: gone - ImageButton searchButton = (ImageButton)findViewById(R.id.action_button_1); - searchButton.setVisibility(View.GONE); - - // Button 2: refresh - ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2); - refreshButton.setImageResource(R.drawable.ic_menu_refresh); - refreshButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - refresh(); - } - }); - - load(); - } - - private void refresh() { - finish(); - Intent intent = new Intent(this, SelectPlaylistActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true); - Util.startActivityWithoutTransition(this, intent); - } - - private void load() { - BackgroundTask> task = new TabActivityBackgroundTask>(this) { - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this); - boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false); - return musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this); - } - - @Override - protected void done(List result) { - list.setAdapter(new PlaylistAdapter(result)); - emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE); - } - }; - task.execute(); - } - - @Override - public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { - super.onCreateContextMenu(menu, view, menuInfo); - menu.add(Menu.NONE, MENU_ITEM_PLAY_ALL, MENU_ITEM_PLAY_ALL, R.string.common_play_now); - } - - @Override - public boolean onContextItemSelected(MenuItem menuItem) { - AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); - Playlist playlist = (Playlist) list.getItemAtPosition(info.position); - - switch (menuItem.getItemId()) { - case MENU_ITEM_PLAY_ALL: - Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); - Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent); - break; - default: - return super.onContextItemSelected(menuItem); - } - return true; - } - - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - - Playlist playlist = (Playlist) parent.getItemAtPosition(position); - - Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); - intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); - Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent); - } - - private class PlaylistAdapter extends ArrayAdapter { - public PlaylistAdapter(List playlists) { - super(SelectPlaylistActivity.this, R.layout.playlist_list_item, playlists); - } - } +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ + +package net.sourceforge.subsonic.androidapp.activity; + +import android.content.Intent; +import android.os.Bundle; +import android.view.ContextMenu; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageButton; +import android.widget.ListView; +import net.sourceforge.subsonic.androidapp.R; +import net.sourceforge.subsonic.androidapp.domain.Playlist; +import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; +import net.sourceforge.subsonic.androidapp.service.MusicService; +import net.sourceforge.subsonic.androidapp.util.BackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Constants; +import net.sourceforge.subsonic.androidapp.util.TabActivityBackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Util; + +import java.util.List; + +public class SelectPlaylistActivity extends SubsonicTabActivity implements AdapterView.OnItemClickListener { + + private static final int MENU_ITEM_PLAY_ALL = 1; + + private ListView list; + private View emptyTextView; + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.select_playlist); + + list = (ListView) findViewById(R.id.select_playlist_list); + emptyTextView = findViewById(R.id.select_playlist_empty); + list.setOnItemClickListener(this); + registerForContextMenu(list); + + // Title: Playlists + setTitle(R.string.playlist_label); + + // Button 1: gone + ImageButton searchButton = (ImageButton)findViewById(R.id.action_button_1); + searchButton.setVisibility(View.GONE); + + // Button 2: refresh + ImageButton refreshButton = (ImageButton) findViewById(R.id.action_button_2); + refreshButton.setImageResource(R.drawable.ic_menu_refresh); + refreshButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + refresh(); + } + }); + + // Button 3: help + ImageButton actionHelpButton = (ImageButton)findViewById(R.id.action_button_3); + actionHelpButton.setImageResource(R.drawable.ic_menu_help); + actionHelpButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SelectPlaylistActivity.this, HelpActivity.class)); + } + }); + + // Button 4: settings + ImageButton actionSettingsButton = (ImageButton)findViewById(R.id.action_button_4); + actionSettingsButton.setImageResource(R.drawable.ic_menu_settings); + actionSettingsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + startActivity(new Intent(SelectPlaylistActivity.this, SettingsActivity.class)); + } + }); + + load(); + } + + private void refresh() { + finish(); + Intent intent = new Intent(this, SelectPlaylistActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_REFRESH, true); + Util.startActivityWithoutTransition(this, intent); + } + + private void load() { + BackgroundTask> task = new TabActivityBackgroundTask>(this) { + @Override + protected List doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(SelectPlaylistActivity.this); + boolean refresh = getIntent().getBooleanExtra(Constants.INTENT_EXTRA_NAME_REFRESH, false); + return musicService.getPlaylists(refresh, SelectPlaylistActivity.this, this); + } + + @Override + protected void done(List result) { + list.setAdapter(new PlaylistAdapter(result)); + emptyTextView.setVisibility(result.isEmpty() ? View.VISIBLE : View.GONE); + } + }; + task.execute(); + } + + @Override + public void onCreateContextMenu(ContextMenu menu, View view, ContextMenu.ContextMenuInfo menuInfo) { + super.onCreateContextMenu(menu, view, menuInfo); + menu.add(Menu.NONE, MENU_ITEM_PLAY_ALL, MENU_ITEM_PLAY_ALL, R.string.common_play_now); + } + + @Override + public boolean onContextItemSelected(MenuItem menuItem) { + AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuItem.getMenuInfo(); + Playlist playlist = (Playlist) list.getItemAtPosition(info.position); + + switch (menuItem.getItemId()) { + case MENU_ITEM_PLAY_ALL: + Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_AUTOPLAY, true); + Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent); + break; + default: + return super.onContextItemSelected(menuItem); + } + return true; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + + Playlist playlist = (Playlist) parent.getItemAtPosition(position); + + Intent intent = new Intent(SelectPlaylistActivity.this, SelectAlbumActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_ID, playlist.getId()); + intent.putExtra(Constants.INTENT_EXTRA_NAME_PLAYLIST_NAME, playlist.getName()); + Util.startActivityWithoutTransition(SelectPlaylistActivity.this, intent); + } + + private class PlaylistAdapter extends ArrayAdapter { + public PlaylistAdapter(List playlists) { + super(SelectPlaylistActivity.this, R.layout.playlist_list_item, playlists); + } + } } \ No newline at end of file diff --git a/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java b/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java index 2a5e266a..88420b6d 100644 --- a/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java +++ b/src/net/sourceforge/subsonic/androidapp/activity/SubsonicTabActivity.java @@ -1,387 +1,389 @@ -/* - 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 . - - Copyright 2009 (C) Sindre Mehus - */ -package net.sourceforge.subsonic.androidapp.activity; - -import java.io.File; -import java.io.PrintWriter; -import java.util.LinkedList; -import java.util.List; - -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageInfo; -import android.graphics.Typeface; -import android.media.AudioManager; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.util.Log; -import android.view.KeyEvent; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.widget.TextView; -import net.sourceforge.subsonic.androidapp.R; -import net.sourceforge.subsonic.androidapp.domain.MusicDirectory; -import net.sourceforge.subsonic.androidapp.service.DownloadService; -import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl; -import net.sourceforge.subsonic.androidapp.service.MusicService; -import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; -import net.sourceforge.subsonic.androidapp.util.Constants; -import net.sourceforge.subsonic.androidapp.util.ImageLoader; -import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask; -import net.sourceforge.subsonic.androidapp.util.Util; - -/** - * @author Sindre Mehus - */ -public class SubsonicTabActivity extends Activity { - - private static final String TAG = SubsonicTabActivity.class.getSimpleName(); - private static ImageLoader IMAGE_LOADER; - - private boolean destroyed; - private View homeButton; - private View musicButton; - private View searchButton; - private View playlistButton; - private View nowPlayingButton; - - @Override - protected void onCreate(Bundle bundle) { - setUncaughtExceptionHandler(); - applyTheme(); - super.onCreate(bundle); - requestWindowFeature(Window.FEATURE_NO_TITLE); - startService(new Intent(this, DownloadServiceImpl.class)); - setVolumeControlStream(AudioManager.STREAM_MUSIC); - } - - @Override - protected void onPostCreate(Bundle bundle) { - super.onPostCreate(bundle); - - homeButton = findViewById(R.id.button_bar_home); - homeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(SubsonicTabActivity.this, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); - } - }); - - musicButton = findViewById(R.id.button_bar_music); - musicButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(SubsonicTabActivity.this, SelectArtistActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); - } - }); - - searchButton = findViewById(R.id.button_bar_search); - searchButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(SubsonicTabActivity.this, SearchActivity.class); - intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true); - Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); - } - }); - - playlistButton = findViewById(R.id.button_bar_playlists); - playlistButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Intent intent = new Intent(SubsonicTabActivity.this, SelectPlaylistActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); - } - }); - - nowPlayingButton = findViewById(R.id.button_bar_now_playing); - nowPlayingButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class); - } - }); - - if (this instanceof MainActivity) { - homeButton.setEnabled(false); - } else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) { - musicButton.setEnabled(false); - } else if (this instanceof SearchActivity) { - searchButton.setEnabled(false); - } else if (this instanceof SelectPlaylistActivity) { - playlistButton.setEnabled(false); - } else if (this instanceof DownloadActivity || this instanceof LyricsActivity) { - nowPlayingButton.setEnabled(false); - } - - updateButtonVisibility(); - } - - @Override - protected void onResume() { - super.onResume(); - Util.registerMediaButtonEventReceiver(this); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - - case R.id.menu_exit: - Intent intent = new Intent(this, MainActivity.class); - intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true); - Util.startActivityWithoutTransition(this, intent); - return true; - - case R.id.menu_settings: - startActivity(new Intent(this, SettingsActivity.class)); - return true; - - case R.id.menu_help: - startActivity(new Intent(this, HelpActivity.class)); - return true; - } - - return false; - } - - @Override - protected void onDestroy() { - super.onDestroy(); - destroyed = true; - getImageLoader().clear(); - } - - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN; - boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP; - boolean isVolumeAdjust = isVolumeDown || isVolumeUp; - boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled(); - - if (isVolumeAdjust && isJukebox) { - getDownloadService().adjustJukeboxVolume(isVolumeUp); - return true; - } - return super.onKeyDown(keyCode, event); - } - - @Override - public void finish() { - super.finish(); - Util.disablePendingTransition(this); - } - - @Override - public void setTitle(CharSequence title) { - super.setTitle(title); - - // Set the font of title in the action bar. - TextView text = (TextView) findViewById(R.id.actionbar_title_text); - Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf"); - text.setTypeface(typeface); - - text.setText(title); - } - - @Override - public void setTitle(int titleId) { - setTitle(getString(titleId)); - } - - private void applyTheme() { - String theme = Util.getTheme(this); - if ("dark".equals(theme)) { - setTheme(R.style.Dark); - } else if ("light".equals(theme)) { - setTheme(R.style.Light); - } else if ("fullscreen".equals(theme)) { - setTheme(R.style.Fullscreen); - } else if ("fullscreenlight".equals(theme)) { - setTheme(R.style.Fullscreenlight); - } - } - - public boolean isDestroyed() { - return destroyed; - } - - private void updateButtonVisibility() { - int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE; - searchButton.setVisibility(visibility); - playlistButton.setVisibility(visibility); - } - - public void setProgressVisible(boolean visible) { - View view = findViewById(R.id.tab_progress); - if (view != null) { - view.setVisibility(visible ? View.VISIBLE : View.GONE); - } - } - - public void updateProgress(String message) { - TextView view = (TextView) findViewById(R.id.tab_progress_message); - if (view != null) { - view.setText(message); - } - } - - public DownloadService getDownloadService() { - // If service is not available, request it to start and wait for it. - for (int i = 0; i < 5; i++) { - DownloadService downloadService = DownloadServiceImpl.getInstance(); - if (downloadService != null) { - return downloadService; - } - Log.w(TAG, "DownloadService not running. Attempting to start it."); - startService(new Intent(this, DownloadServiceImpl.class)); - Util.sleepQuietly(50L); - } - return DownloadServiceImpl.getInstance(); - } - - protected void warnIfNetworkOrStorageUnavailable() { - if (!Util.isExternalStoragePresent()) { - Util.toast(this, R.string.select_album_no_sdcard); - } else if (!Util.isOffline(this) && !Util.isNetworkConnected(this)) { - Util.toast(this, R.string.select_album_no_network); - } - } - - protected synchronized ImageLoader getImageLoader() { - if (IMAGE_LOADER == null) { - IMAGE_LOADER = new ImageLoader(this); - } - return IMAGE_LOADER; - } - - protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay) { - ModalBackgroundTask> task = new ModalBackgroundTask>(this, false) { - - private static final int MAX_SONGS = 500; - - @Override - protected List doInBackground() throws Throwable { - MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this); - MusicDirectory root = musicService.getMusicDirectory(id, false, SubsonicTabActivity.this, this); - List songs = new LinkedList(); - getSongsRecursively(root, songs); - return songs; - } - - private void getSongsRecursively(MusicDirectory parent, List songs) throws Exception { - if (songs.size() > MAX_SONGS) { - return; - } - - for (MusicDirectory.Entry song : parent.getChildren(false, true)) { - if (!song.isVideo()) { - songs.add(song); - } - } - for (MusicDirectory.Entry dir : parent.getChildren(true, false)) { - MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this); - getSongsRecursively(musicService.getMusicDirectory(dir.getId(), false, SubsonicTabActivity.this, this), songs); - } - } - - @Override - protected void done(List songs) { - DownloadService downloadService = getDownloadService(); - if (!songs.isEmpty() && downloadService != null) { - if (!append) { - downloadService.clear(); - } - warnIfNetworkOrStorageUnavailable(); - downloadService.download(songs, save, autoplay, false); - Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class); - } - } - }; - - task.execute(); - } - - private void setUncaughtExceptionHandler() { - Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler(); - if (!(handler instanceof SubsonicUncaughtExceptionHandler)) { - Thread.setDefaultUncaughtExceptionHandler(new SubsonicUncaughtExceptionHandler(this)); - } - } - - /** - * Logs the stack trace of uncaught exceptions to a file on the SD card. - */ - private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { - - private final Thread.UncaughtExceptionHandler defaultHandler; - private final Context context; - - private SubsonicUncaughtExceptionHandler(Context context) { - this.context = context; - defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); - } - - @Override - public void uncaughtException(Thread thread, Throwable throwable) { - File file = null; - PrintWriter printWriter = null; - try { - - PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.sourceforge.subsonic.androidapp", 0); - file = new File(Environment.getExternalStorageDirectory(), "subsonic-stacktrace.txt"); - printWriter = new PrintWriter(file); - printWriter.println("Android API level: " + Build.VERSION.SDK); - printWriter.println("Subsonic version name: " + packageInfo.versionName); - printWriter.println("Subsonic version code: " + packageInfo.versionCode); - printWriter.println(); - throwable.printStackTrace(printWriter); - Log.i(TAG, "Stack trace written to " + file); - } catch (Throwable x) { - Log.e(TAG, "Failed to write stack trace to " + file, x); - } finally { - Util.close(printWriter); - if (defaultHandler != null) { - defaultHandler.uncaughtException(thread, throwable); - } - - } - } - } -} - +/* + 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 . + + Copyright 2009 (C) Sindre Mehus + */ +package net.sourceforge.subsonic.androidapp.activity; + +import java.io.File; +import java.io.PrintWriter; +import java.util.LinkedList; +import java.util.List; + +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageInfo; +import android.graphics.Typeface; +import android.media.AudioManager; +import android.os.Build; +import android.os.Bundle; +import android.os.Environment; +import android.util.Log; +import android.view.KeyEvent; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.Window; +import android.widget.TextView; +import net.sourceforge.subsonic.androidapp.R; +import net.sourceforge.subsonic.androidapp.domain.MusicDirectory; +import net.sourceforge.subsonic.androidapp.service.DownloadService; +import net.sourceforge.subsonic.androidapp.service.DownloadServiceImpl; +import net.sourceforge.subsonic.androidapp.service.MusicService; +import net.sourceforge.subsonic.androidapp.service.MusicServiceFactory; +import net.sourceforge.subsonic.androidapp.util.Constants; +import net.sourceforge.subsonic.androidapp.util.ImageLoader; +import net.sourceforge.subsonic.androidapp.util.ModalBackgroundTask; +import net.sourceforge.subsonic.androidapp.util.Util; + +/** + * @author Sindre Mehus + */ +public class SubsonicTabActivity extends Activity { + + private static final String TAG = SubsonicTabActivity.class.getSimpleName(); + private static ImageLoader IMAGE_LOADER; + + private boolean destroyed; + private View homeButton; + private View musicButton; + private View searchButton; + private View playlistButton; + private View nowPlayingButton; + + @Override + protected void onCreate(Bundle bundle) { + setUncaughtExceptionHandler(); + applyTheme(); + super.onCreate(bundle); + requestWindowFeature(Window.FEATURE_NO_TITLE); + startService(new Intent(this, DownloadServiceImpl.class)); + setVolumeControlStream(AudioManager.STREAM_MUSIC); + } + + @Override + protected void onPostCreate(Bundle bundle) { + super.onPostCreate(bundle); + + homeButton = findViewById(R.id.button_bar_home); + homeButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(SubsonicTabActivity.this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); + } + }); + + musicButton = findViewById(R.id.button_bar_music); + musicButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(SubsonicTabActivity.this, SelectArtistActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); + } + }); + + searchButton = findViewById(R.id.button_bar_search); + searchButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(SubsonicTabActivity.this, SearchActivity.class); + intent.putExtra(Constants.INTENT_EXTRA_REQUEST_SEARCH, true); + Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); + } + }); + + playlistButton = findViewById(R.id.button_bar_playlists); + playlistButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Intent intent = new Intent(SubsonicTabActivity.this, SelectPlaylistActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + Util.startActivityWithoutTransition(SubsonicTabActivity.this, intent); + } + }); + + nowPlayingButton = findViewById(R.id.button_bar_now_playing); + nowPlayingButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class); + } + }); + + if (this instanceof MainActivity) { + homeButton.setEnabled(false); + } else if (this instanceof SelectAlbumActivity || this instanceof SelectArtistActivity) { + musicButton.setEnabled(false); + } else if (this instanceof SearchActivity) { + searchButton.setEnabled(false); + } else if (this instanceof SelectPlaylistActivity) { + playlistButton.setEnabled(false); + } else if (this instanceof DownloadActivity || this instanceof LyricsActivity) { + nowPlayingButton.setEnabled(false); + } + + updateButtonVisibility(); + } + + @Override + protected void onResume() { + super.onResume(); + Util.registerMediaButtonEventReceiver(this); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + if (android.os.Build.VERSION.SDK_INT < 11) { + MenuInflater inflater = getMenuInflater(); + inflater.inflate(R.menu.main, menu); + } + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.menu_exit: + Intent intent = new Intent(this, MainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + intent.putExtra(Constants.INTENT_EXTRA_NAME_EXIT, true); + Util.startActivityWithoutTransition(this, intent); + return true; + + case R.id.menu_settings: + startActivity(new Intent(this, SettingsActivity.class)); + return true; + + case R.id.menu_help: + startActivity(new Intent(this, HelpActivity.class)); + return true; + } + + return false; + } + + @Override + protected void onDestroy() { + super.onDestroy(); + destroyed = true; + getImageLoader().clear(); + } + + + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + boolean isVolumeDown = keyCode == KeyEvent.KEYCODE_VOLUME_DOWN; + boolean isVolumeUp = keyCode == KeyEvent.KEYCODE_VOLUME_UP; + boolean isVolumeAdjust = isVolumeDown || isVolumeUp; + boolean isJukebox = getDownloadService() != null && getDownloadService().isJukeboxEnabled(); + + if (isVolumeAdjust && isJukebox) { + getDownloadService().adjustJukeboxVolume(isVolumeUp); + return true; + } + return super.onKeyDown(keyCode, event); + } + + @Override + public void finish() { + super.finish(); + Util.disablePendingTransition(this); + } + + @Override + public void setTitle(CharSequence title) { + super.setTitle(title); + + // Set the font of title in the action bar. + TextView text = (TextView) findViewById(R.id.actionbar_title_text); + Typeface typeface = Typeface.createFromAsset(getAssets(), "fonts/Roboto-Regular.ttf"); + text.setTypeface(typeface); + + text.setText(title); + } + + @Override + public void setTitle(int titleId) { + setTitle(getString(titleId)); + } + + private void applyTheme() { + String theme = Util.getTheme(this); + if ("dark".equals(theme)) { + setTheme(R.style.Dark); + } else if ("light".equals(theme)) { + setTheme(R.style.Light); + } else if ("fullscreen".equals(theme)) { + setTheme(R.style.Fullscreen); + } else if ("fullscreenlight".equals(theme)) { + setTheme(R.style.Fullscreenlight); + } + } + + public boolean isDestroyed() { + return destroyed; + } + + private void updateButtonVisibility() { + int visibility = Util.isOffline(this) ? View.GONE : View.VISIBLE; + searchButton.setVisibility(visibility); + playlistButton.setVisibility(visibility); + } + + public void setProgressVisible(boolean visible) { + View view = findViewById(R.id.tab_progress); + if (view != null) { + view.setVisibility(visible ? View.VISIBLE : View.GONE); + } + } + + public void updateProgress(String message) { + TextView view = (TextView) findViewById(R.id.tab_progress_message); + if (view != null) { + view.setText(message); + } + } + + public DownloadService getDownloadService() { + // If service is not available, request it to start and wait for it. + for (int i = 0; i < 5; i++) { + DownloadService downloadService = DownloadServiceImpl.getInstance(); + if (downloadService != null) { + return downloadService; + } + Log.w(TAG, "DownloadService not running. Attempting to start it."); + startService(new Intent(this, DownloadServiceImpl.class)); + Util.sleepQuietly(50L); + } + return DownloadServiceImpl.getInstance(); + } + + protected void warnIfNetworkOrStorageUnavailable() { + if (!Util.isExternalStoragePresent()) { + Util.toast(this, R.string.select_album_no_sdcard); + } else if (!Util.isOffline(this) && !Util.isNetworkConnected(this)) { + Util.toast(this, R.string.select_album_no_network); + } + } + + protected synchronized ImageLoader getImageLoader() { + if (IMAGE_LOADER == null) { + IMAGE_LOADER = new ImageLoader(this); + } + return IMAGE_LOADER; + } + + protected void downloadRecursively(final String id, final boolean save, final boolean append, final boolean autoplay) { + ModalBackgroundTask> task = new ModalBackgroundTask>(this, false) { + + private static final int MAX_SONGS = 500; + + @Override + protected List doInBackground() throws Throwable { + MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this); + MusicDirectory root = musicService.getMusicDirectory(id, false, SubsonicTabActivity.this, this); + List songs = new LinkedList(); + getSongsRecursively(root, songs); + return songs; + } + + private void getSongsRecursively(MusicDirectory parent, List songs) throws Exception { + if (songs.size() > MAX_SONGS) { + return; + } + + for (MusicDirectory.Entry song : parent.getChildren(false, true)) { + if (!song.isVideo()) { + songs.add(song); + } + } + for (MusicDirectory.Entry dir : parent.getChildren(true, false)) { + MusicService musicService = MusicServiceFactory.getMusicService(SubsonicTabActivity.this); + getSongsRecursively(musicService.getMusicDirectory(dir.getId(), false, SubsonicTabActivity.this, this), songs); + } + } + + @Override + protected void done(List songs) { + DownloadService downloadService = getDownloadService(); + if (!songs.isEmpty() && downloadService != null) { + if (!append) { + downloadService.clear(); + } + warnIfNetworkOrStorageUnavailable(); + downloadService.download(songs, save, autoplay, false); + Util.startActivityWithoutTransition(SubsonicTabActivity.this, DownloadActivity.class); + } + } + }; + + task.execute(); + } + + private void setUncaughtExceptionHandler() { + Thread.UncaughtExceptionHandler handler = Thread.getDefaultUncaughtExceptionHandler(); + if (!(handler instanceof SubsonicUncaughtExceptionHandler)) { + Thread.setDefaultUncaughtExceptionHandler(new SubsonicUncaughtExceptionHandler(this)); + } + } + + /** + * Logs the stack trace of uncaught exceptions to a file on the SD card. + */ + private static class SubsonicUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler { + + private final Thread.UncaughtExceptionHandler defaultHandler; + private final Context context; + + private SubsonicUncaughtExceptionHandler(Context context) { + this.context = context; + defaultHandler = Thread.getDefaultUncaughtExceptionHandler(); + } + + @Override + public void uncaughtException(Thread thread, Throwable throwable) { + File file = null; + PrintWriter printWriter = null; + try { + + PackageInfo packageInfo = context.getPackageManager().getPackageInfo("net.sourceforge.subsonic.androidapp", 0); + file = new File(Environment.getExternalStorageDirectory(), "subsonic-stacktrace.txt"); + printWriter = new PrintWriter(file); + printWriter.println("Android API level: " + Build.VERSION.SDK); + printWriter.println("Subsonic version name: " + packageInfo.versionName); + printWriter.println("Subsonic version code: " + packageInfo.versionCode); + printWriter.println(); + throwable.printStackTrace(printWriter); + Log.i(TAG, "Stack trace written to " + file); + } catch (Throwable x) { + Log.e(TAG, "Failed to write stack trace to " + file, x); + } finally { + Util.close(printWriter); + if (defaultHandler != null) { + defaultHandler.uncaughtException(thread, throwable); + } + + } + } + } +} +